""" FastAPI Backend for QoS Buddy Thin app factory — business logic lives in routes/ and services/. """ import warnings warnings.filterwarnings("ignore", category=UserWarning) warnings.filterwarnings("ignore", category=FutureWarning) import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from datetime import datetime import uvicorn import os from core.config import CORS_ORIGINS, ENABLE_DB_ALERTS from database import init_db from routes import deps from routes.chat import router as chat_router from routes.diagnostics import router as diagnostics_router from routes.ml import router as ml_router from routes.data import router as data_router from routes.auth import router as auth_router from routes.simulator import router as simulator_router from routes.live_data import router as live_data_router app = FastAPI( title="QoS Buddy API", description="Multi-Agent Telecom Network Diagnostic System", version="2.0.0", ) app.add_middleware( CORSMiddleware, allow_origins=CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Register route modules app.include_router(auth_router) app.include_router(chat_router) app.include_router(diagnostics_router) app.include_router(ml_router) app.include_router(data_router) app.include_router(simulator_router) app.include_router(live_data_router) @app.on_event("startup") async def startup_event(): """Initialize agents on startup.""" print("=" * 70) print("INITIALIZING QoS BUDDY BACKEND v2.0") print("=" * 70) agent1 = None agent2 = None orchestrator = None try: print("\n[0/3] Initializing database tables...") init_db() print(" Database schema ready") except Exception as e: print(f" Database init warning: {e}") try: print("\n[1/3] Initializing orchestrator + Data Manager...") from services.orchestrator import QoSOrchestrator orchestrator = QoSOrchestrator() orchestrator.refresh_data() print(" Orchestrator ready") except Exception as e: print(f" Orchestrator initialization failed: {e}") try: print("\n[2/3] Initializing Agent 1 (Chatbot Advisor)...") from agents.agent1_chatbot import TelecomAdvisorAgent agent1 = TelecomAdvisorAgent() # Heavy init moved to thread/background manually here for simplicity in this specific app structure import threading def bg_agent1_init(a1, orch): try: a1.initialize_vector_db() if orch: a1.set_insights_provider(orch.live_insights_snapshot) orch.wire_agent1(a1) print(" [BG] Agent 1 ready") except Exception as e_bg: print(f" [BG] Agent 1 init failed: {e_bg}") threading.Thread(target=bg_agent1_init, args=(agent1, orchestrator), daemon=True).start() print(" Agent 1 initialization started in background") except Exception as e: print(f" Agent 1 setup failed: {e}") try: print("\n[3/3] Initializing Agent 2 (Diagnostic Worker)...") from agents.agent2_diagnostic import DiagnosticAgent agent2 = DiagnosticAgent() print(" Agent 2 ready") except Exception as e: print(f" Agent 2 initialization failed: {e}") # Wire globals so route modules can access agents deps.set_globals(agent1, agent2, orchestrator) print("\n" + "=" * 70) print("QoS BUDDY BACKEND READY") print(f" DB alerts: {'enabled' if ENABLE_DB_ALERTS else 'disabled'}") print(f" CORS origins: {CORS_ORIGINS}") print(f" API docs: http://localhost:8000/docs") print("=" * 70 + "\n") @app.get("/") async def root(): return { "service": "QoS Buddy API", "version": "2.0.0", "status": "online", "agents": { "agent1_chatbot": deps.get_agent1() is not None, "agent2_diagnostic": deps.get_agent2() is not None, "orchestrator": deps.get_orchestrator() is not None, }, } @app.get("/health") async def health_check(): return { "status": "healthy", "timestamp": datetime.now().isoformat(), "agents": { "agent1": "online" if deps.get_agent1() else "offline", "agent2": "online" if deps.get_agent2() else "offline", "orchestrator": "online" if deps.get_orchestrator() else "offline", }, } if __name__ == "__main__": print("\nStarting QoS Buddy Backend Server...") use_reload = os.getenv("DEV_MODE", "false").lower() == "true" uvicorn.run( "main:app", host="0.0.0.0", port=8000, reload=use_reload, reload_excludes=["../data/*", "*.db", "*.sqlite"] if use_reload else None, log_level="info", )