from fastapi import APIRouter, UploadFile, File, HTTPException, Request from fastapi.responses import FileResponse from pathlib import Path import uuid import os import aiofiles from app.core.config import settings from app.core.limiter import limiter from app.ingestion.pipeline import IngestionPipeline router = APIRouter(prefix="/api/documents", tags=["Documents"]) pipeline = IngestionPipeline() MAX_FILE_SIZE = 50 * 1024 * 1024 @router.post("/upload") async def upload_document(file: UploadFile = File(...)): if not file.filename: raise HTTPException(400, "No filename provided") ext = Path(file.filename).suffix.lower() if ext not in (".pdf", ".txt", ".md"): raise HTTPException(400, f"Unsupported file type: {ext}") upload_dir = Path(settings.upload_dir) upload_dir.mkdir(exist_ok=True) file_id = str(uuid.uuid4()) save_path = upload_dir / f"{file_id}{ext}" size = 0 async with aiofiles.open(save_path, "wb") as f: while True: chunk = await file.read(8 * 1024 * 1024) if not chunk: break size += len(chunk) if size > MAX_FILE_SIZE: raise HTTPException(400, "File too large (max 50MB)") await f.write(chunk) result = await pipeline.process_file(save_path, file_id) return { "document_id": result["document_id"], "filename": file.filename, "chunks": result["chunks"], "pages": result["pages"], "status": "processed", } @router.get("/") @limiter.limit("30/minute") async def list_documents(request: Request): from app.vectorstore.factory import get_vector_store store = get_vector_store(settings.vector_store) collections = store.list_collections() return {"documents": collections} @router.get("/{document_id}/download") @limiter.limit("30/minute") async def download_document(request: Request, document_id: str): upload_dir = Path(settings.upload_dir) for ext in (".pdf", ".txt", ".md"): path = upload_dir / f"{document_id}{ext}" if path.exists(): return FileResponse( path, filename=f"{document_id}{ext}", media_type="application/octet-stream", headers={"Content-Disposition": f"attachment; filename=\"{document_id}{ext}\""}, ) raise HTTPException(404, "Document not found") @router.delete("/{document_id}") @limiter.limit("10/minute") async def delete_document(request: Request, document_id: str): from app.vectorstore.factory import get_vector_store store = get_vector_store(settings.vector_store) store.delete_collection(document_id) return {"status": "deleted", "document_id": document_id}