Spaces:
Running
Running
| from fastapi import FastAPI, Request | |
| from fastapi.responses import HTMLResponse, JSONResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from pathlib import Path | |
| from datetime import datetime | |
| from agents.manager import plan_mission | |
| from agents.specialized import run_specialized_agent | |
| from core.storage import save_mission, load_recent_missions | |
| app = FastAPI(title="Mission Control Aetheris") | |
| # βββββββββββββββββββββββββββββ | |
| # STATIC | |
| # βββββββββββββββββββββββββββββ | |
| templates_dir = Path("templates") | |
| docs_dir = Path("data/docs") | |
| if docs_dir.exists(): | |
| app.mount("/docs", StaticFiles(directory=docs_dir), name="docs") | |
| async def root(): | |
| return (templates_dir / "code_new.html").read_text(encoding="utf-8") | |
| # βββββββββββββββββββββββββββββ | |
| # HEALTH | |
| # βββββββββββββββββββββββββββββ | |
| async def health(): | |
| return {"status": "ok"} | |
| # βββββββββββββββββββββββββββββ | |
| # HISTORY | |
| # βββββββββββββββββββββββββββββ | |
| async def get_history(): | |
| try: | |
| missions = load_recent_missions(limit=100) | |
| return {"missions": missions} | |
| except Exception as e: | |
| return JSONResponse({"error": str(e)}, status_code=500) | |
| # βββββββββββββββββββββββββββββ | |
| # DIAGNOSTICS | |
| # βββββββββββββββββββββββββββββ | |
| async def diagnostics(): | |
| try: | |
| import psutil, time | |
| cpu_percent = psutil.cpu_percent(interval=0.3) | |
| cpu_count = psutil.cpu_count() | |
| ram = psutil.virtual_memory() | |
| ram_total_gb = round(ram.total / (1024**3), 2) | |
| ram_used_gb = round(ram.used / (1024**3), 2) | |
| ram_percent = ram.percent | |
| disk = psutil.disk_usage("/") | |
| disk_total_gb = round(disk.total / (1024**3), 2) | |
| disk_used_gb = round(disk.used / (1024**3), 2) | |
| disk_percent = disk.percent | |
| net1 = psutil.net_io_counters() | |
| time.sleep(0.5) | |
| net2 = psutil.net_io_counters() | |
| net_in_kb = round((net2.bytes_recv - net1.bytes_recv) / 512, 2) | |
| net_out_kb = round((net2.bytes_sent - net1.bytes_sent) / 512, 2) | |
| net_in_total_mb = round(net2.bytes_recv / (1024**2), 2) | |
| net_out_total_mb = round(net2.bytes_sent / (1024**2), 2) | |
| return { | |
| "timestamp": datetime.now().isoformat(), | |
| "cpu": {"percent": cpu_percent, "cores": cpu_count}, | |
| "ram": {"percent": ram_percent, "used_gb": ram_used_gb, "total_gb": ram_total_gb}, | |
| "disk": {"percent": disk_percent, "used_gb": disk_used_gb, "total_gb": disk_total_gb}, | |
| "network": { | |
| "in_kb_s": net_in_kb, "out_kb_s": net_out_kb, | |
| "in_total_mb": net_in_total_mb, "out_total_mb": net_out_total_mb, | |
| } | |
| } | |
| except Exception as e: | |
| return JSONResponse({"error": str(e)}, status_code=500) | |
| # βββββββββββββββββββββββββββββ | |
| # MANAGER (CHAT) | |
| # βββββββββββββββββββββββββββββ | |
| async def manager_only(request: Request): | |
| data = await request.json() | |
| task = data.get("task", "").strip() | |
| if not task: | |
| return JSONResponse({"error": "No task"}, status_code=400) | |
| plan = await plan_mission(task) | |
| return { | |
| "response": plan.get("reasoning"), | |
| "delegate": plan.get("delegate"), | |
| "raw": plan.get("raw"), | |
| "provider": "HuggingFace Router", | |
| "model": "Qwen/Qwen2.5-7B-Instruct" | |
| } | |
| # βββββββββββββββββββββββββββββ | |
| # MISIΓN COMPLETA | |
| # βββββββββββββββββββββββββββββ | |
| async def create_mission(request: Request): | |
| data = await request.json() | |
| task = data.get("task", "").strip() | |
| if not task: | |
| return JSONResponse({"error": "No task provided"}, status_code=400) | |
| started_at = datetime.now().isoformat() | |
| plan = await plan_mission(task) | |
| # ββ Ordenar pipeline: analyst siempre antes que writer ββββββββββββββββββ | |
| delegates = plan.get("delegate", []) | |
| PIPELINE_ORDER = ["analyst", "backend_dev", "frontend_dev", "writer", "image_agent"] | |
| delegates = sorted(delegates, key=lambda k: PIPELINE_ORDER.index(k) if k in PIPELINE_ORDER else 99) | |
| results = [] | |
| shared_context = {} | |
| for agent_key in delegates: | |
| result = await run_specialized_agent(agent_key, task, context=shared_context) | |
| results.append(result) | |
| if result.get("success"): | |
| shared_context[agent_key] = result.get("response", "") | |
| file_path = next((r["file_path"] for r in results if r.get("file_path")), None) | |
| file_url = f"/docs/{file_path}" if file_path else None | |
| # Serializar results para SQLite (quitar objetos no-JSON) | |
| safe_results = [] | |
| for r in results: | |
| safe_results.append({ | |
| "agent": r.get("agent"), | |
| "success": r.get("success"), | |
| "response": r.get("response", "")[:2000], # limitar tamaΓ±o | |
| "file_path": r.get("file_path"), | |
| "file_type": r.get("file_type"), | |
| "image_urls": r.get("image_urls", []), | |
| }) | |
| save_mission({ | |
| "task": task, | |
| "started_at": started_at, | |
| "ended_at": datetime.now().isoformat(), | |
| "plan": plan, | |
| "results": safe_results, | |
| "doc_file": file_path, | |
| "events": [], | |
| }) | |
| return { | |
| "success": True, | |
| "task": task, | |
| "plan": plan, | |
| "results": results, | |
| "file_url": file_url | |
| } |