Spaces:
Running
Running
| """ | |
| src/api/jobs.py — Phase 3: Async upload job status endpoints | |
| GET /api/jobs/{job_id} → poll job status + progress | |
| This is the API router. The job queue worker lives in src/services/jobs.py. | |
| """ | |
| from fastapi import APIRouter, Depends, HTTPException, Request | |
| from src.core.security import get_verified_keys | |
| from src.core.logging import log | |
| from src.services.jobs import get_job_status | |
| from src.common.utils import get_ip | |
| router = APIRouter() | |
| async def poll_job( | |
| job_id: str, | |
| request: Request, | |
| keys: dict = Depends(get_verified_keys), | |
| ): | |
| ip = get_ip(request) | |
| job = await get_job_status(job_id) | |
| if not job: | |
| raise HTTPException(404, f"Job {job_id} not found") | |
| total = job.get("total_files", 0) | |
| processed = job.get("processed_files", 0) | |
| pct = round(processed / total * 100) if total else 0 | |
| response = { | |
| "job_id": job_id, | |
| "status": job.get("status", "unknown"), | |
| "total_files": total, | |
| "processed_files": processed, | |
| "progress_pct": pct, | |
| "status_url": f"/api/jobs/{job_id}", | |
| } | |
| if job.get("status") == "completed": | |
| response["result"] = job.get("result", {}) | |
| if job.get("status") == "failed": | |
| response["error"] = job.get("error", "unknown error") | |
| log("INFO", "jobs.poll", ip=ip, job_id=job_id, status=response["status"]) | |
| return response |