Sidhi2512 commited on
Commit
400b5a2
·
verified ·
1 Parent(s): 1ee6ab4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -273
app.py CHANGED
@@ -1,45 +1,27 @@
1
- import os
2
  import gradio as gr
3
- from fastapi import FastAPI, UploadFile, File
4
- import io
5
- from PIL import Image
6
- import json
7
- import pandas as pd
8
  import numpy as np
 
9
  import matplotlib.pyplot as plt
10
  import torch
11
  from transformers import AutoImageProcessor, AutoModelForImageClassification
 
12
  from difflib import get_close_matches
13
- from datasets import load_dataset
14
- import nltk # For stemming/lemmatization
15
-
16
- # Download nltk resources (if not already present)
17
- try:
18
- from nltk.stem import PorterStemmer # Or LancasterStemmer
19
- stemmer = PorterStemmer()
20
- nltk.data.find("corpora/wordnet")
21
- from nltk.stem import WordNetLemmatizer
22
- lemmatizer = WordNetLemmatizer()
23
- except LookupError:
24
- import nltk
25
- nltk.download('wordnet')
26
- nltk.download('omw-1.4')
27
- from nltk.stem import WordNetLemmatizer
28
-
29
- lemmatizer = WordNetLemmatizer()
30
-
31
- from nltk.stem import PorterStemmer # Or LancasterStemmer
32
- stemmer = PorterStemmer()
33
-
34
-
35
 
36
  # -------------------------------------------------
37
  # Configuration
38
  # -------------------------------------------------
 
 
39
  INSULIN_TYPES = {
40
- "Rapid-Acting": {"onset": 0.25, "duration": 4, "peak_time": 1.0},
41
  "Long-Acting": {"onset": 2, "duration": 24, "peak_time": 8},
42
  }
 
 
43
  DEFAULT_BASAL_RATES = {
44
  "00:00-06:00": 0.8,
45
  "06:00-12:00": 1.0,
@@ -50,6 +32,7 @@ DEFAULT_BASAL_RATES = {
50
  # -------------------------------------------------
51
  # Load Food Data from Hugging Face Dataset
52
  # -------------------------------------------------
 
53
  def load_food_data(dataset_name="Anupam007/Diabetic"):
54
  try:
55
  dataset = load_dataset(dataset_name)
@@ -61,6 +44,13 @@ def load_food_data(dataset_name="Anupam007/Diabetic"):
61
  # Remove unnamed columns
62
  food_data = food_data.loc[:, ~food_data.columns.str.contains('^unnamed')]
63
 
 
 
 
 
 
 
 
64
  # Normalize food_name column to lowercase: Crucial for matching
65
  if 'food_name' in food_data.columns:
66
  food_data['food_name'] = food_data['food_name'].str.lower()
@@ -76,6 +66,8 @@ def load_food_data(dataset_name="Anupam007/Diabetic"):
76
  'serving_amount': [29],
77
  'serving_unit': ['g'],
78
  'carbohydrate_grams': [15],
 
 
79
  'notes': ['default']
80
  })
81
 
@@ -91,11 +83,13 @@ def load_food_data(dataset_name="Anupam007/Diabetic"):
91
  food_data = pd.DataFrame({
92
  'food_category': ['starch'],
93
  'food_subcategory': ['bread'],
94
- 'food_name': ['white bread'], # lowercase default
95
  'serving_description': ['servingsize'],
96
  'serving_amount': [29],
97
  'serving_unit': ['g'],
98
  'carbohydrate_grams': [15],
 
 
99
  'notes': ['default']
100
  })
101
  return food_data
@@ -103,13 +97,14 @@ def load_food_data(dataset_name="Anupam007/Diabetic"):
103
  # -------------------------------------------------
104
  # Load Food Classification Model
105
  # -------------------------------------------------
106
-
107
  try:
108
- # Load model directly
109
- from transformers import AutoImageProcessor, AutoModelForImageClassification
110
-
111
- processor = AutoImageProcessor.from_pretrained("rajistics/finetuned-indian-food")
112
- model = AutoModelForImageClassification.from_pretrained("rajistics/finetuned-indian-food")
 
 
113
  model_loaded = True #Flag for error handling in other defs
