""" FastAPI server for Brace Generator. Provides REST API for: - X-ray analysis and landmark detection - Cobb angle measurement - Rigo-ChĂȘneau classification - Adaptive brace generation (STL/PLY) Usage: uvicorn server.app:app --host 0.0.0.0 --port 8000 Or with Docker: docker run -p 8000:8000 --gpus all brace-generator """ import sys from pathlib import Path from contextlib import asynccontextmanager # Add parent directories to path for imports server_dir = Path(__file__).parent brace_generator_dir = server_dir.parent spine_dir = brace_generator_dir.parent sys.path.insert(0, str(spine_dir)) sys.path.insert(0, str(brace_generator_dir)) from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse import torch from .config import config from .routes import router from .services import BraceService # Global service instance (initialized on startup) brace_service: BraceService = None @asynccontextmanager async def lifespan(app: FastAPI): """Initialize and cleanup resources.""" global brace_service print("=" * 60) print("Brace Generator Server Starting") print("=" * 60) # Ensure directories exist config.ensure_dirs() # Initialize service with model device = config.get_device() print(f"Device: {device}") if device == "cuda": print(f"GPU: {torch.cuda.get_device_name(0)}") print(f"GPU Memory: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.1f} GB") print(f"Loading model: {config.MODEL}") brace_service = BraceService(device=device, model=config.MODEL) print("Model loaded successfully!") # Make service available to routes app.state.brace_service = brace_service print("=" * 60) print(f"Server ready at http://{config.HOST}:{config.PORT}") print("=" * 60) yield # Cleanup print("Shutting down...") del brace_service # Create FastAPI app app = FastAPI( title="Brace Generator API", description=""" API for generating scoliosis braces from X-ray images. ## Features - Vertebrae landmark detection (ScolioVis model) - Cobb angle measurement (PT, MT, TL) - Rigo-ChĂȘneau classification - Adaptive brace generation with research-based deformations ## Experiments - **standard**: Original template-based pipeline - **experiment_3**: Research-based adaptive deformation (Guy et al. 2024) """, version="1.0.0", lifespan=lifespan, ) # CORS middleware app.add_middleware( CORSMiddleware, allow_origins=config.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routes app.include_router(router) # Exception handlers @app.exception_handler(HTTPException) async def http_exception_handler(request, exc): return JSONResponse( status_code=exc.status_code, content={"error": exc.detail} ) @app.exception_handler(Exception) async def general_exception_handler(request, exc): return JSONResponse( status_code=500, content={"error": "Internal server error", "detail": str(exc)} ) if __name__ == "__main__": import uvicorn uvicorn.run( "server.app:app", host=config.HOST, port=config.PORT, reload=config.DEBUG )