""" FILE: app/main.py DESCRIPTION: Bootstrap der FastAPI Anwendung für WP-25a (Agentic MoE). Orchestriert Lifespan-Events, globale Fehlerbehandlung und Routing. Prüft beim Start die Integrität der Mixture of Experts Konfiguration. VERSION: 1.1.0 (WP-25a: MoE Integrity Check) STATUS: Active DEPENDENCIES: app.config, app.routers.*, app.services.llm_service """ from __future__ import annotations import logging import os from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.responses import JSONResponse from .config import get_settings from .services.llm_service import LLMService # Import der Router from .routers.query import router as query_router from .routers.graph import router as graph_router from .routers.tools import router as tools_router from .routers.feedback import router as feedback_router from .routers.chat import router as chat_router from .routers.ingest import router as ingest_router try: from .routers.admin import router as admin_router except Exception: admin_router = None from .core.logging_setup import setup_logging # Initialisierung des Loggings noch VOR create_app() setup_logging() logger = logging.getLogger(__name__) # --- WP-25a: Lifespan Management mit MoE Integritäts-Prüfung --- @asynccontextmanager async def lifespan(app: FastAPI): """ Verwaltet den Lebenszyklus der Anwendung (Startup/Shutdown). Verifiziert die Verfügbarkeit der MoE-Experten-Profile und Strategien. """ settings = get_settings() logger.info("🚀 mindnet API: Starting up (WP-25a MoE Mode)...") # 1. Startup: Integritäts-Check der MoE Konfiguration # Wir prüfen die drei Säulen der Agentic-RAG Architektur. decision_cfg = os.getenv("MINDNET_DECISION_CONFIG", "config/decision_engine.yaml") profiles_cfg = getattr(settings, "LLM_PROFILES_PATH", "config/llm_profiles.yaml") prompts_cfg = settings.PROMPTS_PATH missing_files = [] if not os.path.exists(decision_cfg): missing_files.append(decision_cfg) if not os.path.exists(profiles_cfg): missing_files.append(profiles_cfg) if not os.path.exists(prompts_cfg): missing_files.append(prompts_cfg) if missing_files: logger.error(f"❌ CRITICAL: Missing MoE config files: {missing_files}") else: logger.info("✅ MoE Configuration files verified.") yield # 2. Shutdown: Ressourcen bereinigen logger.info("🛑 mindnet API: Shutting down...") try: llm = LLMService() await llm.close() logger.info("✨ LLM resources cleaned up.") except Exception as e: logger.warning(f"⚠️ Error during LLMService cleanup: {e}") logger.info("Goodbye.") # --- App Factory --- def create_app() -> FastAPI: """Initialisiert die FastAPI App mit WP-25a Erweiterungen.""" app = FastAPI( title="mindnet API", version="1.1.0", # WP-25a Milestone lifespan=lifespan, description="Digital Twin Knowledge Engine mit Mixture of Experts Orchestration." ) s = get_settings() # --- Globale Fehlerbehandlung (WP-25a Resilienz) --- @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): """Fängt unerwartete Fehler in der MoE-Prozesskette ab.""" logger.error(f"❌ Unhandled Engine Error: {exc}", exc_info=True) return JSONResponse( status_code=500, content={ "detail": "Ein interner Fehler ist in der MoE-Kette aufgetreten.", "error_type": type(exc).__name__ } ) # Healthcheck @app.get("/healthz") def healthz(): """Bietet Statusinformationen über die Engine und Datenbank-Verbindung.""" return { "status": "ok", "version": "1.1.0", "qdrant": s.QDRANT_URL, "prefix": s.COLLECTION_PREFIX, "moe_enabled": True } # Inkludieren der Router (100% Kompatibilität erhalten) app.include_router(query_router, prefix="/query", tags=["query"]) app.include_router(graph_router, prefix="/graph", tags=["graph"]) app.include_router(tools_router, prefix="/tools", tags=["tools"]) app.include_router(feedback_router, prefix="/feedback", tags=["feedback"]) app.include_router(chat_router, prefix="/chat", tags=["chat"]) # WP-25a Agentic Chat app.include_router(ingest_router, prefix="/ingest", tags=["ingest"]) if admin_router: app.include_router(admin_router, prefix="/admin", tags=["admin"]) return app # Instanziierung der App app = create_app()