Harshilforworks commited on
Commit
b729b1e
·
verified ·
1 Parent(s): 3f01219

Upload 14 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.12 full image (not slim)
2
+ FROM python:3.12
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies
8
+ RUN apt-get update && apt-get install -y \
9
+ build-essential \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ # Copy requirements first for better caching
13
+ COPY requirements.txt .
14
+
15
+ # Install Python dependencies
16
+ RUN pip install --no-cache-dir --upgrade pip && \
17
+ pip install --no-cache-dir -r requirements.txt
18
+
19
+ # Copy application code and models
20
+ COPY . .
21
+
22
+ # Expose port 7860 (Hugging Face Spaces default)
23
+ EXPOSE 7860
24
+
25
+ # Set environment variables for Hugging Face
26
+ ENV GRADIO_SERVER_NAME="0.0.0.0"
27
+ ENV GRADIO_SERVER_PORT=7860
28
+
29
+ # Run the application
30
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ MEDIGUARD API - FastAPI Application
4
+ Running on HuggingFace Spaces
5
+ """
6
+
7
+ import numpy as np
8
+ import pandas as pd
9
+ import joblib
10
+ from pathlib import Path
11
+ from fastapi import FastAPI, HTTPException
12
+ from pydantic import BaseModel, Field
13
+ from typing import List, Dict
14
+
15
+ # ============================================================
16
+ # CONFIGURATION
17
+ # ============================================================
18
+
19
+ MODEL_DIR = Path("models")
20
+
21
+ CLINICAL_RANGES = {
22
+ "Glucose": (60, 300),
23
+ "Cholesterol": (100, 350),
24
+ "Hemoglobin": (8, 20),
25
+ "Platelets": (50000, 700000),
26
+ "White Blood Cells": (3000, 20000),
27
+ "Red Blood Cells": (3.0, 7.0),
28
+ "Hematocrit": (25, 60),
29
+ "Mean Corpuscular Volume": (65, 110),
30
+ "Mean Corpuscular Hemoglobin": (20, 40),
31
+ "Mean Corpuscular Hemoglobin Concentration": (28, 38),
32
+ "Insulin": (1, 60),
33
+ "BMI": (12, 50),
34
+ "Systolic Blood Pressure": (80, 200),
35
+ "Diastolic Blood Pressure": (40, 130),
36
+ "Triglycerides": (40, 600),
37
+ "HbA1c": (3.0, 14.0),
38
+ "LDL Cholesterol": (40, 250),
39
+ "HDL Cholesterol": (10, 120),
40
+ "ALT": (5, 120),
41
+ "AST": (5, 120),
42
+ "Heart Rate": (40, 220),
43
+ "Creatinine": (0.2, 5.0),
44
+ "Troponin": (0, 10),
45
+ "C-reactive Protein": (0, 100),
46
+ }
47
+
48
+ FEATURE_ORDER = list(CLINICAL_RANGES.keys())
49
+
50
+ # ============================================================
51
+ # LOAD MODELS AT STARTUP
52
+ # ============================================================
53
+
54
+ print("🏥 Loading MediGuard models...")
55
+
56
+ try:
57
+ le = joblib.load(MODEL_DIR / "label_encoder.pkl")
58
+ scaler = joblib.load(MODEL_DIR / "scaler.pkl")
59
+ features_list = joblib.load(MODEL_DIR / "features.pkl")
60
+ meta = joblib.load(MODEL_DIR / "meta_neural.pkl")
61
+ metadata = joblib.load(MODEL_DIR / "metadata.pkl")
62
+
63
+ base_models = []
64
+ for f in sorted(MODEL_DIR.glob("base_*.pkl")):
65
+ model = joblib.load(f)
66
+ name = f.stem.replace("base_", "")
67
+ base_models.append((name, model))
68
+
69
+ MODELS_LOADED = True
70
+ print(f"✓ Loaded {len(base_models)} base models")
71
+ print(f"✓ Features: {len(features_list)}")
72
+ print(f"✓ Classes: {len(le.classes_)}")
73
+
74
+ except Exception as e:
75
+ MODELS_LOADED = False
76
+ print(f"❌ Error loading models: {e}")
77
+
78
+ # ============================================================
79
+ # PYDANTIC MODELS
80
+ # ============================================================
81
+
82
+ class PatientInput(BaseModel):
83
+ Glucose: float
84
+ Cholesterol: float
85
+ Hemoglobin: float
86
+ Platelets: float
87
+ White_Blood_Cells: float = Field(..., alias="White Blood Cells")
88
+ Red_Blood_Cells: float = Field(..., alias="Red Blood Cells")
89
+ Hematocrit: float
90
+ Mean_Corpuscular_Volume: float = Field(..., alias="Mean Corpuscular Volume")
91
+ Mean_Corpuscular_Hemoglobin: float = Field(..., alias="Mean Corpuscular Hemoglobin")
92
+ Mean_Corpuscular_Hemoglobin_Concentration: float = Field(..., alias="Mean Corpuscular Hemoglobin Concentration")
93
+ Insulin: float
94
+ BMI: float
95
+ Systolic_Blood_Pressure: float = Field(..., alias="Systolic Blood Pressure")
96
+ Diastolic_Blood_Pressure: float = Field(..., alias="Diastolic Blood Pressure")
97
+ Triglycerides: float
98
+ HbA1c: float
99
+ LDL_Cholesterol: float = Field(..., alias="LDL Cholesterol")
100
+ HDL_Cholesterol: float = Field(..., alias="HDL Cholesterol")
101
+ ALT: float
102
+ AST: float
103
+ Heart_Rate: float = Field(..., alias="Heart Rate")
104
+ Creatinine: float
105
+ Troponin: float
106
+ C_reactive_Protein: float = Field(..., alias="C-reactive Protein")
107
+
108
+ class Config:
109
+ populate_by_name = True
110
+
111
+
112
+ class PredictionResult(BaseModel):
113
+ prediction: str
114
+ confidence: float
115
+ top_5_predictions: List[Dict[str, float]]
116
+ scaled_values: Dict[str, float]
117
+ model_version: str = "1.0"
118
+
119
+
120
+ class HealthResponse(BaseModel):
121
+ status: str
122
+ models_loaded: bool
123
+ n_base_models: int
124
+ n_diseases: int
125
+
126
+
127
+ # ============================================================
128
+ # HELPER FUNCTIONS
129
+ # ============================================================
130
+
131
+ def scale_value(value: float, feature: str) -> float:
132
+ mn, mx = CLINICAL_RANGES[feature]
133
+ clipped = max(mn, min(mx, float(value)))
134
+ return (clipped - mn) / (mx - mn)
135
+
136
+
137
+ def engineer_features(input_df: pd.DataFrame) -> pd.DataFrame:
138
+ df = input_df.copy()
139
+ # NOTE: If you want the FULL feature engineering block here,
140
+ # paste it EXACTLY from your original code.
141
+ return df
142
+
143
+
144
+ def predict_disease(raw_values: Dict[str, float]) -> Dict:
145
+ scaled_values = {f: scale_value(v, f) for f, v in raw_values.items()}
146
+ input_df = pd.DataFrame([scaled_values])
147
+ input_engineered = engineer_features(input_df)
148
+
149
+ for feat in features_list:
150
+ if feat not in input_engineered.columns:
151
+ input_engineered[feat] = 0
152
+
153
+ input_engineered = input_engineered[features_list]
154
+ X = scaler.transform(input_engineered.values)
155
+
156
+ base_probs = [model.predict_proba(X) for _, model in base_models]
157
+ meta_features = np.hstack(base_probs)
158
+ probs = meta.predict_proba(meta_features)[0]
159
+
160
+ pred_idx = np.argmax(probs)
161
+ disease = le.inverse_transform([pred_idx])[0]
162
+ confidence = float(probs[pred_idx])
163
+
164
+ top5_idx = np.argsort(probs)[-5:][::-1]
165
+ top5 = [{"disease": le.inverse_transform([i])[0],
166
+ "probability": float(probs[i])} for i in top5_idx]
167
+
168
+ return {
169
+ "prediction": disease,
170
+ "confidence": confidence,
171
+ "top_5_predictions": top5,
172
+ "scaled_values": scaled_values
173
+ }
174
+
175
+ # ============================================================
176
+ # FASTAPI BACKEND
177
+ # ============================================================
178
+
179
+ app = FastAPI(title="MediGuard API Backend")
180
+
181
+ @app.get("/health")
182
+ def health():
183
+ return {
184
+ "status": "healthy" if MODELS_LOADED else "unhealthy",
185
+ "models_loaded": MODELS_LOADED,
186
+ "n_base_models": len(base_models),
187
+ "n_diseases": len(le.classes_),
188
+ }
189
+
190
+ @app.post("/predict", response_model=PredictionResult)
191
+ def predict(patient: PatientInput):
192
+ raw_values = {k: getattr(patient, k.replace(" ", "_")) for k in CLINICAL_RANGES.keys()}
193
+ result = predict_disease(raw_values)
194
+ return PredictionResult(**result)
195
+
196
+ # ============================================================
197
+ # RUN THE APPLICATION
198
+ # ============================================================
199
+
200
+ if __name__ == "__main__":
201
+ import uvicorn
202
+ uvicorn.run(app, host="0.0.0.0", port=7860)
models/base_LightGBM.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:063f7957f26bc43bcacc3c8fe166e439570c8d53b089485622de6dbeb610a200
3
+ size 10054996
models/base_XGB_Aggressive.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8a90ee13044e8ddace99515840c094f8458282f88879b019363f1995894392e7
3
+ size 5631588
models/base_XGB_Balanced.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6ae71f7735d5a7c412788f9cf0d9d72bade14fdf1f99f2b6a5b81a0f4a4a73b2
3
+ size 7123421
models/base_XGB_Conservative.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4b9395cc9568629b3cbaaa11bc880f2546c72b413bb07381a7f8e64cfbc92e72
3
+ size 6701906
models/base_XGB_VeryDeep.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cb2a9712e3a688c134c63988be58815355c805c3efc77992114febc3c5582ebb
3
+ size 6606718
models/base_XGB_Wide.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f97279d067528472b0a0251a349fc51181b56094787ad449b511ccbe9027e753
3
+ size 7627616
models/features.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:68b5838b7106e2180386d487ff1bda96eed9aec77e6d511c2700f461fab89961
3
+ size 1209
models/label_encoder.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1bc1da9ba8b7a5b0b4c96f50fd1738fb605026c52feab7cf05a84da670b76a94
3
+ size 774
models/meta_neural.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:09bafaf8f9475ba8b790561a713eda070f375c0773040d6836af807faec8a926
3
+ size 887853
models/metadata.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:96438af3d822f20a48f27a3a3efb5ef2e074e31a4be6c979b76eacaeb81adda1
3
+ size 554
models/scaler.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:287c4d983cde39b5eaac45b2a0e524593f38ebe1ba90a6ee1ebdad7334fe5f08
3
+ size 2199
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ pydantic
3
+ numpy
4
+ pandas
5
+ scikit-learn
6
+ joblib
7
+ xgboost
8
+ lightgbm
9
+ uvicorn