import gradio as gr import json from fastapi import FastAPI import uvicorn import pickle import numpy as np import pandas as pd from typing import Dict, List, Optional import os app = FastAPI() class DiabetesPredictor: def __init__(self, model_path: str = "diabetes_model.pkl", scaler_path: str = "scaler.pkl"): """ Initialize the diabetes predictor with model and scaler. Args: model_path: Path to the trained model .pkl file scaler_path: Path to the scaler .pkl file """ self.model = None self.scaler = None self.feature_names = None # Try to load the model try: if os.path.exists(model_path): with open(model_path, 'rb') as f: self.model = pickle.load(f) print(f"✓ Model loaded successfully from {model_path}") else: print(f"⚠ Warning: Model file not found at {model_path}") except Exception as e: print(f"✗ Error loading model: {e}") # Try to load the scaler try: if os.path.exists(scaler_path): with open(scaler_path, 'rb') as f: self.scaler = pickle.load(f) print(f"✓ Scaler loaded successfully from {scaler_path}") else: print(f"⚠ Warning: Scaler file not found at {scaler_path}") except Exception as e: print(f"✗ Error loading scaler: {e}") def prepare_features(self, data: Dict) -> np.ndarray: """ Prepare input features for prediction. Expected features in order: - Pregnancies - Glucose - BloodPressure - SkinThickness - Insulin - BMI - DiabetesPedigreeFunction - Age """ try: # Extract features from input data # If your model expects different features, modify this mapping features = [ data.get("pregnancies", 0), # Usually needed for diabetes prediction data.get("glucose", 100.0), data.get("blood_pressure", 120.0), data.get("skin_thickness", 20.0), # Common diabetes dataset feature data.get("insulin", 15.0), data.get("bmi", 25.0), data.get("diabetes_pedigree", 0.5), # Common diabetes dataset feature data.get("age", 30) ] return np.array(features).reshape(1, -1) except Exception as e: print(f"Error preparing features: {e}") return None def predict(self, data: Dict) -> Dict: """ Make prediction using the loaded model. """ if self.model is None: return { "success": False, "error": "Model not loaded. Using fallback prediction.", "fallback_used": True, "risk_score": self.fallback_prediction(data) } try: # Prepare features features = self.prepare_features(data) if features is None: raise ValueError("Could not prepare features") # Scale features if scaler is available if self.scaler is not None: features = self.scaler.transform(features) # Make prediction prediction = self.model.predict(features)[0] prediction_proba = self.model.predict_proba(features)[0] # Get probability for positive class (diabetes) # Assuming class 1 is diabetes risk_score = float(prediction_proba[1] * 100) if len(prediction_proba) > 1 else float(prediction * 100) is_high_risk = prediction == 1 or risk_score >= 50 return { "success": True, "model_used": True, "prediction": int(prediction), "risk_score": risk_score, "is_high_risk": bool(is_high_risk), "risk_level": "High Risk" if is_high_risk else "Low Risk", "confidence": float(max(prediction_proba) * 100) if len(prediction_proba) > 1 else None, "message": self.get_recommendation(is_high_risk, risk_score) } except Exception as e: print(f"Prediction error: {e}") return { "success": False, "error": str(e), "fallback_used": True, "risk_score": self.fallback_prediction(data) } def fallback_prediction(self, data: Dict) -> float: """ Fallback prediction logic when model fails to load. This is your original logic. """ try: age = int(data.get("age", 30)) bmi = float(data.get("bmi", 25.0)) glucose = float(data.get("glucose", 100.0)) score = 0 if glucose > 140: score += 40 if bmi > 30: score += 20 if age > 45: score += 10 # Add symptoms if data.get("increased_thirst"): score += 10 if data.get("increased_hunger"): score += 5 if data.get("fatigue"): score += 5 if data.get("blurred_vision"): score += 10 if data.get("weight_loss"): score += 15 return min(score, 100) except: return 0.0 def get_recommendation(self, is_high_risk: bool, risk_score: float) -> str: """Generate recommendation based on risk level.""" if is_high_risk: if risk_score > 80: return "URGENT: Very high diabetes risk detected. Please consult a healthcare professional immediately." elif risk_score > 60: return "High diabetes risk detected. Schedule an appointment with your doctor soon." else: return "Moderate diabetes risk. Consider lifestyle changes and regular monitoring." else: if risk_score < 20: return "Low diabetes risk. Keep maintaining your healthy lifestyle!" else: return "Some risk factors present. Consider preventive measures and regular check-ups." # Initialize predictor predictor = DiabetesPredictor( model_path="diabetes_model.pkl", scaler_path="scaler.pkl" ) def calculate_diabetes_risk_api(data: dict) -> dict: """API endpoint for diabetes risk prediction using ML model.""" try: # Use the predictor result = predictor.predict(data) # If model prediction failed but we have fallback, format it if not result.get("success", False) and "fallback_used" in result: risk_score = result.get("risk_score", 0) is_high_risk = risk_score >= 50 return { "success": True, "model_used": False, "fallback_used": True, "risk_score": risk_score, "is_high_risk": is_high_risk, "risk_level": "High Risk" if is_high_risk else "Low Risk", "message": predictor.get_recommendation(is_high_risk, risk_score) } return result except Exception as e: return { "success": False, "error": str(e) } # Create a comprehensive Gradio interface with gr.Blocks( title="GlucoCheck AI - Diabetes Prediction", css=""" .gradio-container { max-width: 900px; margin: auto; } .header { text-align: center; margin-bottom: 30px; } .header h1 { color: #2E384D; font-size: 36px; margin-bottom: 10px; } .header p { color: #6B7280; font-size: 16px; } .metric-card { background: linear-gradient(135deg, #f8fafc, #f1f5f9); padding: 15px; border-radius: 10px; border: 1px solid #e2e8f0; margin-bottom: 10px; } .vital-metric { background: linear-gradient(135deg, #fef2f2, #fef7ed); padding: 20px; border-radius: 12px; border: 2px solid #fecaca; margin-bottom: 15px; } .result-high-risk { background: linear-gradient(135deg, #fef2f2, #fee2e2); border-left: 5px solid #EF4444; padding: 20px; border-radius: 10px; margin: 15px 0; } .result-low-risk { background: linear-gradient(135deg, #f0fdf4, #dcfce7); border-left: 5px solid #10B981; padding: 20px; border-radius: 10px; margin: 15px 0; } .analyze-btn { background: linear-gradient(135deg, #4361ee, #3a56d4); color: white; padding: 15px 30px; border-radius: 12px; font-weight: 600; font-size: 16px; border: none; margin-top: 20px; width: 100%; } .analyze-btn:hover { background: linear-gradient(135deg, #3a56d4, #304bc0); } .disclaimer { margin-top: 30px; padding-top: 20px; border-top: 1px solid #e2e8f0; color: #6B7280; font-size: 12px; text-align: center; } .model-status { padding: 10px; border-radius: 8px; margin: 10px 0; text-align: center; } .model-success { background: #10B98120; color: #10B981; border: 1px solid #10B981; } .model-warning { background: #F59E0B20; color: #F59E0B; border: 1px solid #F59E0B; } """ ) as demo: # Header gr.HTML("""
Advanced ML-based diabetes risk assessment using trained models
Risk Score: {risk_score:.1f}%
Confidence: {result.get('confidence', 'N/A')}%
Prediction: Diabetes likely present
Risk Score: {risk_score:.1f}%
Confidence: {result.get('confidence', 'N/A')}%
Prediction: Diabetes unlikely
{result.get('error', 'Unknown error occurred')}
Medical Disclaimer: This tool is for informational purposes only and is not a substitute for professional medical advice, diagnosis, or treatment.
Always seek the advice of your physician or other qualified health provider with any questions you may have regarding a medical condition.
Model file: {'Loaded' if predictor.model is not None else 'Not found'}