FatimahEmadEldin commited on
Commit
3b84a2a
·
verified ·
1 Parent(s): b49cc6f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -78
app.py CHANGED
@@ -10,59 +10,46 @@ warnings.filterwarnings("ignore")
10
  # ===================================================================
11
  # 1. LOAD THE TRAINED MODEL
12
  # ===================================================================
13
- # Make sure your trained model file is in the same directory
14
  MODEL_PATH = "glucose_predictor_model.pkl"
15
  try:
16
  with open(MODEL_PATH, 'rb') as file:
17
  model = pickle.load(file)
18
  print("✅ Model loaded successfully!")
19
  except FileNotFoundError:
20
- print(f"❌ CRITICAL ERROR: Model file '{MODEL_PATH}' not found. Please upload it to your Hugging Face Space.")
21
  model = None
22
 
23
  # ===================================================================
24
- # 2. SIMULATION AND PREDICTION LOGIC
25
  # ===================================================================
26
 
27
- def predict_glucose(current_glucose):
28
  """
29
- This is the core function. It takes only the current glucose, simulates
30
- all other features, and returns the model's prediction.
31
  """
32
  if model is None:
33
- return "Model not loaded. Check file path.", "Error: Model file not found."
34
 
35
- # --- a) Simulate Demographics ---
36
- # Randomly select a gender and a realistic HbA1c value
37
- simulated_gender = np.random.choice(["Male", "Female"])
38
- simulated_hba1c = np.round(np.random.uniform(5.5, 9.0), 1)
39
-
40
- # --- b) Simulate a realistic 1-hour glucose history ---
41
- history_size = 12 # 60 minutes of 5-min readings
42
- trend = np.random.uniform(-2, 2) # Simulate a slight trend
43
  noise = np.random.normal(0, 3, history_size)
44
  glucose_history = np.linspace(current_glucose - trend * history_size, current_glucose, history_size) + noise
45
  glucose_history = np.round(glucose_history).astype(int)
46
 
47
- # --- c) Simulate realistic wearable data ---
48
- hr_mean = np.random.uniform(60, 90)
49
  hr_std = np.random.uniform(2, 8)
50
- temp_mean = np.random.uniform(32.0, 35.5)
51
  temp_std = np.random.uniform(0.05, 0.25)
52
- acc_x_mean = np.random.uniform(-35, -5)
53
- acc_y_mean = np.random.uniform(5, 35)
54
- acc_z_mean = np.random.uniform(25, 55)
55
  acc_std = np.random.uniform(1.0, 4.0)
56
- hrv_rmssd = np.random.uniform(25, 60) # Typical RMSSD values in ms
57
 
58
- # --- d) Assemble all features into a dictionary ---
59
  features = {
60
- 'glucose': current_glucose,
61
- 'hr_mean_5min': hr_mean, 'hr_std_5min': hr_std,
62
  'temp_mean_5min': temp_mean, 'temp_std_5min': temp_std,
63
- 'acc_x_mean_5min': acc_x_mean, 'acc_x_std_5min': acc_std,
64
- 'acc_y_mean_5min': acc_y_mean, 'acc_y_std_5min': acc_std,
65
- 'acc_z_mean_5min': acc_z_mean, 'acc_z_std_5min': acc_std,
66
  'glucose_lag_5min': glucose_history[-2], 'glucose_lag_15min': glucose_history[-4],
67
  'glucose_lag_30min': glucose_history[-7], 'glucose_lag_60min': glucose_history[0],
68
  'glucose_rolling_mean_15min': np.mean(glucose_history[-3:]),
@@ -72,83 +59,98 @@ def predict_glucose(current_glucose):
72
  'glucose_rolling_mean_60min': np.mean(glucose_history),
73
  'glucose_rolling_std_60min': np.std(glucose_history),
74
  'glucose_roc': current_glucose - glucose_history[-2],
75
- 'hba1c': simulated_hba1c,
76
- 'gender_is_female': 1 if simulated_gender == "Female" else 0,
77
  'hrv_rmssd_5min': hrv_rmssd
78
  }
