import os import asyncio from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from loguru import logger from app.core.config import get_settings from app.db.database import init_db from app.api.routes.auth import router as auth_router from app.api.routes.conversations import router as conv_router from app.api.routes.query import router as query_router from app.api.routes.documents import router as docs_router from app.api.routes.audio import router as audio_router from app.api.routes.health_admin import health_router, admin_router settings = get_settings() os.makedirs("./data/users", exist_ok=True) from app.services.speech_service import get_speech_service, get_tts_service @asynccontextmanager async def lifespan(app: FastAPI): logger.info(f"Starting {settings.app_name} v{settings.app_version}") await init_db() logger.info("Main database initialised") # Preload STT and TTS models during startup to avoid latency on first request try: logger.info("Preloading Speech-to-Text (STT) model...") await asyncio.to_thread(get_speech_service) logger.info("STT model preloaded successfully") logger.info("Preloading Text-to-Speech (TTS) model...") await asyncio.to_thread(get_tts_service().preload, settings.tts_voice) logger.info("TTS model preloaded successfully") except Exception as e: logger.error(f"Failed to preload speech models during startup: {e}") # Ensure Qdrant collection and indexes exist try: from app.services.qdrant_service import get_qdrant_service qdrant = get_qdrant_service() await qdrant.ensure_collection() logger.info("Qdrant collection and payload indexes ensured on startup") except Exception as e: logger.error(f"Failed to initialize Qdrant collection on startup: {e}") yield logger.info("Shutting down") app = FastAPI( title=settings.app_name, version=settings.app_version, description="Medical Knowledge RAG API — Groq · Llama 4 Scout · Qdrant · BioBERT · Cross-Encoder", lifespan=lifespan, ) app.add_middleware( CORSMiddleware, allow_origins=settings.allowed_origins_list, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # ─── Routers ────────────────────────────────────────────────────────────────── PREFIX = "/api/v1" app.include_router(health_router, prefix=PREFIX) app.include_router(auth_router, prefix=PREFIX) app.include_router(conv_router, prefix=PREFIX) app.include_router(query_router, prefix=PREFIX) app.include_router(docs_router, prefix=PREFIX) app.include_router(audio_router, prefix=PREFIX) app.include_router(admin_router, prefix=PREFIX) @app.get("/") async def root(): return {"name": settings.app_name, "version": settings.app_version, "docs": "/docs"}