138 lines
3.3 KiB
Python
138 lines
3.3 KiB
Python
"""
|
|
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
|
|
)
|