79
 
80
- # --- e) Create the final DataFrame for prediction ---
81
- # The order of columns MUST match the order used during training.
82
- # It's robust to use the model's expected feature names if available.
83
  try:
84
  feature_order = model.get_booster().feature_names
85
- except AttributeError: # Fallback for some model versions
86
- feature_order = list(X.columns) # Assumes X is defined from training script
 
87
 
88
  input_df = pd.DataFrame([features])[feature_order]
89
 
90
- # --- f) Make Prediction ---
91
  prediction = model.predict(input_df)[0]
92
-
93
- # --- g) Format the output for display ---
94
- prediction_text = f"{prediction:.0f} mg/dL"
95
- status_text = (
96
- f"Simulated Inputs:\n"
97
- f" - Gender: {simulated_gender}, HbA1c: {simulated_hba1c}%\n"
98
- f" - Heart Rate: {hr_mean:.1f} bpm, HRV (RMSSD): {hrv_rmssd:.1f} ms\n"
99
- f" - Recent Trend (ROC): {features['glucose_roc']} mg/dL/5min"
100
- )
101
-
102
- return prediction_text, status_text
103
 
104
- def generate_sample_input():
105
- """Generates a random glucose value to populate the input slider."""
106
- return np.random.randint(90, 180)
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  # ===================================================================
109
- # 3. CREATE THE GRADIO INTERFACE
110
  # ===================================================================
111
 
112
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky")) as demo:
113
  gr.Markdown(
114
  """
115
  # 🩸 Glucose Guardian: AI-Powered 30-Minute Prediction
116
- This is a simulation of the AI model we trained. Enter a **current glucose** value to see the model's 30-minute forecast.
117
- The model automatically simulates other sensor and demographic data to make its prediction.
118
  """
119
  )
120
-
121
  with gr.Row():
 
122
  with gr.Column(scale=1):
