Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI | |
| from fastapi.responses import JSONResponse | |
| from fastapi.encoders import jsonable_encoder | |
| from pydantic import BaseModel | |
| import numpy as np | |
| import joblib | |
| import torch | |
| from catboost import CatBoostClassifier | |
| from lightgbm import LGBMClassifier | |
| from xgboost import XGBClassifier | |
| from pytorch_tabnet.tab_model import TabNetClassifier | |
| from pathlib import Path | |
| import os | |
| import sys | |
| BASE_DIR = Path(__file__).resolve().parents[1] | |
| if str(BASE_DIR) not in sys.path: | |
| sys.path.insert(0, str(BASE_DIR)) | |
| # CONFIG | |
| MODEL_DIR = BASE_DIR/"models" | |
| FUSION_PATH = BASE_DIR/"fusion"/"fusion_model_metadata.joblib" | |
| FEATURES = [ | |
| "rainfall_mm", "humidity_pct", "temp_c", "vegetation_index", | |
| "elevation_m", "proximity_to_water_km", "wind_speed_mps", | |
| "surface_water_presence", "daylight_hours", "season_label" | |
| ] | |
| # LOAD MODELS | |
| print(" Loading models...") | |
| cat_model = CatBoostClassifier() | |
| cat_model.load_model(f"{MODEL_DIR}/catboost.cbm") | |
| xgb_model = joblib.load(f"{MODEL_DIR}/xgboost.joblib") | |
| lgb_model = joblib.load(f"{MODEL_DIR}/lightgbm.joblib") | |
| tabnet_model = TabNetClassifier() | |
| tabnet_model.load_model(f"{MODEL_DIR}/tabnet.zip.zip") | |
| tabnet_scaler = joblib.load(f"{MODEL_DIR}/tabnet_scaler.joblib") | |
| fusion_meta = joblib.load(FUSION_PATH) | |
| print(" All models and fusion metadata loaded successfully.") | |
| # FASTAPI APP | |
| app = FastAPI(title="Malaria Risk Prediction API", version="1.0") | |
| # INPUT SCHEMA | |
| class MalariaInput(BaseModel): | |
| rainfall_mm: float | |
| humidity_pct: float | |
| temp_c: float | |
| vegetation_index: float | |
| elevation_m: float | |
| proximity_to_water_km: float | |
| wind_speed_mps: float | |
| surface_water_presence: float | |
| daylight_hours: float | |
| season_label: int # 0 = Dry, 1 = Rainy | |
| # PREDICTION ENDPOINT | |
| def predict(data: MalariaInput): | |
| try: | |
| x = np.array([[getattr(data, f) for f in FEATURES]], dtype=float) | |
| x_scaled = tabnet_scaler.transform(x) | |
| # Individual model probabilities | |
| preds = { | |
| "catboost": float(cat_model.predict_proba(x)[0][1]), | |
| "xgboost": float(xgb_model.predict_proba(x)[0][1]), | |
| "lightgbm": float(lgb_model.predict_proba(x)[0][1]), | |
| "tabnet": float(tabnet_model.predict_proba(torch.tensor(x_scaled).float().numpy())[0][1]), | |
| } | |
| # Fusion weights | |
| models_in_fusion = fusion_meta.get("models", []) | |
| weights_data = fusion_meta.get("weights", []) | |
| weights = {m: float(w) for m, w in zip(models_in_fusion, weights_data)} | |
| # Weighted ensemble score | |
| risk_score = float(sum(preds[m] * weights[m] for m in preds if m in weights)) | |
| #risk_percentage = round(risk_score * 100, 2) | |
| # Label decision | |
| risk_label = "High" if risk_score >= 0.60 else "Medium" | |
| response = { | |
| #"input_features": data.dict(), | |
| "model_outputs": preds, | |
| # "fusion_weights": weights, | |
| "risk_score": round(risk_score, 3), | |
| "risk_label": risk_label | |
| } | |
| return JSONResponse(content=jsonable_encoder(response)) | |
| except Exception as e: | |
| return JSONResponse( | |
| status_code=500, | |
| content={"error": str(e), "message": "Prediction failed."} | |
| ) | |
| # ROOT ENDPOINT | |
| def root(): | |
| return {"message": " Malaria Risk Prediction API is running!"} | |