Anupam007 commited on
Commit
a4dfe81
·
verified ·
1 Parent(s): 3f1ae49

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +544 -0
app.py ADDED
@@ -0,0 +1,544 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import pandas as pd
4
+ import matplotlib.pyplot as plt
5
+ import torch
6
+ from transformers import AutoImageProcessor, AutoModelForImageClassification
7
+ from PIL import Image
8
+ from difflib import get_close_matches
9
+ from typing import Optional, Dict, Any
10
+ import json
11
+ import io
12
+ from datasets import load_dataset # Import the datasets library
13
+
14
+ # -------------------------------------------------
15
+ # Configuration
16
+ # -------------------------------------------------
17
+
18
+ # Define insulin types and their durations and peak times
19
+ INSULIN_TYPES = {
20
+ "Rapid-Acting": {"onset": 0.25, "duration": 4, "peak_time": 1.0}, # Onset in hours, duration in hours, peak time in hours
21
+ "Long-Acting": {"onset": 2, "duration": 24, "peak_time": 8},
22
+ }
23
+
24
+ #Define basal rates
25
+ DEFAULT_BASAL_RATES = {
26
+ "00:00-06:00": 0.8,
27
+ "06:00-12:00": 1.0,
28
+ "12:00-18:00": 0.9,
29
+ "18:00-24:00": 0.7
30
+ }
31
+
32
+ # -------------------------------------------------
33
+ # Load Food Data from Hugging Face Dataset
34
+ # -------------------------------------------------
35
+
36
+ def load_food_data(dataset_name="Anupam007/Diabetic"):
37
+ try:
38
+ dataset = load_dataset(dataset_name)
39
+ food_data = dataset['train'].to_pandas()
40
+
41
+ # Normalize column names to lowercase
42
+ food_data.columns = [col.lower() for col in food_data.columns]
43
+
44
+ # Remove unnamed columns
45
+ food_data = food_data.loc[:, ~food_data.columns.str.contains('^unnamed')]
46
+
47
+ # Normalize food_name column to lowercase: Crucial for matching
48
+ if 'food_name' in food_data.columns:
49
+ food_data['food_name'] = food_data['food_name'].str.lower()
50
+ print("Unique Food Names in Dataset:")
51
+ print(food_data['food_name'].unique())
52
+ else:
53
+ print("Warning: 'food_name' column not found in dataset.")
54
+ food_data = pd.DataFrame({
55
+ 'food_category': ['starch'],
56
+ 'food_subcategory': ['bread'],
57
+ 'food_name': ['white bread'],
58
+ 'serving_description': ['servingsize'],
59
+ 'serving_amount': [29],
60
+ 'serving_unit': ['g'],
61
+ 'carbohydrate_grams': [15],
62
+ 'notes': ['default']
63
+ })
64
+
65
+ #Print first 5 rows to check columns and values
66
+ print("First 5 rows of loaded data from Hugging Face Dataset:")
67
+ print(food_data.head())
68
+
69
+ return food_data
70
+
71
+ except Exception as e:
72
+ print(f"Error loading Hugging Face Dataset: {e}")
73
+ # Provide minimal default data in case of error
74
+ food_data = pd.DataFrame({
75
+ 'food_category': ['starch'],
76
+ 'food_subcategory': ['bread'],
77
+ 'food_name': ['white bread'], # lowercase default
78
+ 'serving_description': ['servingsize'],
79
+ 'serving_amount': [29],
80
+ 'serving_unit': ['g'],
81
+ 'carbohydrate_grams': [15],
82
+ 'notes': ['default']
83
+ })
84
+ return food_data
85
+
86
+ # -------------------------------------------------
87
+ # Load Food Classification Model
88
+ # -------------------------------------------------
89
+ try:
90
+ # Load model directly
91
+ from transformers import AutoImageProcessor, AutoModelForImageClassification
92
+
93
+ processor = AutoImageProcessor.from_pretrained("rajistics/finetuned-indian-food")
94
+ model = AutoModelForImageClassification.from_pretrained("rajistics/finetuned-indian-food")
95
+ model_loaded = True #Flag for error handling in other defs
96
+ except Exception as e:
97
+ print(f"Model Load Error: {e}") # include e in print statement
98
+ model_loaded = False
99
+ processor = None
100
+ model = None
101
+
102
+ def classify_food(image):
103
+
104
+ inputs = processor(images=image, return_tensors="pt")
105
+ print(f"Processed image keys: {inputs.keys()}") # Print the keys of the inputs dictionary
106
+ if 'pixel_values' in inputs:
107
+ print(f"Pixel values shape: {inputs['pixel_values'].shape}")
108
+ print(f"Pixel values type: {inputs['pixel_values'].dtype}")
109
+ print(f"First few pixel values: {inputs['pixel_values'][0, :5]}") # Print a small slice
110
+ else:
111
+ print("Pixel values not found in inputs!")
112
+
113
+ try:
114
+ if not model_loaded:
115
+ print("Model not loaded, returning 'Unknown'")
116
+ return "Unknown"
117
+
118
+ print(f"Image type: {type(image)}") # Check the type of the image
119
+
120
+ if isinstance(image, np.ndarray):
121
+ print("Image is a numpy array, converting to PIL Image")
122
+ image = Image.fromarray(image)
123
+
124
+ print(f"Image mode: {image.mode}") # Check image mode (e.g., RGB, L)
125
+
126
+ inputs = processor(images=image, return_tensors="pt")
127
+ print(f"Processed image: {inputs}") # Print the output of the processor
128
+
129
+ with torch.no_grad():
130
+ outputs = model(**inputs)
131
+ predicted_idx = torch.argmax(outputs.logits, dim=-1).item()
132
+ food_name = model.config.id2label.get(predicted_idx, "Unknown Food")
133
+ print(f"Predicted food name before lower: {food_name}")
134
+ food_name = food_name.lower() # Convert classification to lowercase
135
+ print(f"Predicted food name after lower: {food_name}") # Print the predicted food name
136
+ return food_name
137
+
138
+ except Exception as e:
139
+ print(f"Classify food error: {e}") # Print the full error message
140
+ return "Unknown" # If an exception arises make sure to create a default case
141
+
142
+ # -------------------------------------------------
143
+ # USDA API Integration - REMOVED for local HF Spaces deployment
144
+ # -------------------------------------------------
145
+
146
+ def get_food_nutrition(food_name: str, food_data, portion_size: float = 1.0) -> Optional[Dict[str, Any]]:
147
+ """Get carbohydrate content for the given food""" #No USDA anymore
148
+ print("get_food_nutrition function called") # Ensure the function is called
149
+ try:
150
+ # First try the local CSV database
151
+ food_name_lower = food_name.lower() # Ensure input is also lowercase
152
+ food_names = food_data['food_name'].str.lower().tolist() #Already lowercased during load
153
+
154
+ print(f"Searching for: {food_name_lower}") # Debugging: What are we searching for?
155
+ matches = get_close_matches(food_name_lower, food_names, n=1, cutoff=0.5)
156
+
157
+ print(f"Matches found: {matches}") # Debugging: See what matches are found
158
+
159
+ if matches:
160
+ # Use local database match
161
+ matched_row = food_data[food_data['food_name'].str.lower() == matches[0]]
162
+
163
+ if not matched_row.empty:
164
+ row = matched_row.iloc[0]
165
+
166
+ # Debugging: Print the entire row
167
+ print(f"Matched row from CSV: {row}")
168
+
169
+ # Explicitly check for column existence and valid data
170
+ carb_col = 'carbohydrate_grams'
171
+ amount_col = 'serving_amount'
172
+ unit_col = 'serving_unit'
173
+ if carb_col not in row or pd.isna(row[carb_col]):
174
+ print(f"Warning: '{carb_col}' is missing or NaN in CSV")
175
+ base_carbs = 0.0
176
+ else:
177
+ base_carbs = row[carb_col]
178
+ try:
179
+ base_carbs = float(base_carbs) # Ensure it's a float
180
+ except ValueError:
181
+ print(f"Warning: '{carb_col}' is not a valid number in CSV")
182
+ base_carbs = 0.0
183
+
184
+ if amount_col not in row or unit_col not in row or pd.isna(row[amount_col]) or pd.isna(row[unit_col]):
185
+ serving_size = "Unknown"
186
+ print(f"Warning: '{amount_col}' or '{unit_col}' is missing in CSV")
187
+ else:
188
+ serving_size = f"{row[amount_col]} {row[unit_col]}"
189
+
190
+ adjusted_carbs = base_carbs * portion_size
191
+
192
+ return {
193
+ 'matched_food': row['food_name'],
194
+ 'category': row['food_category'] if 'food_category' in row and not pd.isna(row['food_category']) else 'Unknown',
195
+ 'subcategory': row['food_subcategory'] if 'food_subcategory' in row and not pd.isna(row['food_subcategory']) else 'Unknown',
196
+ 'base_carbs': base_carbs,
197
+ 'adjusted_carbs': adjusted_carbs,
198
+ 'serving_size': serving_size,
199
+ 'portion_multiplier': portion_size,
200
+ 'notes': row['notes'] if 'notes' in row and not pd.isna(row['notes']) else ''
201
+ }
202
+
203
+ # If no match found in local database
204
+ print(f"No match found in CSV for {food_name}") # Debugging line
205
+ print(f"No nutrition information found for {food_name} in the local database.") # Debugging line
206
+ return None
207
+ except Exception as e:
208
+ print(f"Error in get_food_nutrition: {e}")
209
+ return None
210
+
211
+ # -------------------------------------------------
212
+ # Insulin and Glucose Calculations
213
+ # -------------------------------------------------
214
+ def get_basal_rate(current_time_hour, basal_rates):
215
+ """Gets the appropriate basal rate for a given time of day."""
216
+ for interval, rate in basal_rates.items():
217
+ try: # add a try and except to handle values in intervals that do not have the format "start-end"
218
+ parts = interval.split(":")[0].split("-")
219
+ if len(parts) == 2: # Check if there are two parts (start and end)
220
+ start_hour, end_hour = map(int, parts)
221
+ if start_hour <= current_time_hour < end_hour or (start_hour <= current_time_hour and end_hour == 24):
222
+ return rate
223
+ except Exception as e: # include exception in exception handling
224
+ print(f"Warning: Invalid interval format: {interval}. Skipping. Error: {e}") #Inform user of formatting issues
225
+
226
+ return 0 # Default if no matching interval
227
+
228
+ def insulin_activity(t, insulin_type, bolus_dose, bolus_duration=0):
229
+ """Models insulin activity over time."""
230
+ insulin_data = INSULIN_TYPES.get(insulin_type)
231
+ if not insulin_data:
232
+ return 0 # Or raise an error
233
+
234
+ # Simple exponential decay model (replace with a more sophisticated model)
235
+ peak_time = insulin_data['peak_time'] # Time in hours at which insulin activity is at max level
236
+ duration = insulin_data['duration'] # Total time for which insulin stays in effect
237
+ if t < peak_time:
238
+ activity = (bolus_dose * t / peak_time) * np.exp(1- t/peak_time) # rising activity
239
+ elif t < duration:
240
+ activity = bolus_dose * np.exp((peak_time - t) / (duration - peak_time)) # decaying activity
241
+ else:
242
+ activity = 0
243
+
244
+ if bolus_duration > 0: # Extended Bolus
245
+ if 0 <= t <= bolus_duration:
246
+ # Linear release of insulin over bolus_duration
247
+ effective_dose = bolus_dose / bolus_duration
248
+ duration = INSULIN_TYPES.get(insulin_type)['duration']
249
+ if t < duration:
250
+ activity = effective_dose
251
+ else:
252
+ activity = 0
253
+ else:
254
+ activity = 0
255
+
256
+ return activity
257
+
258
+ def calculate_active_insulin(insulin_history, current_time):
259
+ """Calculates remaining active insulin from previous doses."""
260
+ active_insulin = 0
261
+ for dose_time, dose_amount, insulin_type, bolus_duration in insulin_history:
262
+ elapsed_time = current_time - dose_time
263
+ remaining_activity = insulin_activity(elapsed_time, insulin_type, dose_amount, bolus_duration)
264
+ active_insulin += remaining_activity
265
+ return active_insulin
266
+
267
+ def calculate_insulin_needs(carbs, glucose_current, glucose_target, tdd, weight, insulin_type="Rapid-Acting", override_correction_dose = None):
268
+ """Calculate insulin needs for Type 1 diabetes"""
269
+ if tdd <= 0:
270
+ return {
271
+ 'error': 'Total Daily Dose (TDD) must be greater than 0'
272
+ }
273
+ insulin_data = INSULIN_TYPES.get(insulin_type)
274
+ if not insulin_data:
275
+ return {
276
+ 'error': "Invalid insulin type. Choose from" + ", ".join(INSULIN_TYPES.keys())
277
+ }
278
+
279
+ # Refined calculations
280
+ icr = (450 if weight <= 45 else 500) / tdd
281
+ isf = 1700 / tdd
282
+
283
+ # Calculate correction dose
284
+ glucose_difference = glucose_current - glucose_target
285
+ correction_dose = glucose_difference / isf
286
+
287
+ if override_correction_dose is not None: # Check for None
288
+ correction_dose = override_correction_dose
289
+
290
+ # Calculate carb dose
291
+ carb_dose = carbs / icr
292
+
293
+ # Calculate total bolus
294
+ total_bolus = max(0, carb_dose + correction_dose)
295
+
296
+ # Calculate basal
297
+ basal_dose = weight * 0.5
298
+
299
+ return {
300
+ 'icr': round(icr, 2),
301
+ 'isf': round(isf, 2),
302
+ 'correction_dose': round(correction_dose, 2),
303
+ 'carb_dose': round(carb_dose, 2),
304
+ 'total_bolus': round(total_bolus, 2),
305
+ 'basal_dose': round(basal_dose, 2),
306
+ 'insulin_type': insulin_type,
307
+ 'insulin_onset': insulin_data['onset'],
308
+ 'insulin_duration': insulin_data['duration'],
309
+ 'peak_time': insulin_data['peak_time'],
310
+ }
311
+
312
+ def create_detailed_report(nutrition_info, insulin_info, current_basal_rate):
313
+ """Create a detailed report of carbs and insulin calculations"""
314
+ carb_details = f"""
315
+ FOOD DETAILS:
316
+ -------------
317
+ Detected Food: {nutrition_info['matched_food']}
318
+ Category: {nutrition_info['category']}
319
+ Subcategory: {nutrition_info['subcategory']}
320
+
321
+ CARBOHYDRATE INFORMATION:
322
+ ------------------------
323
+ Standard Serving Size: {nutrition_info['serving_size']}
324
+ Carbs per Serving: {nutrition_info['base_carbs']}g
325
+ Portion Multiplier: {nutrition_info['portion_multiplier']}x
326
+ Total Carbs: {nutrition_info['adjusted_carbs']}g
327
+ Notes: {nutrition_info['notes']}
328
+ """
329
+
330
+ insulin_details = f"""
331
+ INSULIN CALCULATIONS:
332
+ --------------------
333
+ ICR (Insulin to Carb Ratio): 1:{insulin_info['icr']}
334
+ ISF (Insulin Sensitivity Factor): 1:{insulin_info['isf']}
335
+ Insulin Type: {insulin_info['insulin_type']}
336
+ Onset: {insulin_info['insulin_onset']} hours
337
+ Duration: {insulin_info['insulin_duration']} hours
338
+ Peak Time: {insulin_info['peak_time']} hours
339
+
340
+ RECOMMENDED DOSES:
341
+ -----------------
342
+ Correction Dose: {insulin_info['correction_dose']} units
343
+ Carb Dose: {insulin_info['carb_dose']} units
344
+ Total Bolus: {insulin_info['total_bolus']} units
345
+ Daily Basal: {insulin_info['basal_dose']} units
346
+ Current Basal Rate: {current_basal_rate} units/hour
347
+ """
348
+
349
+ return carb_details, insulin_details
350
+
351
+ # -------------------------------------------------
352
+ # Main Dashboard Function
353
+ # -------------------------------------------------
354
+ def diabetes_dashboard(initial_glucose, food_image, stress_level, sleep_hours, time_hours,
355
+ weight, tdd, target_glucose, exercise_duration, exercise_intensity, portion_size, insulin_type,
356
+ override_correction_dose, extended_bolus_duration, basal_rates_input):
357
+ """Main dashboard function"""
358
+ try:
359
+ # 0. Load Files
360
+ food_data = load_food_data() #loads HF Datasets from the function
361
+
362
+ # 1. Food Classification and Carb Calculation
363
+ food_name = classify_food(food_image) # This line is now inside the function
364
+ print(f"Classified food name: {food_name}") # Debugging: What is classified as? # Corrected indentation
365
+ nutrition_info = get_food_nutrition(food_name, food_data, portion_size) # Changed to pass in data
366
+ if not nutrition_info:
367
+ # Try with generic categories if specific food not found
368
+ generic_terms = food_name.split()
369
+ for term in generic_terms:
370
+ nutrition_info = get_food_nutrition(term, food_data, portion_size) # Changed to pass in data
371
+ if nutrition_info:
372
+ break
373
+
374
+ if not nutrition_info:
375
+ return (
376
+ f"Could not find nutrition information for: {food_name} in the local database", # Removed USDA ref
377
+ "No insulin calculations available",
378
+ None,
379
+ None,
380
+ None
381
+ )
382
+
383
+ # 2. Insulin Calculations
384
+ try:
385
+ basal_rates_dict = json.loads(basal_rates_input)
386
+ except Exception as e: # added exception handling
387
+ print(f"Basal rates JSON invalid, using default. Error: {e}")
388
+ basal_rates_dict = DEFAULT_BASAL_RATES
389
+
390
+ insulin_info = calculate_insulin_needs(
391
+ nutrition_info['adjusted_carbs'],
392
+ initial_glucose,
393
+ target_glucose,
394
+ tdd,
395
+ weight,
396
+ insulin_type,
397
+ override_correction_dose # Pass override
398
+ )
399
+
400
+ if 'error' in insulin_info:
401
+ return insulin_info['error'], None, None, None, None
402
+
403
+ # 3. Create detailed reports
404
+ current_time_for_basal = 12 #Arbitrary number to pull from Basal Rates Dict
405
+ current_basal_rate = get_basal_rate(current_time_for_basal, basal_rates_dict) # Added basal rate to the function and report.
406
+ carb_details, insulin_details = create_detailed_report(nutrition_info, insulin_info, current_basal_rate)
407
+
408
+ # 4. Glucose Prediction
409
+ hours = list(range(time_hours))
410
+ glucose_levels = []
411
+ current_glucose = initial_glucose
412
+ insulin_history = [] # This will store all past doses for active insulin calculations
413
+ # simulate that a dose has just been given to the patient at t=0
414
+ insulin_history.append((0, insulin_info['total_bolus'], insulin_info['insulin_type'], extended_bolus_duration)) # Pass bolus duration
415
+
416
+ for t in hours:
417
+ # Factor in carbs effect (peaks at 1-2 hours)
418
+ carb_effect = nutrition_info['adjusted_carbs'] * 0.1 * np.exp(-(t - 1.5) ** 2 / 2)
419
+
420
+ # Factor in insulin effect (peaks at 2-3 hours)
421
+ # Original model: insulin_effect = insulin_info['total_bolus'] * 2 * np.exp(-(t-2.5)**2/2)
422
+ # get effect based on amount of insulin still active from previous boluses
423
+ active_insulin = calculate_active_insulin(insulin_history, t)
424
+ insulin_effect = insulin_activity(t, insulin_type, active_insulin, extended_bolus_duration) # Pass bolus duration
425
+
426
+ # Get the basal effect
427
+ basal_rate = get_basal_rate(t, basal_rates_dict)
428
+ basal_insulin_effect = basal_rate # Units per hour
429
+
430
+ # Add stress effect
431
+ stress_effect = stress_level * 2
432
+
433
+ # Add sleep effect
434
+ sleep_effect = abs(8 - sleep_hours) * 5
435
+
436
+ # Add exercise effect
437
+ exercise_effect = (exercise_duration / 60) * exercise_intensity * 2
438
+
439
+ # Calculate glucose with all factors
440
+ glucose = (current_glucose + carb_effect - insulin_effect +
441
+ stress_effect + sleep_effect + exercise_effect - basal_insulin_effect)
442
+ glucose_levels.append(max(70, min(400, glucose)))
443
+ current_glucose = glucose_levels[-1]
444
+
445
+ # 5. Create visualization
446
+ fig, ax = plt.subplots(figsize=(12, 6))
447
+ ax.plot(hours, glucose_levels, 'b-', label='Predicted Glucose')
448
+ ax.axhline(y=target_glucose, color='g', linestyle='--', label='Target')
449
+ ax.fill_between(hours, [70] * len(hours), [180] * len(hours),
450
+ alpha=0.1, color='g', label='Target Range')
451
+ ax.set_ylabel('Glucose (mg/dL)')
452
+ ax.set_xlabel('Hours')
453
+ ax.set_title('Predicted Blood Glucose Over Time')
454
+ ax.legend()
455
+ ax.grid(True)
456
+
457
+ return (
458
+ carb_details,
459
+ insulin_details,
460
+ insulin_info['basal_dose'],
461
+ insulin_info['total_bolus'],
462
+ fig
463
+ )
464
+
465
+ except Exception as e:
466
+ return f"Error: {str(e)}", None, None, None, None
467
+
468
+ # -------------------------------------------------
469
+ # Gradio Interface Setup
470
+ # -------------------------------------------------
471
+ with gr.Blocks() as app: # using Blocks API to manually design the layout
472
+ gr.Markdown("# Type 1 Diabetes Management Dashboard")
473
+
474
+ with gr.Tab("Glucose & Meal"):
475
+ with gr.Row():
476
+ initial_glucose = gr.Number(label="Current Blood Glucose (mg/dL)", value=120)
477
+ food_image = gr.Image(label="Food Image", type="pil") # Now a file upload
478
+ with gr.Row():
479
+ portion_size = gr.Slider(0.1, 3, step=0.1, label="Portion Size Multiplier", value=1.0)
480
+
481
+ with gr.Tab("Insulin"):
482
+ with gr.Column(): # Place inputs in a column layout
483
+ insulin_type = gr.Dropdown(choices=list(INSULIN_TYPES.keys()), label="Insulin Type", value="Rapid-Acting")
484
+ override_correction_dose = gr.Number(label="Override Correction Dose (Units)", value=None)
485
+ extended_bolus_duration = gr.Number(label="Extended Bolus Duration (Hours)", value=0)
486
+
487
+ with gr.Tab("Basal Settings"):
488
+ with gr.Column():
489
+ basal_rates_input = gr.Textbox(label="Basal Rates (JSON)", lines=3,
490
+ value="""{"00:00-06:00": 0.8, "06:00-12:00": 1.0, "12:00-18:00": 0.9, "18:00-24:00": 0.7}""")
491
+
492
+ with gr.Tab("Other Factors"):
493
+ with gr.Accordion("Factors affecting Glucose levels", open=False): # keep advanced options collapsed by default
494
+ weight = gr.Number(label="Weight (kg)", value=70)
495
+ tdd = gr.Number(label="Total Daily Dose (TDD) of insulin (units)", value=40)
496
+ target_glucose = gr.Number(label="Target Blood Glucose (mg/dL)", value=100)
497
+ stress_level = gr.Slider(1, 10, step=1, label="Stress Level (1-10)", value=1)
498
+ sleep_hours = gr.Number(label="Sleep Hours", value=7)
499
+ exercise_duration = gr.Number(label="Exercise Duration (minutes)", value=0)
500
+ exercise_intensity = gr.Slider(1, 10, step=1, label="Exercise Intensity (1-10)", value=1)
501
+
502
+ with gr.Row():
503
+ time_hours = gr.Slider(1, 24, step=1, label="Prediction Time (hours)", value=6)
504
+
505
+ with gr.Row():
506
+ calculate_button = gr.Button("Calculate")
507
+
508
+ with gr.Column():
509
+ carb_details_output = gr.Textbox(label="Carbohydrate Details", lines=5)
510
+ insulin_details_output = gr.Textbox(label="Insulin Calculation Details", lines=5)
511
+ basal_dose_output = gr.Number(label="Basal Insulin Dose (units/day)")
512
+ bolus_dose_output = gr.Number(label="Bolus Insulin Dose (units)")
513
+ glucose_plot_output = gr.Plot(label="Glucose Prediction")
514
+
515
+ calculate_button.click(
516
+ fn=diabetes_dashboard,
517
+ inputs=[
518
+ initial_glucose,
519
+ food_image,
520
+ stress_level,
521
+ sleep_hours,
522
+ time_hours,
523
+ weight,
524
+ tdd,
525
+ target_glucose,
526
+ exercise_duration,
527
+ exercise_intensity,
528
+ portion_size,
529
+ insulin_type,
530
+ override_correction_dose,
531
+ extended_bolus_duration,
532
+ basal_rates_input,
533
+ ],
534
+ outputs=[
535
+ carb_details_output,
536
+ insulin_details_output,
537
+ basal_dose_output,
538
+ bolus_dose_output,
539
+ glucose_plot_output
540
+ ]
541
+ )
542
+
543
+ if __name__ == "__main__":
544
+ app.launch(share=True)