114
  except Exception as e:
115
  print(f"Model Load Error: {e}") # include e in print statement
@@ -118,16 +113,8 @@ except Exception as e:
118
  model = None
119
 
120
  def classify_food(image):
121
-
122
- inputs = processor(images=image, return_tensors="pt")
123
- print(f"Processed image keys: {inputs.keys()}") # Print the keys of the inputs dictionary
124
- if 'pixel_values' in inputs:
125
- print(f"Pixel values shape: {inputs['pixel_values'].shape}")
126
- print(f"Pixel values type: {inputs['pixel_values'].dtype}")
127
- print(f"First few pixel values: {inputs['pixel_values'][0, :5]}") # Print a small slice
128
- else:
129
- print("Pixel values not found in inputs!")
130
-
131
  try:
132
  if not model_loaded:
133
  print("Model not loaded, returning 'Unknown'")
@@ -158,214 +145,73 @@ def classify_food(image):
158
  return "Unknown" # If an exception arises make sure to create a default case
159
 
160
  # -------------------------------------------------
161
- # Nutrition Data Retrieval with Enhanced Matching
162
  # -------------------------------------------------
163
 
164
- def lemmatize_food_name(food_name):
165
- """Lemmatize the food name to its base form."""
166
- return lemmatizer.lemmatize(food_name)
167
-
168
- def stem_food_name(food_name):
169
- """Stem the food name to its root form."""
170
- return stemmer.stem(food_name)
171
-
172
- def get_food_nutrition(food_name: str, food_data, portion_size: float = 1.0) -> dict:
173
- """
174
- Retrieves nutrition information for a given food name from a local database,
175
- with enhanced matching including stemming, lemmatization, and synonym lookup.
176
- """
177
- food_name_lower = food_name.lower()
178
- food_names = food_data['food_name'].str.lower().tolist()
179
-
180
- print(f"Searching for: {food_name_lower}")
181
-
182
- # 1. Exact Match
183
- if food_name_lower in food_names:
184
- print("Exact match found.")
185
- return _extract_nutrition_data(food_data, food_name_lower, portion_size)
186
-
187
- # 2. Close Matches
188
- close_matches = get_close_matches(food_name_lower, food_names, n=1, cutoff=0.6)
189
- if close_matches:
190
- print(f"Close match found: {close_matches[0]}")
191
- return _extract_nutrition_data(food_data, close_matches[0], portion_size)
192
-
193
- # 3. Stemming and Lemmatization
194
- stemmed_name = stem_food_name(food_name_lower)
195
- lemmatized_name = lemmatize_food_name(food_name_lower)
196
-
197
- stemmed_matches = get_close_matches(stemmed_name, [stem_food_name(name) for name in food_names], n=1, cutoff=0.6)
198
- lemmatized_matches = get_close_matches(lemmatized_name, [lemmatize_food_name(name) for name in food_names], n=1, cutoff=0.6)
199
-
200
- if stemmed_matches:
201
- original_name = food_data['food_name'].iloc[[food_names.index(stemmed_matches[0])]].values[0]
202
- print(f"Stemmed match found: {stemmed_matches[0]} -> {original_name}")
203
- return _extract_nutrition_data(food_data, original_name, portion_size)
204
-
205
- if lemmatized_matches:
206
- original_name = food_data['food_name'].iloc[[food_names.index(lemmatized_matches[0])]].values[0]
207
- print(f"Lemmatized match found: {lemmatized_matches[0]} -> {original_name}")
208
- return _extract_nutrition_data(food_data, original_name, portion_size)
209
-
210
- # 4. Synonym Lookup (if 'synonyms' column exists)
211
- if 'synonyms' in food_data.columns:
212
- for index, row in food_data.iterrows():
213
- synonyms = row.get('synonyms', '')
214
- if synonyms:
215
- synonym_list = [s.strip().lower() for s in synonyms.split(',')]
216
- if food_name_lower in synonym_list:
217
- print(f"Synonym match found: {food_name_lower} in synonyms for {row['food_name']}")
218
- return _extract_nutrition_data(food_data, row['food_name'].lower(), portion_size)
219
-
220
- print(f"No nutrition information found for {food_name} using any matching method.")
221
- return None
222
-
223
- def _extract_nutrition_data(food_data: pd.DataFrame, matched_food_name: str, portion_size: float) -> dict:
224
- """Extracts nutrition data from a matched food item."""
225
- matched_row = food_data[food_data['food_name'] == matched_food_name].iloc[0]
226
-
227
- carb_col = 'carbohydrate_grams'
228
- amount_col = 'serving_amount'
229
- unit_col = 'serving_unit'
230
- fiber_col = 'fiber_grams'
231
- sugar_col = 'sugar_grams' # Add Sugar
232
-
233
- base_carbs = matched_row.get(carb_col, 0.0)
234
- base_fiber = matched_row.get(fiber_col, 0.0) # Get Fiber
235
- base_sugar = matched_row.get(sugar_col, 0.0) # Get Sugar
236
-
237
  try:
