feat(documents): add GET /documents endpoint and improve models
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
This commit is contained in:
@@ -11,33 +11,36 @@ from src.core.models import StrategyName
|
|||||||
|
|
||||||
class DocumentResponse(BaseModel):
|
class DocumentResponse(BaseModel):
|
||||||
"""Returned after upload or GET."""
|
"""Returned after upload or GET."""
|
||||||
|
|
||||||
id: str
|
id: str
|
||||||
filename: str
|
filename: str
|
||||||
paragraph_count: int
|
paragraph_count: int = 0
|
||||||
chunk_counts: dict[str, int] = Field(default_factory=dict)
|
chunk_counts: dict[str, int] = Field(default_factory=dict)
|
||||||
created_at: str
|
created_at: str
|
||||||
|
|
||||||
|
|
||||||
class DocumentDetailResponse(DocumentResponse):
|
class DocumentDetailResponse(DocumentResponse):
|
||||||
"""Full document detail including tree and text preview."""
|
"""Full document detail including tree and text preview."""
|
||||||
|
|
||||||
parsed_text_preview: str # first 500 chars
|
parsed_text_preview: str # first 500 chars
|
||||||
document_tree: dict # JSON-serialised DocumentTree
|
document_tree: dict # JSON-serialised DocumentTree
|
||||||
|
|
||||||
|
|
||||||
class ProcessRequest(BaseModel):
|
class ProcessRequest(BaseModel):
|
||||||
"""Body for POST /documents/{id}/process."""
|
"""Body for POST /documents/{id}/process."""
|
||||||
|
|
||||||
strategies: list[StrategyName] = Field(
|
strategies: list[StrategyName] = Field(
|
||||||
description="Which chunking strategies to run",
|
default=[
|
||||||
|
StrategyName.RECURSIVE,
|
||||||
|
StrategyName.FIXED_SIZE,
|
||||||
|
StrategyName.SEMANTIC,
|
||||||
|
StrategyName.CONTEXTUAL_RETRIEVAL,
|
||||||
|
StrategyName.SEMANTIC_PARENT_CHILD,
|
||||||
|
],
|
||||||
|
description="Which chunking strategies to run (defaults to all 5)",
|
||||||
min_length=1,
|
min_length=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class StrategyResult(BaseModel):
|
class StrategyResult(BaseModel):
|
||||||
"""Outcome for a single strategy in a processing run."""
|
"""Outcome for a single strategy in a processing run."""
|
||||||
|
|
||||||
strategy: StrategyName
|
strategy: StrategyName
|
||||||
status: str # "completed" | "failed"
|
status: str # "completed" | "failed"
|
||||||
chunks_produced: int = 0
|
chunks_produced: int = 0
|
||||||
@@ -46,7 +49,6 @@ class StrategyResult(BaseModel):
|
|||||||
|
|
||||||
class ProcessResponse(BaseModel):
|
class ProcessResponse(BaseModel):
|
||||||
"""Returned after processing a document with selected strategies."""
|
"""Returned after processing a document with selected strategies."""
|
||||||
|
|
||||||
document_id: str
|
document_id: str
|
||||||
strategies_completed: list[StrategyResult]
|
strategies_completed: list[StrategyResult]
|
||||||
strategies_failed: list[StrategyResult]
|
strategies_failed: list[StrategyResult]
|
||||||
@@ -54,11 +56,18 @@ class ProcessResponse(BaseModel):
|
|||||||
|
|
||||||
class DeleteResponse(BaseModel):
|
class DeleteResponse(BaseModel):
|
||||||
"""Returned after deleting a document."""
|
"""Returned after deleting a document."""
|
||||||
|
|
||||||
deleted: bool
|
deleted: bool
|
||||||
document_id: str
|
document_id: str
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentListResponse(BaseModel):
|
||||||
|
"""Returned when listing documents."""
|
||||||
|
items: list[DocumentResponse]
|
||||||
|
total: int
|
||||||
|
offset: int
|
||||||
|
limit: int
|
||||||
|
|
||||||
|
|
||||||
# ── Strategies list ────────────────────────────────────────────────
|
# ── Strategies list ────────────────────────────────────────────────
|
||||||
|
|
||||||
class StrategyInfo(BaseModel):
|
class StrategyInfo(BaseModel):
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from src.core.models import PaginatedResponse, StrategyName
|
|||||||
from src.documents.models import (
|
from src.documents.models import (
|
||||||
DeleteResponse,
|
DeleteResponse,
|
||||||
DocumentResponse,
|
DocumentResponse,
|
||||||
|
DocumentListResponse,
|
||||||
ProcessRequest,
|
ProcessRequest,
|
||||||
ProcessResponse,
|
ProcessResponse,
|
||||||
StrategiesResponse,
|
StrategiesResponse,
|
||||||
@@ -24,6 +25,18 @@ from src.documents import service
|
|||||||
router = APIRouter()
|
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)
|
@router.post("/documents", response_model=DocumentResponse, status_code=201)
|
||||||
async def upload_document(file: UploadFile = File(...)):
|
async def upload_document(file: UploadFile = File(...)):
|
||||||
"""Upload a .docx file. Parses it, stores the document tree in SQLite."""
|
"""Upload a .docx file. Parses it, stores the document tree in SQLite."""
|
||||||
|
|||||||
@@ -141,6 +141,13 @@ def delete_document(doc_id: str) -> bool:
|
|||||||
return db.delete_document(doc_id)
|
return db.delete_document(doc_id)
|
||||||
|
|
||||||
|
|
||||||
|
# ── List documents ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def list_documents(*, offset: int = 0, limit: int = 50) -> dict[str, Any]:
|
||||||
|
"""List documents with pagination."""
|
||||||
|
return db.list_documents(offset=offset, limit=limit)
|
||||||
|
|
||||||
|
|
||||||
# ── List strategies ────────────────────────────────────────────────
|
# ── List strategies ────────────────────────────────────────────────
|
||||||
|
|
||||||
def list_strategies() -> list[dict[str, str]]:
|
def list_strategies() -> list[dict[str, str]]:
|
||||||
|
|||||||
Reference in New Issue
Block a user