Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -30,26 +30,67 @@ DEFAULT_BASAL_RATES = {
|
|
30 |
"18:00-24:00": 0.7
|
31 |
}
|
32 |
|
|
|
|
|
|
|
33 |
# -------------------------------------------------
|
34 |
# Load Food Data from Hugging Face Dataset
|
35 |
# -------------------------------------------------
|
36 |
|
37 |
def load_food_data(dataset_name="Anupam007/Diabetic", local_csv="food_data.csv"):
|
|
|
38 |
try:
|
39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
return food_data
|
41 |
|
42 |
except Exception as e:
|
43 |
print(f"Error loading data: {e}")
|
44 |
# Provide minimal default data in case of error
|
45 |
food_data = pd.DataFrame({
|
46 |
-
'food_category': ['
|
47 |
-
'food_subcategory': ['
|
48 |
-
'food_name': ['
|
49 |
-
'serving_description': ['
|
50 |
-
'serving_amount': [
|
51 |
-
'serving_unit': ['
|
52 |
-
'carbohydrate_grams': [
|
53 |
'notes': ['default']
|
54 |
})
|
55 |
return food_data
|
@@ -72,39 +113,60 @@ except Exception as e:
|
|
72 |
processor = None
|
73 |
model = None
|
74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
def classify_food(image):
|
76 |
-
"""Classify food image using the pre-trained model"""
|
77 |
-
|
|
|
|
|
|
|
|
|
78 |
try:
|
79 |
if not model_loaded:
|
80 |
-
print("Model not loaded, returning
|
81 |
-
return
|
82 |
-
|
83 |
-
print(f"Image type: {type(image)}") # Check the type of the image
|
84 |
|
85 |
if isinstance(image, np.ndarray):
|
86 |
-
print("Image is a numpy array, converting to PIL Image")
|
87 |
image = Image.fromarray(image)
|
88 |
|
89 |
-
print(f"Image mode: {image.mode}") # Check image mode (e.g., RGB, L)
|
90 |
-
|
91 |
image = processor(images=image, return_tensors="pt")
|
92 |
-
print(f"Processed image: {image}") # Print the output of the processor
|
93 |
|
94 |
with torch.no_grad():
|
95 |
outputs = model(**image)
|
96 |
predicted_idx = torch.argmax(outputs.logits, dim=-1).item()
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
100 |
|
101 |
except Exception as e:
|
102 |
-
print(f"Classify food error: {e}")
|
103 |
-
return
|
104 |
|
105 |
|
106 |
def get_food_nutrition(food_name: str, food_data, portion_size: float = 1.0) -> Optional[Dict[str, Any]]:
|
107 |
"""Get carbohydrate content for the given food""" #No USDA anymore
|
|
|
|
|
108 |
try:
|
109 |
# First try the local CSV database
|
110 |
food_name_lower = food_name.lower() # Ensure input is also lowercase
|
@@ -319,53 +381,26 @@ def diabetes_dashboard(initial_glucose, food_image, stress_level, sleep_hours, t
|
|
319 |
|
320 |
# 1. Food Classification and Carb Calculation
|
321 |
food_name = classify_food(food_image) # This line is now inside the function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
322 |
print(f"Classified food name: {food_name}") # Debugging: What is classified as? # Corrected indentation
|
323 |
nutrition_info = get_food_nutrition(food_name, food_data, portion_size) # Changed to pass in data
|
324 |
if not nutrition_info:
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
if not nutrition_info:
|
333 |
-
# Food not found, add to DataFrame if user provided the data
|
334 |
-
if new_food_name:
|
335 |
-
new_row = pd.DataFrame([{
|
336 |
-
'food_category': new_food_category,
|
337 |
-
'food_subcategory': new_food_subcategory,
|
338 |
-
'food_name': new_food_name.lower(), # Ensure lowercase
|
339 |
-
'serving_description': new_serving_description,
|
340 |
-
'serving_amount': new_serving_amount,
|
341 |
-
'serving_unit': new_serving_unit,
|
342 |
-
'carbohydrate_grams': new_carbohydrate_grams,
|
343 |
-
'notes': new_notes
|
344 |
-
}])
|
345 |
-
food_data = pd.concat([food_data, new_row], ignore_index=True)
|
346 |
-
|
347 |
-
# Save the updated food_data to the local CSV (or HF Dataset - implement that function)
|
348 |
-
food_data.to_csv("food_data.csv", index=False) # Save locally
|
349 |
-
print(f"Added {new_food_name} to the database and saved to food_data.csv")
|
350 |
-
|
351 |
-
# Now try to get nutrition info again
|
352 |
-
nutrition_info = get_food_nutrition(new_food_name, food_data, portion_size)
|
353 |
-
if not nutrition_info:
|
354 |
-
return (
|
355 |
-
f"Added {new_food_name} to database, but still could not retrieve nutrition information. Verify data.",
|
356 |
-
"No insulin calculations available",
|
357 |
-
None,
|
358 |
-
None,
|
359 |
-
None
|
360 |
-
)
|
361 |
-
else:
|
362 |
-
return (
|
363 |
-
f"Could not find nutrition information for: {food_name}. Please add it using the 'Add New Food' tab and provide the data.", # User prompt
|
364 |
-
"No insulin calculations available",
|
365 |
-
None,
|
366 |
-
None,
|
367 |
-
None
|
368 |
-
)
|
369 |
|
370 |
# 2. Insulin Calculations
|
371 |
try:
|
@@ -615,6 +650,8 @@ def compute_metrics(eval_pred):
|
|
615 |
|
616 |
# # trainer.save_model("food_classifier") # save locally
|
617 |
# # trainer.push_to_hub() # upload to HF Hub
|
618 |
-
|
|
|
619 |
if __name__ == "__main__":
|
|
|
620 |
app.launch(share=True)
|
|
|
30 |
"18:00-24:00": 0.7
|
31 |
}
|
32 |
|
33 |
+
# Global variable to store food name vocabulary
|
34 |
+
food_name_vocabulary = None
|
35 |
+
|
36 |
# -------------------------------------------------
|
37 |
# Load Food Data from Hugging Face Dataset
|
38 |
# -------------------------------------------------
|
39 |
|
40 |
def load_food_data(dataset_name="Anupam007/Diabetic", local_csv="food_data.csv"):
|
41 |
+
"""Loads food data from Hugging Face Dataset or a local CSV."""
|
42 |
try:
|
43 |
+
# Try loading from local CSV first
|
44 |
+
if os.path.exists(local_csv):
|
45 |
+
food_data = pd.read_csv(local_csv)
|
46 |
+
print(f"Loaded food data from local CSV: {local_csv}")
|
47 |
+
else:
|
48 |
+
# Load from Hugging Face Dataset
|
49 |
+
dataset = load_dataset(dataset_name)
|
50 |
+
food_data = dataset['train'].to_pandas()
|
51 |
+
print(f"Loaded food data from Hugging Face Dataset: {dataset_name}")
|
52 |
+
|
53 |
+
# Normalize column names to lowercase and remove spaces
|
54 |
+
food_data.columns = [col.lower().replace(' ', '') for col in food_data.columns]
|
55 |
+
|
56 |
+
# Remove unnamed columns
|
57 |
+
food_data = food_data.loc[:, ~food_data.columns.str.contains('^unnamed')]
|
58 |
+
|
59 |
+
# Normalize food_name column to lowercase: Crucial for matching
|
60 |
+
if 'food_name' in food_data.columns:
|
61 |
+
food_data['food_name'] = food_data['food_name'].str.lower()
|
62 |
+
print("Unique Food Names in Dataset:")
|
63 |
+
print(food_data['food_name'].unique())
|
64 |
+
else:
|
65 |
+
print("Warning: 'food_name' column not found in dataset.")
|
66 |
+
food_data = pd.DataFrame({
|
67 |
+
'food_category': ['starch'],
|
68 |
+
'food_subcategory': ['bread'],
|
69 |
+
'food_name': ['white bread'], # lowercase default
|
70 |
+
'serving_description': ['servingsize'],
|
71 |
+
'serving_amount': [29],
|
72 |
+
'serving_unit': ['g'],
|
73 |
+
'carbohydrate_grams': [15],
|
74 |
+
'notes': ['default']
|
75 |
+
})
|
76 |
+
|
77 |
+
#Print first 5 rows to check columns and values
|
78 |
+
print("First 5 rows of loaded data:")
|
79 |
+
print(food_data.head())
|
80 |
+
|
81 |
return food_data
|
82 |
|
83 |
except Exception as e:
|
84 |
print(f"Error loading data: {e}")
|
85 |
# Provide minimal default data in case of error
|
86 |
food_data = pd.DataFrame({
|
87 |
+
'food_category': ['starch'],
|
88 |
+
'food_subcategory': ['bread'],
|
89 |
+
'food_name': ['white bread'], # lowercase default
|
90 |
+
'serving_description': ['servingsize'],
|
91 |
+
'serving_amount': [29],
|
92 |
+
'serving_unit': ['g'],
|
93 |
+
'carbohydrate_grams': [15],
|
94 |
'notes': ['default']
|
95 |
})
|
96 |
return food_data
|
|
|
113 |
processor = None
|
114 |
model = None
|
115 |
|
116 |
+
def load_food_name_vocabulary(dataset_name="Anupam007/Diabetic"):
|
117 |
+
"""Loads the food name vocabulary from the dataset."""
|
118 |
+
global food_name_vocabulary # Use global keyword to modify the global variable
|
119 |
+
try:
|
120 |
+
dataset = load_dataset(dataset_name)
|
121 |
+
food_data = dataset['train'].to_pandas()
|
122 |
+
food_data['food_name'] = food_data['food_name'].str.lower()
|
123 |
+
food_name_vocabulary = food_data['food_name'].unique().tolist()
|
124 |
+
print("Food name vocabulary loaded.")
|
125 |
+
return food_name_vocabulary
|
126 |
+
|
127 |
+
except Exception as e:
|
128 |
+
print(f"Error loading food name vocabulary: {e}")
|
129 |
+
food_name_vocabulary = [] # Initialize to empty list in case of error
|
130 |
+
return food_name_vocabulary
|
131 |
+
|
132 |
def classify_food(image):
|
133 |
+
"""Classify food image using the pre-trained model, only return names from the allowed vocabulary."""
|
134 |
+
global food_name_vocabulary # Access global vocabulary
|
135 |
+
|
136 |
+
if food_name_vocabulary is None:
|
137 |
+
load_food_name_vocabulary() # Load vocab if not already loaded
|
138 |
+
|
139 |
try:
|
140 |
if not model_loaded:
|
141 |
+
print("Model not loaded, returning None")
|
142 |
+
return None
|
|
|
|
|
143 |
|
144 |
if isinstance(image, np.ndarray):
|
|
|
145 |
image = Image.fromarray(image)
|
146 |
|
|
|
|
|
147 |
image = processor(images=image, return_tensors="pt")
|
|
|
148 |
|
149 |
with torch.no_grad():
|
150 |
outputs = model(**image)
|
151 |
predicted_idx = torch.argmax(outputs.logits, dim=-1).item()
|
152 |
+
predicted_food_name = model.config.id2label.get(predicted_idx, None) # Get the predicted name OR None if not available
|
153 |
+
|
154 |
+
if predicted_food_name and predicted_food_name.lower() in food_name_vocabulary:
|
155 |
+
print(f"Predicted food name: {predicted_food_name.lower()}")
|
156 |
+
return predicted_food_name.lower()
|
157 |
+
else:
|
158 |
+
print(f"Predicted food name {predicted_food_name} not in dataset vocabulary.")
|
159 |
+
return None # Or some other special value like "unknown_food"
|
160 |
|
161 |
except Exception as e:
|
162 |
+
print(f"Classify food error: {e}")
|
163 |
+
return None
|
164 |
|
165 |
|
166 |
def get_food_nutrition(food_name: str, food_data, portion_size: float = 1.0) -> Optional[Dict[str, Any]]:
|
167 |
"""Get carbohydrate content for the given food""" #No USDA anymore
|
168 |
+
if food_name is None: #If food is none, immediately return None to avoid an error.
|
169 |
+
return None
|
170 |
try:
|
171 |
# First try the local CSV database
|
172 |
food_name_lower = food_name.lower() # Ensure input is also lowercase
|
|
|
381 |
|
382 |
# 1. Food Classification and Carb Calculation
|
383 |
food_name = classify_food(food_image) # This line is now inside the function
|
384 |
+
|
385 |
+
if food_name is None:
|
386 |
+
return (
|
387 |
+
"Food not recognized. Please choose a different image, or add this item to your dataset.",
|
388 |
+
"No insulin calculations available",
|
389 |
+
None,
|
390 |
+
None,
|
391 |
+
None
|
392 |
+
)
|
393 |
+
|
394 |
print(f"Classified food name: {food_name}") # Debugging: What is classified as? # Corrected indentation
|
395 |
nutrition_info = get_food_nutrition(food_name, food_data, portion_size) # Changed to pass in data
|
396 |
if not nutrition_info:
|
397 |
+
return (
|
398 |
+
f"Could not find nutrition information for: {food_name} in the local database", # Removed USDA ref
|
399 |
+
"No insulin calculations available",
|
400 |
+
None,
|
401 |
+
None,
|
402 |
+
None
|
403 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
404 |
|
405 |
# 2. Insulin Calculations
|
406 |
try:
|
|
|
650 |
|
651 |
# # trainer.save_model("food_classifier") # save locally
|
652 |
# # trainer.push_to_hub() # upload to HF Hub
|
653 |
+
|
654 |
+
# before app launch, load food name vocabulary
|
655 |
if __name__ == "__main__":
|
656 |
+
load_food_name_vocabulary()
|
657 |
app.launch(share=True)
|