238
- base_carbs = float(base_carbs)
239
- base_fiber = float(base_fiber) # Convert Fiber to float
240
- base_sugar = float(base_sugar) # Convert Sugar to float
241
- except (ValueError, TypeError):
242
- base_carbs = 0.0
243
- base_fiber = 0.0 # Default Fiber
244
- base_sugar = 0.0 # Default Sugar
245
-
246
- serving_size = f"{matched_row.get(amount_col, 'Unknown')} {matched_row.get(unit_col, '')}"
247
- adjusted_carbs = base_carbs * portion_size
248
- adjusted_fiber = base_fiber * portion_size # Adjust Fiber
249
- adjusted_sugar = base_sugar * portion_size # Adjust Sugar
250
-
251
- print(f"Carbs: {base_carbs}, Fiber: {base_fiber}, Sugar: {base_sugar}") # Debug print
252
-
253
- return {
254
- 'matched_food': matched_row['food_name'],
255
- 'category': matched_row.get('food_category', 'Unknown'),
256
- 'subcategory': matched_row.get('food_subcategory', 'Unknown'),
257
- 'base_carbs': base_carbs,
258
- 'adjusted_carbs': adjusted_carbs,
259
- 'base_fiber': base_fiber, # Include Base Fiber
260
- 'adjusted_fiber': adjusted_fiber, # Include Adjusted Fiber
261
- 'base_sugar': base_sugar, # Include Base Sugar
262
- 'adjusted_sugar': adjusted_sugar, # Include Adjusted Sugar
263
- 'serving_size': serving_size,
264
- 'portion_multiplier': portion_size,
265
- 'notes': matched_row.get('notes', '')
266
- }
267
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
 
