| from __future__ import annotations |
| import logging |
| import uuid |
| from datetime import datetime |
| from typing import List, Optional |
|
|
| from fastapi import APIRouter, File, Form, HTTPException, UploadFile |
| from pydantic import BaseModel |
|
|
| from schemas.report import ReportInput, ReportType, UploadBatch |
| from services.pipeline import Pipeline |
| from services.storage import get_storage |
|
|
| logger = logging.getLogger(__name__) |
| router = APIRouter(prefix="/reports", tags=["reports"]) |
|
|
|
|
| @router.post("/upload") |
| async def upload_reports( |
| session_id: Optional[str] = Form(default=None), |
| scenario_name: Optional[str] = Form(default=None), |
| files: List[UploadFile] = File(default=[]), |
| text_messages: Optional[str] = Form(default=None), |
| ) -> dict: |
| sid = session_id or str(uuid.uuid4()) |
| reports: List[ReportInput] = [] |
|
|
| if text_messages: |
| for i, msg in enumerate(text_messages.split("|||")): |
| msg = msg.strip() |
| if msg: |
| reports.append(ReportInput( |
| id=str(uuid.uuid4()), |
| session_id=sid, |
| report_type=ReportType.TEXT, |
| content=msg, |
| metadata={"source": "upload", "index": i}, |
| created_at=datetime.utcnow(), |
| )) |
|
|
| for file in files: |
| filename = file.filename or "unknown" |
| name_lower = filename.lower() |
| if name_lower.endswith((".mp3", ".wav", ".ogg", ".m4a")): |
| rtype = ReportType.AUDIO |
| elif name_lower.endswith((".jpg", ".jpeg", ".png", ".webp")): |
| rtype = ReportType.IMAGE |
| elif name_lower.endswith(".csv"): |
| rtype = ReportType.CSV |
| else: |
| rtype = ReportType.TEXT |
|
|
| content = await file.read() |
| reports.append(ReportInput( |
| id=str(uuid.uuid4()), |
| session_id=sid, |
| report_type=rtype, |
| content=content.decode("utf-8", errors="replace") if rtype in (ReportType.TEXT, ReportType.CSV) else None, |
| file_path=filename, |
| metadata={"original_filename": filename, "size_bytes": len(content)}, |
| created_at=datetime.utcnow(), |
| )) |
|
|
| storage = get_storage() |
| await storage.save_session(sid, { |
| "session_id": sid, |
| "scenario_name": scenario_name, |
| "total_reports": len(reports), |
| "status": "uploaded", |
| "created_at": datetime.utcnow().isoformat(), |
| }) |
|
|
| return {"session_id": sid, "batch_id": sid, "report_count": len(reports), "status": "uploaded"} |
|
|
|
|
| @router.post("/process") |
| async def process_batch(batch: UploadBatch) -> dict: |
| pipeline = Pipeline() |
| try: |
| summary = await pipeline.process_batch(batch) |
| except Exception as exc: |
| logger.exception("Batch processing error: %s", exc) |
| raise HTTPException(status_code=500, detail=str(exc)) |
| return summary.model_dump(mode="json") |
|
|
|
|
| @router.get("/{session_id}") |
| async def list_session_reports(session_id: str) -> dict: |
| storage = get_storage() |
| session = await storage.get_session(session_id) |
| if session is None: |
| raise HTTPException(status_code=404, detail=f"Session {session_id} not found") |
| return {"session_id": session_id, "session": session} |
|
|