File size: 4,164 Bytes
1425afc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | 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
# =================================================
@router.post("/execute/{task_name}")
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
# =================================================
@router.get("/tasks")
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
# =================================================
@router.get("/health")
async def health():
return {
"status": "ok",
"tasks_loaded": len(get_tasks()),
}
return router |