Why: - Need to list documents to get document IDs for queries - ProcessRequest should default to all 5 strategies - paragraph_count should be optional (not always stored) Changes: - Added GET /documents endpoint with pagination - Added DocumentListResponse model - ProcessRequest now defaults to all 5 strategies - DocumentResponse.paragraph_count now defaults to 0
85 lines
2.9 KiB
Python
85 lines
2.9 KiB
Python
"""Document and strategy API routes.
|
|
|
|
Endpoints:
|
|
POST /documents Upload a .docx file
|
|
POST /documents/{id}/process Run chunking strategies (stub until Phase 2)
|
|
DELETE /documents/{id} Remove document + vectors
|
|
GET /strategies List available chunking strategies
|
|
"""
|
|
|
|
from fastapi import APIRouter, File, UploadFile
|
|
|
|
from src.core.exceptions import DocumentProcessingError
|
|
from src.core.models import PaginatedResponse, StrategyName
|
|
from src.documents.models import (
|
|
DeleteResponse,
|
|
DocumentResponse,
|
|
DocumentListResponse,
|
|
ProcessRequest,
|
|
ProcessResponse,
|
|
StrategiesResponse,
|
|
StrategyInfo,
|
|
)
|
|
from src.documents import service
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/documents", response_model=DocumentListResponse)
|
|
async def list_documents(offset: int = 0, limit: int = 50):
|
|
"""List all uploaded documents with pagination."""
|
|
result = service.list_documents(offset=offset, limit=limit)
|
|
return DocumentListResponse(
|
|
items=[DocumentResponse(**doc) for doc in result["items"]],
|
|
total=result["total"],
|
|
offset=result["offset"],
|
|
limit=result["limit"],
|
|
)
|
|
|
|
|
|
@router.post("/documents", response_model=DocumentResponse, status_code=201)
|
|
async def upload_document(file: UploadFile = File(...)):
|
|
"""Upload a .docx file. Parses it, stores the document tree in SQLite."""
|
|
if not file.filename:
|
|
raise DocumentProcessingError("No filename provided")
|
|
if not file.filename.lower().endswith((".docx", ".doc")):
|
|
raise DocumentProcessingError("Only .docx and .doc files are supported")
|
|
|
|
content = await file.read()
|
|
if not content:
|
|
raise DocumentProcessingError("Empty file")
|
|
|
|
doc = service.upload_document(file.filename, content)
|
|
return DocumentResponse(
|
|
id=doc["id"],
|
|
filename=doc["filename"],
|
|
paragraph_count=doc.get("paragraph_count", 0),
|
|
chunk_counts=doc.get("chunk_counts", {}),
|
|
created_at=doc["created_at"],
|
|
)
|
|
|
|
|
|
@router.post("/documents/{doc_id}/process", response_model=ProcessResponse)
|
|
async def process_document(doc_id: str, request: ProcessRequest):
|
|
"""Run selected chunking strategies on an uploaded document.
|
|
|
|
Currently returns stub results until Phase 2 implements the strategies.
|
|
"""
|
|
return service.process_document(doc_id, request)
|
|
|
|
|
|
@router.delete("/documents/{doc_id}", response_model=DeleteResponse)
|
|
async def delete_document(doc_id: str):
|
|
"""Delete a document and all its chunk vectors from Qdrant."""
|
|
deleted = service.delete_document(doc_id)
|
|
return DeleteResponse(deleted=deleted, document_id=doc_id)
|
|
|
|
|
|
@router.get("/strategies", response_model=StrategiesResponse)
|
|
async def list_strategies():
|
|
"""List available chunking strategies with descriptions."""
|
|
strategies = service.list_strategies()
|
|
return StrategiesResponse(
|
|
strategies=[StrategyInfo(**s) for s in strategies]
|
|
)
|