"""XRayVision AI — FastAPI Application Entry Point. Initializes the FastAPI app with CORS, model preloading, and all routers. """ from __future__ import annotations import logging import threading from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.config import get_settings logging.basicConfig( level=logging.INFO, format="%(asctime)s | %(levelname)-7s | %(name)s | %(message)s", ) logger = logging.getLogger("xrayvision") def _preload_models_background(): """Load AI models in a background thread so the server starts immediately.""" logger.info("📦 Preloading AI models in background thread...") try: from app.services.chest_model import _get_model as load_chest load_chest() logger.info("✅ DenseNet121 (Chest Pathology) loaded") except Exception as e: logger.warning(f"⚠️ DenseNet121 failed to preload: {e}") try: from app.services.fracture_model import _get_model as load_fracture load_fracture() logger.info("✅ YOLOv8 (Fracture Detection) loaded") except Exception as e: logger.warning(f"⚠️ YOLOv8 failed to preload: {e}") try: if get_settings().fracture_classifier_enabled: from app.services.fracture_classifier import _get_model as load_fracture_classifier load_fracture_classifier() logger.info("HF Fracture Classifier loaded") except Exception as e: logger.warning(f"HF Fracture Classifier failed to preload: {e}") try: from app.services.wound_model import _get_model as load_wound load_wound() logger.info("✅ ViT (Wound Classification) loaded") except Exception as e: logger.warning(f"⚠️ ViT failed to preload: {e}") logger.info("🟢 All AI models loaded and ready!") @asynccontextmanager async def lifespan(app: FastAPI): """Start model loading in background — server is ready immediately.""" logger.info("🚀 XRayVision AI backend starting...") settings = get_settings() if settings.disable_preload: # On free-tier hosts (<=512 MB RAM) skip preloading entirely. # Models will lazy-load on first use so auth/chat/diet work immediately. logger.info("⏭️ DISABLE_PRELOAD=true — models will load on first use") else: # Full preload on capable hosts (HuggingFace Spaces, Render Standard+) thread = threading.Thread(target=_preload_models_background, daemon=True) thread.start() logger.info("🟢 XRayVision AI is accepting requests! (models loading in background)") yield logger.info("🔴 XRayVision AI shutting down...") def create_app() -> FastAPI: """Create and configure the FastAPI application.""" settings = get_settings() app = FastAPI( title="XRayVision AI", description=( "Advanced medical diagnostic API using a Hybrid Multi-Model Ensemble. " "DenseNet121 for chest pathology, YOLOv8 for fracture detection, " "ViT for wound classification, and OpenRouter GLM 4.5 Air for agentic synthesis." ), version="2.1.0", lifespan=lifespan, docs_url="/docs", redoc_url="/redoc", ) # CORS — allow common dev origins app.add_middleware( CORSMiddleware, allow_origins=[ settings.frontend_url, "http://localhost:5173", "http://localhost:5174", "http://localhost:3000", "http://localhost:3001", "http://localhost:8080", "http://localhost:8081", "http://127.0.0.1:5173", "http://127.0.0.1:3000", ], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Register routers from app.routers import auth, analyze, scans, chat, diet, stats, clinics app.include_router(auth.router) app.include_router(analyze.router) app.include_router(scans.router) app.include_router(chat.router) app.include_router(diet.router) app.include_router(stats.router) app.include_router(clinics.router) @app.get("/", tags=["health"]) async def health(): return { "status": "healthy", "service": "XRayVision AI", "version": "2.1.0", "models": ["DenseNet121", "YOLOv8", "ViT", "OpenRouter GLM 4.5 Air"], } @app.get("/health", tags=["health"]) async def health_check(): return {"status": "ok"} return app app = create_app()