vfven's picture
Update main.py
3c8750c verified
Raw
History Blame Contribute Delete
6.18 kB
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")
@app.get("/", response_class=HTMLResponse)
async def root():
return (templates_dir / "code_new.html").read_text(encoding="utf-8")
# ─────────────────────────────
# HEALTH
# ─────────────────────────────
@app.get("/health")
async def health():
return {"status": "ok"}
# ─────────────────────────────
# HISTORY
# ─────────────────────────────
@app.get("/api/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
# ─────────────────────────────
@app.get("/api/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)
# ─────────────────────────────
@app.post("/api/manager")
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
# ─────────────────────────────
@app.post("/api/mission")
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
}