269
- # -------------------------------------------------
270
- # Insulin and Glucose Calculations
271
- # -------------------------------------------------
272
- def get_basal_rate(current_time_hour, basal_rates):
273
- """Gets the appropriate basal rate for a given time of day."""
274
- for interval, rate in basal_rates.items():
275
- try: # add a try and except to handle values in intervals that do not have the format "start-end"
276
- parts = interval.split(":")[0].split("-")
277
- if len(parts) == 2: # Check if there are two parts (start and end)
278
- start_hour, end_hour = map(int, parts)
279
- if start_hour <= current_time_hour < end_hour or (start_hour <= current_time_hour and end_hour == 24):
280
- return rate
281
- except Exception as e: # include exception in exception handling
282
- print(f"Warning: Invalid interval format: {interval}. Skipping. Error: {e}") #Inform user of formatting issues
283
-
284
- return 0 # Default if no matching interval
285
-
286
- def insulin_activity(t, insulin_type, bolus_dose, bolus_duration=0):
287
- """Models insulin activity over time."""
288
- insulin_data = INSULIN_TYPES.get(insulin_type)
289
- if not insulin_data:
290
- return 0 # Or raise an error
291
-
292
- # Simple exponential decay model (replace with a more sophisticated model)
293
- peak_time = insulin_data['peak_time'] # Time in hours at which insulin activity is at max level
294
- duration = insulin_data['duration'] # Total time for which insulin stays in effect
295
- if t < peak_time:
296
- activity = (bolus_dose * t / peak_time) * np.exp(1- t/peak_time) # rising activity
297
- elif t < duration:
298
- activity = bolus_dose * np.exp((peak_time - t) / (duration - peak_time)) # decaying activity
299
- else:
300
- activity = 0
301
-
302
- if bolus_duration > 0: # Extended Bolus
303
- if 0 <= t <= bolus_duration:
304
- # Linear release of insulin over bolus_duration
305
- effective_dose = bolus_dose / bolus_duration
306
- duration = INSULIN_TYPES.get(insulin_type)['duration']
307
- if t < duration:
308
- activity = effective_dose
309
- else:
310
- activity = 0
311
- else:
312
- activity = 0
313
-
314
- return activity
315
-
316
- def calculate_active_insulin(insulin_history, current_time):
317
- """Calculates remaining active insulin from previous doses."""
318
- active_insulin = 0
319
- for dose_time, dose_amount, insulin_type, bolus_duration in insulin_history:
320
- elapsed_time = current_time - dose_time
321
- remaining_activity = insulin_activity(elapsed_time, insulin_type, dose_amount, bolus_duration)
322
- active_insulin += remaining_activity
323
- return active_insulin
324
-
325
- def calculate_insulin_needs(carbs, glucose_current, glucose_target, tdd, weight, insulin_type="Rapid-Acting", override_correction_dose = None):
326
- """Calculate insulin needs for Type 1 diabetes"""
327
- if tdd <= 0:
328
- return {
329
- 'error': 'Total Daily Dose (TDD) must be greater than 0'
330
- }
331
- insulin_data = INSULIN_TYPES.get(insulin_type)
332
- if not insulin_data:
333
- return {
334
- 'error': "Invalid insulin type. Choose from" + ", ".join(INSULIN_TYPES.keys())
335
- }
336
-
337
- # Refined calculations
338
- icr = (450 if weight <= 45 else 500) / tdd
339
- isf = 1700 / tdd
340
-
341
- # Calculate correction dose
342
- glucose_difference = glucose_current - glucose_target
343
- correction_dose = glucose_difference / isf
344
-
345
- if override_correction_dose is not None: # Check for None
346
- correction_dose = override_correction_dose
347
-
348
- # Calculate carb dose
349
- carb_dose = carbs / icr
350
-
351
- # Calculate total bolus
352
- total_bolus = max(0, carb_dose + correction_dose)
353
-
354
- # Calculate basal
355
- basal_dose = weight * 0.5
356
-
357
- return {
358
- 'icr': round(icr, 2),
359
- 'isf': round(isf, 2),
360
- 'correction_dose': round(correction_dose, 2),
361
- 'carb_dose': round(carb_dose, 2),
362
- 'total_bolus': round(total_bolus, 2),
363
- 'basal_dose': round(basal_dose, 2),
364
- 'insulin_type': insulin_type,
365
- 'insulin_onset': insulin_data['onset'],
366
- 'insulin_duration': insulin_data['duration'],
367
- 'peak_time': insulin_data['peak_time'],
368
- }
369
 
370
  def create_detailed_report(nutrition_info, insulin_info, current_basal_rate):
371
  """Create a detailed report of carbs and insulin calculations"""
@@ -380,12 +226,12 @@ def create_detailed_report(nutrition_info, insulin_info, current_basal_rate):
380
  ------------------------
381
  Standard Serving Size: {nutrition_info['serving_size']}
382
  Carbs per Serving: {nutrition_info['base_carbs']}g
 
383
  Fiber per Serving: {nutrition_info['base_fiber']}g
 
384
  Sugar per Serving: {nutrition_info['base_sugar']}g
 
