Alizain78688 commited on
Commit
840dc13
·
verified ·
1 Parent(s): 1013127

Upload 6 files

Browse files
Files changed (6) hide show
  1. Dockerfile +16 -0
  2. app.py +329 -0
  3. app_gradio.py +96 -0
  4. diabetes_model.pkl +3 -0
  5. requirements.txt +8 -0
  6. scaler.pkl +3 -0
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ curl \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
+ COPY requirements.txt .
11
+ RUN pip install --no-cache-dir --upgrade pip && \
12
+ pip install --no-cache-dir -r requirements.txt
13
+
14
+ COPY . .
15
+
16
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pickle
2
+ import numpy as np
3
+ import sys
4
+ import traceback
5
+ from contextlib import asynccontextmanager
6
+ from fastapi import FastAPI, HTTPException
7
+ from pydantic import BaseModel
8
+ from typing import List, Optional
9
+ from fastapi.middleware.cors import CORSMiddleware
10
+
11
+ # Global variables for model and scaler
12
+ model = None
13
+ scaler = None
14
+
15
+ def load_model_with_fallback():
16
+ """Load model with multiple fallback methods"""
17
+ global model, scaler
18
+
19
+ print("=" * 50)
20
+ print("Attempting to load model and scaler...")
21
+
22
+ # Method 1: Try joblib first (more robust)
23
+ try:
24
+ import joblib
25
+ print("Trying joblib...")
26
+ model = joblib.load('diabetes_model.pkl')
27
+ scaler = joblib.load('scaler.pkl')
28
+ print("✓ Model and scaler loaded with joblib")
29
+ return True
30
+ except Exception as e:
31
+ print(f"Joblib failed: {e}")
32
+
33
+ # Method 2: Try pickle with custom unpickler
34
+ try:
35
+ print("Trying pickle with custom unpickler...")
36
+
37
+ class CustomUnpickler(pickle.Unpickler):
38
+ def find_class(self, module, name):
39
+ # Handle common module changes
40
+ if module.startswith('numpy._core'):
41
+ module = module.replace('numpy._core', 'numpy.core')
42
+ elif module == 'numpy.core._multiarray_umath':
43
+ module = 'numpy'
44
+ elif module == 'sklearn.tree._tree':
45
+ module = 'sklearn.tree'
46
+ return super().find_class(module, name)
47
+
48
+ with open('diabetes_model.pkl', 'rb') as f:
49
+ model = CustomUnpickler(f).load()
50
+
51
+ with open('scaler.pkl', 'rb') as f:
52
+ scaler = CustomUnpickler(f).load()
53
+
54
+ print("✓ Model and scaler loaded with custom unpickler")
55
+ return True
56
+ except Exception as e:
57
+ print(f"Custom unpickler failed: {e}")
58
+
59
+ # Method 3: Try standard pickle
60
+ try:
61
+ print("Trying standard pickle...")
62
+ with open('diabetes_model.pkl', 'rb') as f:
63
+ model = pickle.load(f)
64
+ with open('scaler.pkl', 'rb') as f:
65
+ scaler = pickle.load(f)
66
+ print("✓ Model and scaler loaded with standard pickle")
67
+ return True
68
+ except Exception as e:
69
+ print(f"Standard pickle failed: {e}")
70
+ return False
71
+
72
+ @asynccontextmanager
73
+ async def lifespan(app: FastAPI):
74
+ # Startup
75
+ print("Starting up...")
76
+
77
+ # Load model
78
+ success = load_model_with_fallback()
79
+ if not success:
80
+ print("WARNING: Could not load model. Running in demo mode.")
81
+ print("Creating dummy model for testing...")
82
+
83
+ # Create a simple logistic regression model for demo
84
+ from sklearn.linear_model import LogisticRegression
85
+ global model, scaler
86
+
87
+ # Create dummy scaler
88
+ from sklearn.preprocessing import StandardScaler
89
+ scaler = StandardScaler()
90
+ scaler.fit(np.random.randn(10, 8)) # Fit with dummy data
91
+
92
+ # Create dummy model
93
+ model = LogisticRegression()
94
+ X_dummy = np.random.randn(100, 8)
95
+ y_dummy = np.random.randint(0, 2, 100)
96
+ model.fit(X_dummy, y_dummy)
97
+ print("✓ Created demo model")
98
+
99
+ yield
100
+
101
+ # Shutdown (optional cleanup)
102
+ print("Shutting down...")
103
+
104
+ app = FastAPI(
105
+ title="Diabetes Prediction API",
106
+ description="API for early diabetes prediction",
107
+ version="1.0.0",
108
+ lifespan=lifespan
109
+ )
110
+
111
+ # Add CORS middleware
112
+ app.add_middleware(
113
+ CORSMiddleware,
114
+ allow_origins=["*"],
115
+ allow_credentials=True,
116
+ allow_methods=["*"],
117
+ allow_headers=["*"],
118
+ )
119
+
120
+ class DiabetesFeatures(BaseModel):
121
+ Pregnancies: float
122
+ Glucose: float
123
+ BloodPressure: float
124
+ SkinThickness: float
125
+ Insulin: float
126
+ BMI: float
127
+ DiabetesPedigreeFunction: float
128
+ Age: float
129
+
130
+ class PredictionResponse(BaseModel):
131
+ prediction: int
132
+ probability: float
133
+ message: str
134
+ risk_level: str
135
+ demo_mode: bool = False
136
+
137
+ @app.get("/")
138
+ async def home():
139
+ demo_mode = model is None or "demo" in str(type(model)).lower()
140
+ return {
141
+ "message": "Diabetes Prediction API",
142
+ "status": "active",
143
+ "model_loaded": model is not None,
144
+ "scaler_loaded": scaler is not None,
145
+ "demo_mode": demo_mode,
146
+ "endpoints": {
147
+ "GET /": "This info",
148
+ "GET /health": "Health check",
149
+ "GET /features": "List of required features",
150
+ "POST /predict": "Single prediction",
151
+ "GET /test": "Test endpoint"
152
+ }
153
+ }
154
+
155
+ @app.get("/health")
156
+ async def health_check():
157
+ demo_mode = model is None or "demo" in str(type(model)).lower()
158
+ return {
159
+ "status": "healthy",
160
+ "model_loaded": model is not None,
161
+ "scaler_loaded": scaler is not None,
162
+ "demo_mode": demo_mode
163
+ }
164
+
165
+ @app.get("/features")
166
+ async def get_features():
167
+ return {
168
+ "features": [
169
+ {"name": "Pregnancies", "type": "float", "description": "Number of times pregnant"},
170
+ {"name": "Glucose", "type": "float", "description": "Plasma glucose concentration"},
171
+ {"name": "BloodPressure", "type": "float", "description": "Diastolic blood pressure (mm Hg)"},
172
+ {"name": "SkinThickness", "type": "float", "description": "Triceps skin fold thickness (mm)"},
173
+ {"name": "Insulin", "type": "float", "description": "2-Hour serum insulin (mu U/ml)"},
174
+ {"name": "BMI", "type": "float", "description": "Body mass index (kg/m²)"},
175
+ {"name": "DiabetesPedigreeFunction", "type": "float", "description": "Diabetes pedigree function"},
176
+ {"name": "Age", "type": "float", "description": "Age (years)"}
177
+ ]
178
+ }
179
+
180
+ @app.get("/test")
181
+ async def test_endpoint():
182
+ """Simple test endpoint"""
183
+ demo_mode = model is None or "demo" in str(type(model)).lower()
184
+ return {
185
+ "status": "ok",
186
+ "message": "API is working",
187
+ "demo_mode": demo_mode,
188
+ "test_data": {
189
+ "Pregnancies": 2,
190
+ "Glucose": 148,
191
+ "BloodPressure": 72,
192
+ "SkinThickness": 35,
193
+ "Insulin": 0,
194
+ "BMI": 33.6,
195
+ "DiabetesPedigreeFunction": 0.627,
196
+ "Age": 50
197
+ }
198
+ }
199
+
200
+ @app.post("/predict", response_model=PredictionResponse)
201
+ async def predict(features: DiabetesFeatures):
202
+ demo_mode = model is None or "demo" in str(type(model)).lower()
203
+
204
+ if model is None or scaler is None:
205
+ raise HTTPException(status_code=503, detail="Model not available")
206
+
207
+ try:
208
+ # Convert input to array
209
+ input_data = np.array([[
210
+ features.Pregnancies,
211
+ features.Glucose,
212
+ features.BloodPressure,
213
+ features.SkinThickness,
214
+ features.Insulin,
215
+ features.BMI,
216
+ features.DiabetesPedigreeFunction,
217
+ features.Age
218
+ ]], dtype=np.float64)
219
+
220
+ # Scale the data
221
+ if hasattr(scaler, 'transform'):
222
+ scaled_data = scaler.transform(input_data)
223
+ else:
224
+ scaled_data = input_data
225
+
226
+ # Make prediction
227
+ if hasattr(model, 'predict'):
228
+ prediction = model.predict(scaled_data)[0]
229
+ else:
230
+ # Simple rule-based fallback
231
+ prediction = 1 if features.Glucose > 140 else 0
232
+
233
+ # Get probability
234
+ probability = 0.5
235
+ if hasattr(model, 'predict_proba'):
236
+ probability = float(model.predict_proba(scaled_data)[0][1])
237
+ elif hasattr(model, 'decision_function'):
238
+ try:
239
+ score = model.decision_function(scaled_data)[0]
240
+ probability = 1 / (1 + np.exp(-score))
241
+ except:
242
+ probability = 0.5
243
+ else:
244
+ # Estimate probability based on glucose level
245
+ probability = min(0.95, max(0.05, features.Glucose / 200))
246
+
247
+ # Determine risk level
248
+ if probability >= 0.7:
249
+ risk_level = "High"
250
+ elif probability >= 0.4:
251
+ risk_level = "Medium"
252
+ else:
253
+ risk_level = "Low"
254
+
255
+ return PredictionResponse(
256
+ prediction=int(prediction),
257
+ probability=float(probability),
258
+ message="Diabetic" if prediction == 1 else "Non-Diabetic",
259
+ risk_level=risk_level,
260
+ demo_mode=demo_mode
261
+ )
262
+
263
+ except Exception as e:
264
+ print(f"Prediction error: {e}")
265
+ traceback.print_exc()
266
+ raise HTTPException(status_code=400, detail=f"Prediction failed: {str(e)}")
267
+
268
+ @app.post("/predict_simple")
269
+ async def predict_simple(data: dict):
270
+ """Simplified endpoint that accepts any format"""
271
+ demo_mode = model is None or "demo" in str(type(model)).lower()
272
+
273
+ try:
274
+ # Extract features with flexible keys
275
+ features_map = {
276
+ 'Pregnancies': ['pregnancies', 'Pregnancies', 'preg'],
277
+ 'Glucose': ['glucose', 'Glucose', 'gluc'],
278
+ 'BloodPressure': ['blood_pressure', 'BloodPressure', 'bp', 'BP'],
279
+ 'SkinThickness': ['skin_thickness', 'SkinThickness', 'skin'],
280
+ 'Insulin': ['insulin', 'Insulin', 'ins'],
281
+ 'BMI': ['bmi', 'BMI'],
282
+ 'DiabetesPedigreeFunction': ['diabetes_pedigree', 'DiabetesPedigreeFunction', 'pedigree', 'dpf'],
283
+ 'Age': ['age', 'Age']
284
+ }
285
+
286
+ features_list = []
287
+ for feature_name, possible_keys in features_map.items():
288
+ value = 0
289
+ for key in possible_keys:
290
+ if key in data:
291
+ value = float(data[key])
292
+ break
293
+ features_list.append(value)
294
+
295
+ input_data = np.array([features_list], dtype=np.float64)
296
+
297
+ if scaler and hasattr(scaler, 'transform'):
298
+ scaled_data = scaler.transform(input_data)
299
+ else:
300
+ scaled_data = input_data
301
+
302
+ if model and hasattr(model, 'predict'):
303
+ prediction = model.predict(scaled_data)[0]
304
+ else:
305
+ prediction = 1 if features_list[1] > 140 else 0 # Based on glucose
306
+
307
+ probability = 0.5
308
+ if model and hasattr(model, 'predict_proba'):
309
+ probability = float(model.predict_proba(scaled_data)[0][1])
310
+
311
+ return {
312
+ "success": True,
313
+ "prediction": int(prediction),
314
+ "probability": float(probability),
315
+ "message": "Diabetic" if prediction == 1 else "Non-Diabetic",
316
+ "demo_mode": demo_mode,
317
+ "features_used": features_list
318
+ }
319
+
320
+ except Exception as e:
321
+ return {
322
+ "success": False,
323
+ "error": str(e),
324
+ "demo_mode": demo_mode
325
+ }
326
+
327
+ if __name__ == "__main__":
328
+ import uvicorn
329
+ uvicorn.run(app, host="0.0.0.0", port=7860)
app_gradio.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import gradio as gr
3
+ import pickle
4
+ import os
5
+
6
+ # Try to load model, fallback to dummy if fails
7
+ def load_or_create_model():
8
+ try:
9
+ if os.path.exists('diabetes_model.pkl'):
10
+ with open('diabetes_model.pkl', 'rb') as f:
11
+ model = pickle.load(f)
12
+ with open('scaler.pkl', 'rb') as f:
13
+ scaler = pickle.load(f)
14
+ print("✓ Loaded trained model")
15
+ return model, scaler, False
16
+ except:
17
+ print("⚠ Could not load model, using demo mode")
18
+
19
+ # Create simple rule-based model
20
+ class SimpleModel:
21
+ def predict(self, X):
22
+ # Simple rule: glucose > 140 = diabetic
23
+ return [1 if x[1] > 140 else 0 for x in X]
24
+ def predict_proba(self, X):
25
+ probs = []
26
+ for x in X:
27
+ glucose = x[1]
28
+ prob_diabetic = min(0.95, max(0.05, glucose / 200))
29
+ probs.append([1 - prob_diabetic, prob_diabetic])
30
+ return probs
31
+
32
+ class SimpleScaler:
33
+ def transform(self, X):
34
+ return X
35
+
36
+ return SimpleModel(), SimpleScaler(), True
37
+
38
+ model, scaler, is_demo = load_or_create_model()
39
+
40
+ def predict(pregnancies, glucose, bp, skin, insulin, bmi, pedigree, age):
41
+ try:
42
+ input_data = np.array([[pregnancies, glucose, bp, skin, insulin, bmi, pedigree, age]])
43
+
44
+ # Scale
45
+ if hasattr(scaler, 'transform'):
46
+ input_data = scaler.transform(input_data)
47
+
48
+ # Predict
49
+ prediction = model.predict(input_data)[0]
50
+
51
+ # Get probability
52
+ if hasattr(model, 'predict_proba'):
53
+ proba = model.predict_proba(input_data)[0]
54
+ confidence = proba[1] if prediction == 1 else proba[0]
55
+ else:
56
+ confidence = 0.5
57
+
58
+ result = "Diabetic" if prediction == 1 else "Non-Diabetic"
59
+ risk = "High" if confidence > 0.7 else "Medium" if confidence > 0.4 else "Low"
60
+
61
+ return {
62
+ "result": result,
63
+ "confidence": f"{confidence * 100:.1f}%",
64
+ "risk_level": risk,
65
+ "demo_mode": is_demo,
66
+ "glucose_status": "High" if glucose > 140 else "Normal" if glucose > 70 else "Low"
67
+ }
68
+ except Exception as e:
69
+ return {"error": str(e)}
70
+
71
+ # Create Gradio interface
72
+ iface = gr.Interface(
73
+ fn=predict,
74
+ inputs=[
75
+ gr.Number(label="Pregnancies", value=2),
76
+ gr.Number(label="Glucose (mg/dL)", value=148),
77
+ gr.Number(label="Blood Pressure (mmHg)", value=72),
78
+ gr.Number(label="Skin Thickness (mm)", value=35),
79
+ gr.Number(label="Insulin (mu U/ml)", value=0),
80
+ gr.Number(label="BMI (kg/m²)", value=33.6),
81
+ gr.Number(label="Diabetes Pedigree", value=0.627),
82
+ gr.Number(label="Age (years)", value=50)
83
+ ],
84
+ outputs=gr.JSON(label="Prediction Result"),
85
+ title="Diabetes Risk Predictor",
86
+ description="Enter health metrics to assess diabetes risk",
87
+ examples=[
88
+ [2, 148, 72, 35, 0, 33.6, 0.627, 50],
89
+ [1, 85, 66, 29, 0, 26.6, 0.351, 31],
90
+ [5, 116, 74, 0, 0, 25.6, 0.201, 30]
91
+ ],
92
+ theme="soft"
93
+ )
94
+
95
+ if __name__ == "__main__":
96
+ iface.launch(server_name="0.0.0.0", server_port=7860)
diabetes_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3f697fe210ee5bc5907e10f03ec13a084a6e69187ac15d82e6a455e0343d68b6
3
+ size 1127
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn[standard]==0.24.0
3
+ pydantic==2.5.0
4
+ numpy==1.24.3
5
+ scikit-learn==1.3.2
6
+ joblib==1.3.2
7
+ gradio==4.24.0
8
+ numpy==1.24.3
scaler.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e6d4b82ba818bb9a0f1d2e939c36ca625f46e74bd112b9486a84501a6c956afb
3
+ size 1359