123
- gr.Markdown("### CGM Input")
124
- glucose_input = gr.Slider(
125
- label="Current Glucose Level (mg/dL)",
126
- minimum=40, maximum=400, step=1, value=125
127
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
- with gr.Row():
130
- sample_btn = gr.Button("Generate Sample Input")
131
- predict_btn = gr.Button("Predict Future Glucose", variant="primary")
132
 
133
- with gr.Column(scale=2):
134
- gr.Markdown("### 🔮 AI Forecast & Simulated Data")
135
- prediction_output = gr.Textbox(label="Predicted Glucose in 30 Minutes", interactive=False)
136
- status_output = gr.Textbox(label="Automatically Simulated Data (for this prediction)", interactive=False, lines=4)
137
 
138
- # --- Link buttons to functions ---
139
- sample_btn.click(
140
- fn=generate_sample_input,
141
- inputs=[],
142
- outputs=[glucose_input]
143
- )
144
  predict_btn.click(
145
  fn=predict_glucose,
146
- inputs=[glucose_input],
147
- outputs=[prediction_output, status_output]
 
 
 
 
 
 
148
  )
149
-
150
- gr.Markdown("---")
151
- gr.Markdown("*Medical Disclaimer: This is a research project and is **NOT** an approved medical device. Predictions are for educational and demonstrational purposes only and should not be used for medical decisions.*")
152
 
153
  # Launch the app
154
  if __name__ == "__main__":
 
10
  # ===================================================================
11
  # 1. LOAD THE TRAINED MODEL
12
  # ===================================================================
 
13
  MODEL_PATH = "glucose_predictor_model.pkl"
14
  try:
15
  with open(MODEL_PATH, 'rb') as file:
16
  model = pickle.load(file)
17
  print("✅ Model loaded successfully!")
18
  except FileNotFoundError:
19
+ print(f"❌ CRITICAL ERROR: Model file '{MODEL_PATH}' not found.")
20
  model = None
21
 
22
  # ===================================================================
23
+ # 2. CORE PREDICTION LOGIC
24
  # ===================================================================
25
 
26
+ def predict_glucose(current_glucose, hba1c, gender, hr_mean, hrv_rmssd, temp_mean):
27
  """
28
+ This is the core prediction engine. It takes the primary inputs from the UI,
29
+ simulates the rest, engineers all features, and returns a prediction.
30
  """
31
  if model is None:
32
+ return "Model not loaded. Check file path."
33
 
34
+ # --- a) Simulate a realistic 1-hour glucose history ---
35
+ history_size = 12
36
+ trend = np.random.uniform(-2, 2)
 
 
 
 
 
37
  noise = np.random.normal(0, 3, history_size)
38
  glucose_history = np.linspace(current_glucose - trend * history_size, current_glucose, history_size) + noise
39
  glucose_history = np.round(glucose_history).astype(int)
40
 
41
+ # --- b) Simulate the standard deviations and accelerometer data ---
 
42
  hr_std = np.random.uniform(2, 8)
 
43
  temp_std = np.random.uniform(0.05, 0.25)
44
+ acc_x_mean, acc_y_mean, acc_z_mean = np.random.uniform(-35, -5), np.random.uniform(5, 35), np.random.uniform(25, 55)
 
 
45
  acc_std = np.random.uniform(1.0, 4.0)
 
46
 
47
+ # --- c) Assemble all features into a dictionary ---
48
  features = {
49
+ 'glucose': current_glucose, 'hr_mean_5min': hr_mean, 'hr_std_5min': hr_std,
 
50
  'temp_mean_5min': temp_mean, 'temp_std_5min': temp_std,
51
+ 'acc_x_mean_5min': acc_x_mean, 'acc_x_std_5min': acc_std, 'acc_y_mean_5min': acc_y_mean,
52
+ 'acc_y_std_5min': acc_std, 'acc_z_mean_5min': acc_z_mean, 'acc_z_std_5min': acc_std,
 
53
  'glucose_lag_5min': glucose_history[-2], 'glucose_lag_15min': glucose_history[-4],
54
  'glucose_lag_30min': glucose_history[-7], 'glucose_lag_60min': glucose_history[0],
55
  'glucose_rolling_mean_15min': np.mean(glucose_history[-3:]),
 
59
  'glucose_rolling_mean_60min': np.mean(glucose_history),
60
  'glucose_rolling_std_60min': np.std(glucose_history),
61
  'glucose_roc': current_glucose - glucose_history[-2],
62
+ 'hba1c': hba1c, 'gender_is_female': 1 if gender == "Female" else 0,
 
63
  'hrv_rmssd_5min': hrv_rmssd
64
  }
65
 
66
+ # --- d) Create the final DataFrame for prediction ---
 
 
67
  try:
68
  feature_order = model.get_booster().feature_names
69
+ except AttributeError:
70
+ # Fallback if the feature names aren't in the model object
71
+ feature_order = ['glucose', 'hr_mean_5min', 'hr_std_5min', 'temp_mean_5min', 'temp_std_5min', 'acc_x_mean_5min', 'acc_x_std_5min', 'acc_y_mean_5min', 'acc_y_std_5min', 'acc_z_mean_5min', 'acc_z_std_5min', 'glucose_lag_5min', 'glucose_lag_15min', 'glucose_lag_30min', 'glucose_lag_60min', 'glucose_rolling_mean_15min', 'glucose_rolling_std_15min', 'glucose_rolling_mean_30min', 'glucose_rolling_std_30min', 'glucose_rolling_mean_60min', 'glucose_rolling_std_60min', 'glucose_roc', 'hba1c', 'gender_is_female', 'hrv_rmssd_5min']
72
 
73
  input_df = pd.DataFrame([features])[feature_order]
74
 
75
+ # --- e) Make Prediction ---
76
  prediction = model.predict(input_df)[0]
77
+ return f"{prediction:.0f} mg/dL"
78
+
79
+ # ===================================================================
80
+ # 3. RANDOM SCENARIO GENERATOR
81
+ # ===================================================================
 
 
 
 
 
 
82
 
83
+ def generate_random_scenario_and_predict():
84
+ """Generates random values for all inputs and triggers a prediction."""
85
+ # Generate random values
86
+ random_glucose = np.random.randint(70, 250)
87
+ random_hba1c = np.round(np.random.uniform(5.5, 10.0), 1)
88
+ random_gender = np.random.choice(["Male", "Female"])
89
+ random_hr = np.random.randint(60, 100)
90
+ random_hrv = np.random.randint(20, 70)
91
+ random_temp = np.round(np.random.uniform(32.0, 36.0), 1)
92
+
93
+ # Get a prediction based on these random values
94
+ prediction = predict_glucose(random_glucose, random_hba1c, random_gender, random_hr, random_hrv, random_temp)
95
+
96
+ # Return all the generated values to update the UI
97
+ return random_glucose, random_hba1c, random_gender, random_hr, random_hrv, random_temp, prediction
98
 
99
  # ===================================================================
100
+ # 4. CREATE THE GRADIO INTERFACE
101
  # ===================================================================
102
 
103
+ with gr.Blocks(theme=gr.themes.Monochrome()) as demo:
104
  gr.Markdown(
105
  """
106
  # 🩸 Glucose Guardian: AI-Powered 30-Minute Prediction
107
+ A simulation of an AI model that predicts future glucose levels. You can either adjust the sliders yourself
108
+ or click the "Generate Random Vitals" button to create a new scenario.
109
  """
110
  )
111
+
112
  with gr.Row():
113
+ # --- INPUTS COLUMN ---
114
  with gr.Column(scale=1):
115
+ with gr.Group():
116
+ gr.Markdown("### CGM Input")
117
+ glucose_input = gr.Slider(label="Current Glucose (mg/dL)", minimum=40, maximum=400, step=1, value=125)
118
+
119
+ with gr.Group():
120
+ gr.Markdown("### 👤 Demographics")
121
+ gender_input = gr.Radio(label="Gender", choices=["Male", "Female"], value="Female")
122
+ hba1c_input = gr.Slider(label="HbA1c (%)", minimum=5.0, maximum=12.0, step=0.1, value=6.5)
123
+
124
+ with gr.Group():
125
+ gr.Markdown("### ⌚ Wearable Vitals (Simulated)")
126
+ hr_input = gr.Slider(label="❤️ Heart Rate (bpm)", minimum=50, maximum=160, step=1, value=75)
127
+ hrv_input = gr.Slider(label="🧬 HRV - RMSSD (ms)", minimum=10, maximum=120, step=1, value=45)
128
+ temp_input = gr.Slider(label="🌡️ Skin Temperature (°C)", minimum=30.0, maximum=38.0, step=0.1, value=34.5)
129
+
130
+ # --- OUTPUTS AND BUTTONS COLUMN ---
131
+ with gr.Column(scale=2):
132
+ gr.Markdown("### 🔮 AI Forecast")
133
+ prediction_output = gr.Textbox(label="Predicted Glucose in 30 Minutes", interactive=False, elem_id="prediction_textbox")
134
 
135
+ predict_btn = gr.Button("🔮 Predict Future Glucose (from sliders)", variant="primary")
136
+ random_btn = gr.Button("🎲 Generate Random Vitals & Predict")
 
137
 
138
+ gr.Markdown("---")
139
+ gr.Markdown("*Medical Disclaimer: This is a research project and is **NOT** an approved medical device. Predictions are for educational and demonstrational purposes only.*")
 
 
140
 
141
+
142
+ # --- Link UI components to functions ---
 
 
 
 
143
  predict_btn.click(
144
  fn=predict_glucose,
145
+ inputs=[glucose_input, hba1c_input, gender_input, hr_input, hrv_input, temp_input],
146
+ outputs=[prediction_output]
147
+ )
148
+
149
+ random_btn.click(
150
+ fn=generate_random_scenario_and_predict,
151
+ inputs=[],
152
+ outputs=[glucose_input, hba1c_input, gender_input, hr_input, hrv_input, temp_input, prediction_output]
153
  )
 
 
 
154
 
155
  # Launch the app
156
  if __name__ == "__main__":