import gradio as gr import xgboost as xgb import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score, confusion_matrix import plotly.express as px import plotly.graph_objects as go import json class DiabetesGame: def __init__(self): self.data = self.load_data() self.model = self.train_model() self.user_score = 0 self.total_attempts = 0 self.tips_database = { "glucose": "Normal fasting blood glucose levels are less than 100 mg/dL. Levels between 100-125 mg/dL indicate prediabetes.", "bmi": "A BMI between 18.5 and 24.9 is considered healthy. BMI over 30 indicates obesity, a risk factor for diabetes.", "blood_pressure": "Normal blood pressure is usually below 120/80 mmHg. High blood pressure often co-occurs with diabetes.", "age": "Type 2 diabetes risk increases with age, particularly after 45 years.", "pregnancies": "Gestational diabetes during pregnancy increases future diabetes risk.", "lifestyle": "Regular exercise and a balanced diet can significantly reduce diabetes risk.", "family_history": "Having a parent or sibling with diabetes increases your risk.", "general": "Early detection and lifestyle changes can prevent or delay type 2 diabetes." } def load_data(self): return pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/diabetes.csv') def train_model(self): X = self.data.drop(columns=['Outcome']) y = self.data['Outcome'] X_train, _, y_train, _ = train_test_split(X, y, test_size=0.2, random_state=42) model = xgb.XGBClassifier( eval_metric='logloss', max_depth=6, learning_rate=0.1, n_estimators=100, random_state=42 ) model.fit(X_train, y_train) return model def create_radar_chart(self, values): categories = ['Pregnancies', 'Glucose', 'Blood Pressure', 'Skin Thickness', 'Insulin', 'BMI', 'Diabetes Pedigree', 'Age'] # Normalize values for radar chart max_values = [17, 200, 122, 99, 846, 67.1, 2.42, 81] normalized_values = [v/m for v, m in zip(values, max_values)] fig = go.Figure() fig.add_trace(go.Scatterpolar( r=normalized_values, theta=categories, fill='toself', name='Patient Values' )) fig.update_layout( polar=dict( radialaxis=dict( visible=True, range=[0, 1] )), showlegend=True, title="Patient Risk Factors Radar Chart" ) return fig def create_feature_importance_plot(self): importance_df = pd.DataFrame({ 'Feature': ['Pregnancies', 'Glucose', 'Blood Pressure', 'Skin Thickness', 'Insulin', 'BMI', 'Diabetes Pedigree', 'Age'], 'Importance': self.model.feature_importances_ }) importance_df = importance_df.sort_values('Importance', ascending=True) fig = px.bar(importance_df, x='Importance', y='Feature', orientation='h', title='Feature Importance in Diagnosis') fig.update_layout(height=400) return fig def get_relevant_tips(self, values): tips = [] # Add tips based on values if values[1] > 140: # High glucose tips.append(("⚠️ High Glucose", self.tips_database["glucose"])) if values[5] > 30: # High BMI tips.append(("⚠️ High BMI", self.tips_database["bmi"])) if values[2] > 90: # High blood pressure tips.append(("⚠️ High Blood Pressure", self.tips_database["blood_pressure"])) # Always add a random general tip general_tips = [self.tips_database["lifestyle"], self.tips_database["family_history"], self.tips_database["general"]] tips.append(("💡 Health Tip", np.random.choice(general_tips))) return "\n\n".join([f"{title}\n{content}" for title, content in tips]) def predict_and_play(self, pregnancies, glucose, blood_pressure, skin_thickness, insulin, bmi, diabetes_pedigree, age, user_diagnosis): values = [pregnancies, glucose, blood_pressure, skin_thickness, insulin, bmi, diabetes_pedigree, age] # Make prediction user_input = np.array(values).reshape(1, -1) prediction = self.model.predict(user_input)[0] probability = self.model.predict_proba(user_input)[0][1] * 100 # Update score self.total_attempts += 1 correct = (user_diagnosis == "Yes" and prediction == 1) or \ (user_diagnosis == "No" and prediction == 0) if correct: self.user_score += 1 # Create visualizations radar_chart = self.create_radar_chart(values) importance_plot = self.create_feature_importance_plot() # Generate result message accuracy = (self.user_score / self.total_attempts) * 100 if self.total_attempts > 0 else 0 result = f"""{'🎉 Correct!' if correct else '❌ Incorrect'}\n Model Prediction: {'Diabetes Risk Detected' if prediction == 1 else 'No Significant Risk'}\n Confidence: {probability:.1f}%\n Your Score: {self.user_score}/{self.total_attempts} ({accuracy:.1f}% accuracy) """ # Get relevant tips tips = self.get_relevant_tips(values) return result, radar_chart, importance_plot, tips # Initialize game game = DiabetesGame() # Create the interface with gr.Blocks(theme=gr.themes.Soft()) as interface: gr.Markdown(""" # 🏥 Interactive Diabetes Diagnosis Game Test your medical diagnosis skills! Analyze patient data and try to predict diabetes risk. Your score will be tracked as you play. ## How to Play: 1. Adjust the patient parameters using the sliders 2. Make your diagnosis (Yes/No for diabetes risk) 3. Submit to see if you matched the model's prediction 4. Learn from the visualizations and tips """) with gr.Row(): with gr.Column(): pregnancies = gr.Slider(0, 17, step=1, label="Pregnancies") glucose = gr.Slider(0, 200, value=120, step=1, label="Glucose Level") blood_pressure = gr.Slider(0, 122, value=70, step=1, label="Blood Pressure") skin_thickness = gr.Slider(0, 99, value=20, step=1, label="Skin Thickness") with gr.Column(): insulin = gr.Slider(0, 846, value=80, step=1, label="Insulin") bmi = gr.Slider(0.0, 67.1, value=25.0, step=0.1, label="BMI") diabetes_pedigree = gr.Slider(0.078, 2.42, value=0.5, step=0.001, label="Diabetes Pedigree") age = gr.Slider(21, 81, value=30, step=1, label="Age") diagnosis = gr.Radio(["Yes", "No"], label="Your Diagnosis", info="Do you think this patient has diabetes?") submit_btn = gr.Button("Submit Diagnosis", variant="primary") with gr.Row(): result_box = gr.Textbox(label="Game Result", lines=5) tips_box = gr.Textbox(label="Health Tips & Information", lines=5) with gr.Row(): radar_plot = gr.Plot(label="Patient Risk Factors") importance_plot = gr.Plot(label="Feature Importance") submit_btn.click( fn=game.predict_and_play, inputs=[pregnancies, glucose, blood_pressure, skin_thickness, insulin, bmi, diabetes_pedigree, age, diagnosis], outputs=[result_box, radar_plot, importance_plot, tips_box] ) gr.Markdown(""" ## 📚 About the Features - **Pregnancies**: Number of times pregnant - **Glucose**: Plasma glucose concentration (2 hours in an oral glucose tolerance test) - **Blood Pressure**: Diastolic blood pressure (mm Hg) - **Skin Thickness**: Triceps skin fold thickness (mm) - **Insulin**: 2-Hour serum insulin (mu U/ml) - **BMI**: Body mass index (weight in kg/(height in m)²) - **Diabetes Pedigree**: A function scoring likelihood of diabetes based on family history - **Age**: Age in years """) if __name__ == "__main__": interface.launch()