Spaces:
Running
Running
| from fastapi import APIRouter, UploadFile, File, Form, HTTPException | |
| from fastapi.responses import JSONResponse, FileResponse | |
| from typing import Optional | |
| import tempfile | |
| import shutil | |
| import os | |
| from core.registry.loader import get_tasks | |
| from core.execution.executor import execute_task | |
| # ===================================================== | |
| # ROUTER BUILDER | |
| # ===================================================== | |
| def build_api_router() -> APIRouter: | |
| """ | |
| Dynamically builds API routes from TASK REGISTRY. | |
| Generated endpoints: | |
| POST /execute/{task} | |
| GET /tasks | |
| GET /health | |
| """ | |
| router = APIRouter(tags=["API"]) | |
| # ================================================= | |
| # EXECUTE TASK | |
| # ================================================= | |
| async def execute( | |
| task_name: str, | |
| file: Optional[UploadFile] = File(None), | |
| url_input: Optional[str] = Form(None), | |
| ): | |
| """ | |
| Universal execution endpoint. | |
| Accepts: | |
| - file upload | |
| - url_input | |
| """ | |
| tasks = get_tasks() | |
| if task_name not in tasks: | |
| raise HTTPException( | |
| status_code=404, | |
| detail=f"Task '{task_name}' not found", | |
| ) | |
| temp_path = None | |
| try: | |
| # ----------------------------------------- | |
| # SAVE UPLOADED FILE | |
| # ----------------------------------------- | |
| if file: | |
| suffix = os.path.splitext(file.filename)[1] | |
| with tempfile.NamedTemporaryFile( | |
| delete=False, | |
| suffix=suffix, | |
| ) as tmp: | |
| shutil.copyfileobj(file.file, tmp) | |
| temp_path = tmp.name | |
| # ----------------------------------------- | |
| # BUILD INPUT PAYLOAD | |
| # ----------------------------------------- | |
| payload = { | |
| "file_path": temp_path, | |
| "url_input": url_input, | |
| } | |
| # ----------------------------------------- | |
| # EXECUTE TASK | |
| # ----------------------------------------- | |
| result = await execute_task(task_name, payload) | |
| # ----------------------------------------- | |
| # FILE RESPONSE | |
| # ----------------------------------------- | |
| if isinstance(result, dict) and result.get("file"): | |
| output_file = result["file"] | |
| if os.path.exists(output_file): | |
| return FileResponse( | |
| output_file, | |
| filename=os.path.basename(output_file), | |
| ) | |
| # ----------------------------------------- | |
| # JSON RESPONSE | |
| # ----------------------------------------- | |
| return JSONResponse(result) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=str(e), | |
| ) | |
| finally: | |
| # ----------------------------------------- | |
| # CLEANUP TEMP FILE | |
| # ----------------------------------------- | |
| if temp_path and os.path.exists(temp_path): | |
| os.unlink(temp_path) | |
| # ================================================= | |
| # TASK LIST | |
| # ================================================= | |
| async def list_tasks(): | |
| """ | |
| Returns registry tasks. | |
| Used by UI and Docs builder. | |
| """ | |
| tasks = get_tasks() | |
| return { | |
| name: { | |
| "category": getattr(t, "category", "general"), | |
| "description": getattr(t, "description", ""), | |
| } | |
| for name, t in tasks.items() | |
| } | |
| # ================================================= | |
| # HEALTH CHECK | |
| # ================================================= | |
| async def health(): | |
| return { | |
| "status": "ok", | |
| "tasks_loaded": len(get_tasks()), | |
| } | |
| return router |