Download app/api/export.py from nvikou/Sheetly: direct link, hf CLI and curl.
- Browser
- Download file 3.4 kB
-
https://huggingface.co/spaces/nvikou/Sheetly/resolve/main/app/api/export.py
- Command line
-
hf download hf://spaces/nvikou/Sheetly/app/api/export.py
-
curl -L -o export.py https://huggingface.co/spaces/nvikou/Sheetly/resolve/main/app/api/export.py
3.4 kB
| """Export and dashboard API.""" | |
| from __future__ import annotations | |
| from collections import Counter | |
| from fastapi import APIRouter, Depends, HTTPException, Query | |
| from fastapi.responses import FileResponse | |
| from sqlalchemy import func, select | |
| from sqlalchemy.ext.asyncio import AsyncSession | |
| from app.config import get_settings | |
| from app.db import get_session | |
| from app.models import Batch, Document | |
| from app.schemas import DashboardStats, DocStatus, PublicSettings | |
| from app.services.export import build_export | |
| router = APIRouter(prefix="/api", tags=["export"]) | |
| _XLSX_MEDIA = ( | |
| "application/vnd.openxmlformats-officedocument" | |
| ".spreadsheetml.sheet" | |
| ) | |
| async def export_documents( | |
| fmt: str = Query("xlsx", pattern="^(xlsx|excel|json|csv)$"), | |
| batch_id: str | None = None, | |
| session: AsyncSession = Depends(get_session), | |
| ) -> FileResponse: | |
| """Export documents as Excel, JSON, or CSV.""" | |
| stmt = select(Document).where( | |
| Document.status.in_( | |
| [DocStatus.READY.value, DocStatus.VALIDATED.value] | |
| ) | |
| ) | |
| if batch_id: | |
| stmt = stmt.where(Document.batch_id == batch_id) | |
| result = await session.execute(stmt) | |
| docs = list(result.scalars().all()) | |
| if not docs: | |
| raise HTTPException(404, "No documents to export") | |
| try: | |
| path = build_export(docs, fmt) | |
| except ValueError as exc: | |
| raise HTTPException(400, str(exc)) from exc | |
| media = { | |
| "json": "application/json", | |
| "csv": "text/csv", | |
| "xlsx": _XLSX_MEDIA, | |
| "excel": _XLSX_MEDIA, | |
| } | |
| return FileResponse( | |
| path, | |
| filename=path.name, | |
| media_type=media.get(fmt, "application/octet-stream"), | |
| ) | |
| async def dashboard( | |
| session: AsyncSession = Depends(get_session), | |
| ) -> DashboardStats: | |
| """Aggregate processing stats.""" | |
| docs = ( | |
| await session.execute(select(Document)) | |
| ).scalars().all() | |
| by_type = Counter(d.doc_type for d in docs) | |
| needs_review = 0 | |
| conf_scores: list[float] = [] | |
| duplicates = 0 | |
| for doc in docs: | |
| if doc.is_duplicate: | |
| duplicates += 1 | |
| if doc.avg_confidence is not None: | |
| conf_scores.append(doc.avg_confidence) | |
| conf = doc.confidence or {} | |
| if any( | |
| isinstance(v, dict) and v.get("needs_review") | |
| for v in conf.values() | |
| ): | |
| needs_review += 1 | |
| batch_count = ( | |
| await session.execute(select(func.count(Batch.id))) | |
| ).scalar() or 0 | |
| avg = ( | |
| sum(conf_scores) / len(conf_scores) | |
| if conf_scores | |
| else 0.0 | |
| ) | |
| return DashboardStats( | |
| total_documents=len(docs), | |
| by_type=dict(by_type), | |
| needs_review=needs_review, | |
| duplicates=duplicates, | |
| avg_confidence=round(avg, 3), | |
| batches=batch_count, | |
| ) | |
| async def public_settings() -> PublicSettings: | |
| """Expose non-secret settings to the UI.""" | |
| settings = get_settings() | |
| return PublicSettings( | |
| app_name=settings.app_name, | |
| confidence_threshold=settings.confidence_threshold, | |
| output_language=settings.output_language, | |
| openai=settings.has_openai, | |
| text_model=settings.openai_model, | |
| vision_model=settings.openai_vision_model, | |
| ) | |