385
  Portion Multiplier: {nutrition_info['portion_multiplier']}x
386
- Total Carbs: {nutrition_info['adjusted_carbs']}g
387
- Total Fiber: {nutrition_info['adjusted_fiber']}g
388
- Total Sugar: {nutrition_info['adjusted_sugar']}g
389
  Notes: {nutrition_info['notes']}
390
  """
391
 
@@ -425,17 +271,22 @@ def diabetes_dashboard(initial_glucose, food_image, stress_level, sleep_hours, t
425
  food_name = classify_food(food_image) # This line is now inside the function
426
  print(f"Classified food name: {food_name}") # Debugging: What is classified as? # Corrected indentation
427
  nutrition_info = get_food_nutrition(food_name, food_data, portion_size) # Changed to pass in data
428
-
429
  if not nutrition_info:
430
- return (
431
- f"Could not find nutrition information for: {food_name} in the local database",
432
- "No insulin calculations available",
433
- None,
434
- None,
435
- None,
436
- None,
437
- None # Fiber and Sugar Output
438
- )
 
 
 
 
 
 
439
 
440
  # 2. Insulin Calculations
441
  try:
@@ -455,7 +306,7 @@ def diabetes_dashboard(initial_glucose, food_image, stress_level, sleep_hours, t
455
  )
456
 
457
  if 'error' in insulin_info:
458
- return insulin_info['error'], None, None, None, None, None, None
459
 
460
  # 3. Create detailed reports
461
  current_time_for_basal = 12 #Arbitrary number to pull from Basal Rates Dict
@@ -516,13 +367,11 @@ def diabetes_dashboard(initial_glucose, food_image, stress_level, sleep_hours, t
516
  insulin_details,
517
  insulin_info['basal_dose'],
518
  insulin_info['total_bolus'],
519
- fig,
520
- nutrition_info['base_fiber'], # Base Fiber Output
521
- nutrition_info['base_sugar'] # Base Sugar Output
522
  )
523
 
524
  except Exception as e:
525
- return f"Error: {str(e)}", None, None, None, None, None, None
526
 
527
  # -------------------------------------------------
528
  # Gradio Interface Setup
@@ -570,8 +419,6 @@ with gr.Blocks() as app: # using Blocks API to manually design the layout
570
  basal_dose_output = gr.Number(label="Basal Insulin Dose (units/day)")
571
  bolus_dose_output = gr.Number(label="Bolus Insulin Dose (units)")
572
  glucose_plot_output = gr.Plot(label="Glucose Prediction")
573
- fiber_output = gr.Number(label="Fiber (g)")
574
- sugar_output = gr.Number(label="Sugar (g)")
575
 
576
  calculate_button.click(
577
  fn=diabetes_dashboard,
@@ -597,9 +444,7 @@ with gr.Blocks() as app: # using Blocks API to manually design the layout
597
  insulin_details_output,
598
  basal_dose_output,
599
  bolus_dose_output,
600
- glucose_plot_output,
601
- fiber_output,
602
- sugar_output
603
  ]
604
  )
605
 
 
 
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,
 
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)
 
44
  # Remove unnamed columns
45
  food_data = food_data.loc[:, ~food_data.columns.str.contains('^unnamed')]
46
 
47
+ # Check if "fiber_grams" and "sugar_grams" are not in the dataset
48
+ if "fiber_grams" not in food_data.columns:
49
+ food_data['fiber_grams'] = None
50
+ if "sugar_grams" not in food_data.columns:
51
+ food_data['sugar_grams'] = None
52
+
53
+
54
  # Normalize food_name column to lowercase: Crucial for matching
55
  if 'food_name' in food_data.columns:
56
  food_data['food_name'] = food_data['food_name'].str.lower()
 
66
  'serving_amount': [29],
67
  'serving_unit': ['g'],
68
  'carbohydrate_grams': [15],
69
+ 'fiber_grams': [0], #added column
70
+ 'sugar_grams': [0], #added column
71
  'notes': ['default']
72
  })
73
 
 
83
  food_data = pd.DataFrame({
84
  'food_category': ['starch'],
85
  'food_subcategory': ['bread'],
86
+ 'food_name': ['white bread'],
87
  'serving_description': ['servingsize'],
88
  'serving_amount': [29],
89
  'serving_unit': ['g'],
90
  'carbohydrate_grams': [15],
91
+ 'fiber_grams': [0], #added column
92
+ 'sugar_grams': [0], #added column
93
  'notes': ['default']
94
  })
95
  return food_data
 
97
  # -------------------------------------------------
98
  # Load Food Classification Model
99
  # -------------------------------------------------
 
100
  try:
101
+ processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
102
+ model = AutoModelForImageClassification.from_pretrained(
103
+ "google/vit-base-patch16-224",
104
+ torch_dtype=torch.float16, # Use float16 for efficiency
105
+ device_map="cpu", # Run on CPU
106
+ low_cpu_mem_usage=True # Optimize memory usage
107
+ )
108
  model_loaded = True #Flag for error handling in other defs
109
  except Exception as e:
110
  print(f"Model Load Error: {e}") # include e in print statement
 
113
  model = None
114
 
115
  def classify_food(image):
116
+ """Classify food image using the pre-trained model"""
117
+ print("classify_food function called") # Check if this function is even called
 
 
 
 
 
 
 
 
118
  try:
119
  if not model_loaded:
120
  print("Model not loaded, returning 'Unknown'")
 
145
  return "Unknown" # If an exception arises make sure to create a default case
146
 
147
  # -------------------------------------------------
148
+ # USDA API Integration - REMOVED for local HF Spaces deployment
149
  # -------------------------------------------------
150
 
151
+ def get_food_nutrition(food_name: str, food_data, portion_size: float = 1.0) -> Optional[Dict[str, Any]]:
152
+ """Get carbohydrate content for the given food, and also sugar and fiber"""
153
+ print("get_food_nutrition function called") # Ensure the function is called
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  try:
155
+ # First try the local CSV database
156
+ food_name_lower = food_name.lower() # Ensure input is also lowercase
157
+ food_names = food_data['food_name'].str.lower().tolist()
158
+
159
+ print(f"Searching for: {food_name_lower}")
160
+ matches = get_close_matches(food_name_lower, food_names, n=1, cutoff=0.5)
161
+
162
+ print(f"Matches found: {matches}")
163
+
164
+ if matches:
165
+ matched_row = food_data[food_data['food_name'].str.lower() == matches[0]]
166
+
167
+ if not matched_row.empty:
168
+ row = matched_row.iloc[0]
169
+
170
+ print(f"Matched row from CSV: {row}")
171
+
172
+ carb_col = 'carbohydrate_grams'
173
+ amount_col = 'serving_amount'
174
+ unit_col = 'serving_unit'
175
+ fiber_col = 'fiber_grams' # Added Fiber column
176
+ sugar_col = 'sugar_grams' # Added Sugar column
177
+
178
+ base_carbs = row.get(carb_col, 0.0) if pd.notna(row.get(carb_col, None)) else 0.0
179
+ base_fiber = row.get(fiber_col, 0.0) if pd.notna(row.get(fiber_col, None)) else 0.0
180
+ base_sugar = row.get(sugar_col, 0.0) if pd.notna(row.get(sugar_col, None)) else 0.0
181
+
182
+
183
+ if amount_col not in row or unit_col not in row or pd.isna(row[amount_col]) or pd.isna(row[unit_col]):
184
+ serving_size = "Unknown"
185
+ print(f"Warning: '{amount_col}' or '{unit_col}' is missing in CSV")
186
+ else:
187
+ serving_size = f"{row[amount_col]} {row[unit_col]}"
188
+
189
+ adjusted_carbs = base_carbs * portion_size
190
+ adjusted_fiber = base_fiber * portion_size
191
+ adjusted_sugar = base_sugar * portion_size
192
+
193
+ return {
194
+ 'matched_food': row['food_name'],
195
+ 'category': row['food_category'] if 'food_category' in row and not pd.isna(row['food_category']) else 'Unknown',
196
+ 'subcategory': row['food_subcategory'] if 'food_subcategory' in row and not pd.isna(row['food_subcategory']) else 'Unknown',
197
+ 'base_carbs': base_carbs,
198
+ 'adjusted_carbs': adjusted_carbs,
199
+ 'base_fiber': base_fiber,
200
+ 'adjusted_fiber': adjusted_fiber,
201
+ 'base_sugar': base_sugar,
202
+ 'adjusted_sugar': adjusted_sugar,
203
+ 'serving_size': serving_size,
204
+ 'portion_multiplier': portion_size,
205
+ 'notes': row['notes'] if 'notes' in row and not pd.isna(row['notes']) else ''
206
+ }
207
+
208
+ print(f"No match found in CSV for {food_name}")
209
+ print(f"No nutrition information found for {food_name} in the local database.")
210
+ return None
211
+ except Exception as e:
212
+ print(f"Error in get_food_nutrition: {e}")
213
+ return None
214
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
 
216
  def create_detailed_report(nutrition_info, insulin_info, current_basal_rate):
217
  """Create a detailed report of carbs and insulin calculations"""
 
226
  ------------------------
227
  Standard Serving Size: {nutrition_info['serving_size']}
228
  Carbs per Serving: {nutrition_info['base_carbs']}g
229
+ Adjusted Carbs: {nutrition_info['adjusted_carbs']}g
230
  Fiber per Serving: {nutrition_info['base_fiber']}g
231
+ Adjusted Fiber: {nutrition_info['adjusted_fiber']}g
232
  Sugar per Serving: {nutrition_info['base_sugar']}g
233
+ Adjusted Sugar: {nutrition_info['adjusted_sugar']}g
234
  Portion Multiplier: {nutrition_info['portion_multiplier']}x
 
 
 
235
  Notes: {nutrition_info['notes']}
236
  """
