UPDRS_API / ml /model_predictor.py
UdasriHasindu
load models from hugging face in first run
d352a67
Raw
History Blame Contribute Delete
2.92 kB
import joblib
import os
import numpy as np
import pandas as pd
from huggingface_hub import hf_hub_download
MODEL_REPO = "xplorers/parkinsons-updrs-model"
MODEL_DIR = "/tmp/models"
# In-memory cache — models are loaded once at startup, reused for every request
_cache = {}
def _download_and_cache():
"""Download models from HF Hub and cache in memory. Runs once at startup."""
if _cache:
return # already loaded
os.makedirs(MODEL_DIR, exist_ok=True)
filenames = ["ensemble_model.pkl", "feature_names.pkl", "scaler.pkl"]
for filename in filenames:
hf_hub_download(
repo_id=MODEL_REPO,
filename=filename,
repo_type="model",
local_dir=MODEL_DIR,
token=os.getenv("HF_TOKEN"), # needed if your HF model repo is private
)
_cache["model"] = joblib.load(os.path.join(MODEL_DIR, "ensemble_model.pkl"))
_cache["feature_names"] = joblib.load(os.path.join(MODEL_DIR, "feature_names.pkl"))
_cache["scaler"] = joblib.load(os.path.join(MODEL_DIR, "scaler.pkl"))
print("Models loaded into memory from HF Hub.")
def predict_parkinson(features: dict) -> float:
"""
Predict Parkinson's motor UPDRS score from patient features.
Uses cached models — no disk read on each request.
"""
try:
model = _cache["model"]
feature_names = _cache["feature_names"]
scaler = _cache["scaler"]
print(f"Expected features: {feature_names}")
print(f"Received features: {list(features.keys())}")
missing_features = [name for name in feature_names if name not in features]
if missing_features:
raise ValueError(f"Missing required features: {missing_features}")
for name in feature_names:
value = features[name]
if pd.isna(value) or np.isinf(value):
print(f"Warning: Feature '{name}' has invalid value: {value}, replacing with 0.0")
features[name] = 0.0
input_values = [features[name] for name in feature_names]
input_df = pd.DataFrame([input_values], columns=feature_names)
scaled_features = scaler.transform(input_df)
updrs_prediction = model.predict(scaled_features)[0]
return float(updrs_prediction)
except KeyError:
raise RuntimeError("Models not loaded. Ensure startup lifespan ran successfully.")
except Exception as e:
raise Exception(f"Prediction error: {e}")
def get_required_features():
try:
return list(_cache["feature_names"])
except KeyError:
return [
'age', 'sex', 'test_time', 'Jitter(%)', 'Jitter(Abs)', 'Jitter:RAP',
'Jitter:PPQ5', 'Jitter:DDP', 'Shimmer', 'Shimmer(dB)', 'Shimmer:APQ3',
'Shimmer:APQ5', 'Shimmer:APQ11', 'Shimmer:DDA', 'NHR', 'HNR',
'RPDE', 'DFA', 'PPE'
]