API e interfaz de carga
El endpoint de carga está en RAG.Api/Program.cs:
El endpoint de carga encola trabajo en vez de hacerlo
app.MapPost("/api/documents", async (HttpRequest request, RagDbContext dbContext, IObjectStorage storage, IOptions<RagOptions> options, CancellationToken cancellationToken) =>
{
var documentId = Guid.NewGuid();
var objectKey = $"{documentId:N}/{fileName}";
await storage.UploadAsync(objectKey, stream, contentType, cancellationToken);
return Results.Accepted($"/api/documents/{documentId}");
});El endpoint de carga está en RAG.Api/Program.cs:
POST /api/documents
El endpoint:
- verifica que la solicitud sea multipart form data;
- requiere un archivo PDF o TXT;
- aplica el límite de carga configurado;
- escribe el archivo original en almacenamiento de objetos;
- crea un
DocumentRecordcon estadoPending; - devuelve
202 Accepted.
La API evita deliberadamente hacer extracción y embeddings dentro de la solicitud. Encola trabajo creando una fila pendiente en la base de datos.
Nota de producción: el límite de carga protege el cuerpo de la solicitud, pero este ejemplo todavía confía lo suficiente en el archivo cargado como para guardarlo y procesarlo después. Un sistema de producción normalmente agregaría validación de contenido más fuerte, escaneo de malware, cuotas por usuario más estrictas y respuestas de error genéricas en vez de devolver detalles internos de excepciones. Este proyecto mantiene el comportamiento simple porque es un proyecto de aprendizaje, no software de producción.
La UI en RAG.Api/wwwroot es intencionalmente sencilla:
index.html: estructura para carga y chat.styles.css: layout y estilos de progreso.app.js: llama a la API, consulta estado de documentos y renderiza respuestas y citas.
La UI consulta GET /api/documents cada pocos segundos. Para libros grandes, la ingesta puede tardar, así que el worker actualiza:
progressStageprogressPercentprocessedChunkstotalChunks
Nota de producción: polling es simple y funciona bien para este ejemplo local, pero una UI de producción normalmente se suscribiría a actualizaciones de estado. Por ejemplo, la API podría publicar eventos de progreso del documento mediante SignalR, WebSockets, Server-Sent Events o un servicio de notificaciones respaldado por un message broker, y el navegador podría recibir actualizaciones cuando ocurren en lugar de pedir repetidamente la lista completa de documentos.
Esto permite que la UI muestre progreso útil en lugar de dejar un libro atrapado en un estado vago de Processing.
Controles de borrar y reindexar
La API ahora expone controles del ciclo de vida del documento además de carga y consulta de estado:
DELETE /api/documents/{id}
POST /api/documents/{id}/reindex
DocumentManagementService controla esas operaciones. La eliminación borra la fila de metadatos, elimina el objeto original y remueve los puntos vectoriales del documento. La reindexación restablece estado y progreso a Pending para que el worker pueda reconstruir chunks y vectores desde el archivo original.
Esto importa porque los sistemas RAG necesitan workflows de mantenimiento. Cuando cambian el chunking, la extracción, los prompts, los embeddings o los artefactos generados, los usuarios necesitan una forma de reconstruir el índice derivado sin subir otra vez el mismo documento.