237
 
 
271
  food_name = classify_food(food_image) # This line is now inside the function
272
  print(f"Classified food name: {food_name}") # Debugging: What is classified as? # Corrected indentation
273
  nutrition_info = get_food_nutrition(food_name, food_data, portion_size) # Changed to pass in data
 
274
  if not nutrition_info:
275
+ # Try with generic categories if specific food not found
276
+ generic_terms = food_name.split()
277
+ for term in generic_terms:
278
+ nutrition_info = get_food_nutrition(term, food_data, portion_size) # Changed to pass in data
279
+ if nutrition_info:
280
+ break
281
+
282
+ if not nutrition_info:
283
+ return (
284
+ f"Could not find nutrition information for: {food_name} in the local database", # Removed USDA ref
285
+ "No insulin calculations available",
286
+ None,
287
+ None,
288
+ None
289
+ )
290
 
291
  # 2. Insulin Calculations
292
  try:
 
306
  )
307
 
308
  if 'error' in insulin_info:
309
+ return insulin_info['error'], None, None, None, None
310
 
311
  # 3. Create detailed reports
312
  current_time_for_basal = 12 #Arbitrary number to pull from Basal Rates Dict
 
367
  insulin_details,
368
  insulin_info['basal_dose'],
369
  insulin_info['total_bolus'],
370
+ fig
 
 
371
  )
372
 
373
  except Exception as e:
374
+ return f"Error: {str(e)}", None, None, None, None
375
 
376
  # -------------------------------------------------
377
  # Gradio Interface Setup
 
419
  basal_dose_output = gr.Number(label="Basal Insulin Dose (units/day)")
420
  bolus_dose_output = gr.Number(label="Bolus Insulin Dose (units)")
421
  glucose_plot_output = gr.Plot(label="Glucose Prediction")
 
 
422
 
423
  calculate_button.click(
424
  fn=diabetes_dashboard,
 
444
  insulin_details_output,
445
  basal_dose_output,
446
  bolus_dose_output,
447
+ glucose_plot_output
 
 
448
  ]
449
  )
450