Spaces:
Sleeping
Sleeping
| """On-demand actions and export endpoints. | |
| These let the frontend trigger individual functions (re-extract with a chosen | |
| schema, re-summarize) and download results — independent of the chat agent. | |
| """ | |
| from __future__ import annotations | |
| from fastapi import APIRouter, HTTPException, Query | |
| from fastapi.responses import Response | |
| from app.core.logging import get_logger | |
| from app.schemas.documents import Classification, ExtractionResult | |
| from app.schemas.templates import all_template_names | |
| from app.services import ( | |
| anomaly, | |
| classification, | |
| export, | |
| extraction, | |
| storage, | |
| summary, | |
| vectorstore, | |
| ) | |
| log = get_logger(__name__) | |
| router = APIRouter(prefix="/api/documents", tags=["actions"]) | |
| async def re_extract(doc_id: str, schema: str | None = Query(None), | |
| provider: str | None = Query(None)): | |
| detail = storage.get(doc_id) | |
| if not detail: | |
| raise HTTPException(404, "Document not found") | |
| chunks = await vectorstore.query(doc_id, "key fields", k=40) | |
| doc_type = detail.classification.doc_type if detail.classification else None | |
| # `schema` is an OPTIONAL user-chosen framing; "auto" (or unset) keeps the | |
| # extractor fully adaptive. | |
| hint = schema if (schema and schema.lower() != "auto") else None | |
| result = await extraction.extract(detail.markdown or "", doc_type, chunks, provider, | |
| schema_hint=hint) | |
| detail.extraction = result | |
| detail.anomalies = await anomaly.detect(detail.markdown or "", result, doc_type, provider) | |
| storage.save(detail) | |
| return result | |
| async def re_classify(doc_id: str, provider: str | None = Query(None)): | |
| detail = storage.get(doc_id) | |
| if not detail: | |
| raise HTTPException(404, "Document not found") | |
| c = await classification.classify(detail.markdown or "", provider) | |
| detail.classification = c | |
| storage.save(detail) | |
| return c | |
| async def re_summarize(doc_id: str, provider: str | None = Query(None)): | |
| detail = storage.get(doc_id) | |
| if not detail: | |
| raise HTTPException(404, "Document not found") | |
| s = await summary.summarize(detail.markdown or "", provider) | |
| detail.summary = s | |
| storage.save(detail) | |
| return {"summary": s} | |
| async def export_document(doc_id: str, format: str = Query("json")): | |
| detail = storage.get(doc_id) | |
| if not detail: | |
| raise HTTPException(404, "Document not found") | |
| fmt = format.lower() | |
| if fmt not in export.EXPORTERS: | |
| raise HTTPException(400, f"Unsupported format. Use one of {list(export.EXPORTERS)}") | |
| fn, media, ext = export.EXPORTERS[fmt] | |
| data = fn(detail) | |
| safe = (detail.filename or doc_id).rsplit(".", 1)[0] | |
| return Response( | |
| content=data, media_type=media, | |
| headers={"Content-Disposition": f'attachment; filename="{safe}.{ext}"'}, | |
| ) | |
| async def list_schemas(): | |
| return {"schemas": all_template_names()} | |