| """FastAPI app for the gallstone rural-adaptation demo.""" |
| from __future__ import annotations |
|
|
| from contextlib import asynccontextmanager |
|
|
| from fastapi import FastAPI, HTTPException |
| from fastapi.middleware.cors import CORSMiddleware |
|
|
| from . import predictor |
| from .schemas import ( |
| BioimpedanceRequest, |
| BioimpedanceResponse, |
| ExplainResponse, |
| PredictRequest, |
| PredictResponse, |
| ) |
|
|
|
|
| @asynccontextmanager |
| async def lifespan(app: FastAPI): |
| predictor.load_artifacts() |
| yield |
|
|
|
|
| app = FastAPI( |
| title="Gallstone rural-adaptation demo", |
| version="0.1.0", |
| lifespan=lifespan, |
| ) |
|
|
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=[ |
| "http://localhost:3000", |
| "http://127.0.0.1:3000", |
| "https://gallstone.rosewt.dev", |
| ], |
| allow_origin_regex=r"https://.*\.vercel\.app", |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
|
|
| @app.get("/health") |
| def health() -> dict: |
| return { |
| "status": "ok", |
| "model_loaded": predictor.is_model_loaded(), |
| "explainer_loaded": predictor.is_explainer_loaded(), |
| } |
|
|
|
|
| @app.get("/model/info") |
| def model_info() -> dict: |
| metrics = predictor.get_metrics() |
| if metrics is None: |
| raise HTTPException(status_code=404, detail="Metrics not available") |
| return metrics |
|
|
|
|
| @app.post("/predict/rural", response_model=PredictResponse) |
| def predict_rural(payload: PredictRequest) -> PredictResponse: |
| prob, risk = predictor.predict(payload.features) |
| return PredictResponse(probability=prob, risk_level=risk) |
|
|
|
|
| @app.post("/explain/rural", response_model=ExplainResponse) |
| def explain_rural(payload: PredictRequest) -> ExplainResponse: |
| shap_values, base_value = predictor.explain(payload.features) |
| return ExplainResponse(shap_values=shap_values, base_value=base_value) |
|
|
|
|
| @app.post("/generate/bioimpedance", response_model=BioimpedanceResponse) |
| def generate_bioimpedance(payload: BioimpedanceRequest) -> BioimpedanceResponse: |
| features = predictor.generate_bioimpedance( |
| age=payload.age, |
| gender=payload.gender, |
| height=payload.height, |
| weight=payload.weight, |
| bmi=payload.bmi, |
| ) |
| return BioimpedanceResponse(features=features) |
|
|