Neylton commited on
Commit
08317a2
·
1 Parent(s): 5a2aacd

🚀 Major Update: 89.82% Accuracy Model + Professional UI

Browse files
Files changed (3) hide show
  1. allergen_info.json +118 -0
  2. app.py +675 -279
  3. health_info.json +157 -0
allergen_info.json ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "grilled_salmon": {
3
+ "common_allergens": ["Fish"],
4
+ "may_contain": []
5
+ },
6
+ "pizza": {
7
+ "common_allergens": ["Gluten", "Dairy", "Wheat"],
8
+ "may_contain": ["Egg", "Soy"]
9
+ },
10
+ "chicken_curry": {
11
+ "common_allergens": [],
12
+ "may_contain": ["Dairy", "Nuts"]
13
+ },
14
+ "caesar_salad": {
15
+ "common_allergens": ["Dairy", "Egg"],
16
+ "may_contain": ["Gluten", "Wheat"]
17
+ },
18
+ "hamburger": {
19
+ "common_allergens": ["Gluten", "Dairy", "Wheat"],
20
+ "may_contain": ["Egg", "Soy", "Sesame"]
21
+ },
22
+ "sushi": {
23
+ "common_allergens": ["Fish"],
24
+ "may_contain": ["Shellfish", "Soy", "Sesame"]
25
+ },
26
+ "chocolate_cake": {
27
+ "common_allergens": ["Gluten", "Dairy", "Egg", "Wheat"],
28
+ "may_contain": ["Nuts", "Soy"]
29
+ },
30
+ "french_fries": {
31
+ "common_allergens": [],
32
+ "may_contain": ["Gluten", "Wheat"]
33
+ },
34
+ "ice_cream": {
35
+ "common_allergens": ["Dairy"],
36
+ "may_contain": ["Egg", "Nuts", "Soy"]
37
+ },
38
+ "tacos": {
39
+ "common_allergens": ["Gluten", "Dairy", "Wheat"],
40
+ "may_contain": ["Soy"]
41
+ },
42
+ "steak": {
43
+ "common_allergens": [],
44
+ "may_contain": []
45
+ },
46
+ "fish_and_chips": {
47
+ "common_allergens": ["Fish", "Gluten", "Wheat"],
48
+ "may_contain": ["Egg"]
49
+ },
50
+ "shrimp_and_grits": {
51
+ "common_allergens": ["Shellfish", "Dairy"],
52
+ "may_contain": ["Gluten", "Wheat"]
53
+ },
54
+ "lobster_bisque": {
55
+ "common_allergens": ["Shellfish", "Dairy"],
56
+ "may_contain": ["Gluten", "Wheat"]
57
+ },
58
+ "crab_cakes": {
59
+ "common_allergens": ["Shellfish", "Egg", "Gluten", "Wheat"],
60
+ "may_contain": ["Dairy"]
61
+ },
62
+ "oysters": {
63
+ "common_allergens": ["Shellfish"],
64
+ "may_contain": []
65
+ },
66
+ "mussels": {
67
+ "common_allergens": ["Shellfish"],
68
+ "may_contain": []
69
+ },
70
+ "scallops": {
71
+ "common_allergens": ["Shellfish"],
72
+ "may_contain": []
73
+ },
74
+ "fried_calamari": {
75
+ "common_allergens": ["Shellfish", "Gluten", "Wheat"],
76
+ "may_contain": ["Egg"]
77
+ },
78
+ "sashimi": {
79
+ "common_allergens": ["Fish"],
80
+ "may_contain": []
81
+ },
82
+ "tuna_tartare": {
83
+ "common_allergens": ["Fish"],
84
+ "may_contain": ["Egg", "Soy"]
85
+ },
86
+ "cheese_plate": {
87
+ "common_allergens": ["Dairy"],
88
+ "may_contain": ["Nuts"]
89
+ },
90
+ "macaroni_and_cheese": {
91
+ "common_allergens": ["Gluten", "Dairy", "Wheat"],
92
+ "may_contain": ["Egg"]
93
+ },
94
+ "eggs_benedict": {
95
+ "common_allergens": ["Egg", "Dairy", "Gluten", "Wheat"],
96
+ "may_contain": []
97
+ },
98
+ "omelette": {
99
+ "common_allergens": ["Egg", "Dairy"],
100
+ "may_contain": []
101
+ },
102
+ "deviled_eggs": {
103
+ "common_allergens": ["Egg"],
104
+ "may_contain": ["Soy"]
105
+ },
106
+ "donuts": {
107
+ "common_allergens": ["Gluten", "Dairy", "Egg", "Wheat"],
108
+ "may_contain": ["Soy", "Nuts"]
109
+ },
110
+ "churros": {
111
+ "common_allergens": ["Gluten", "Wheat"],
112
+ "may_contain": ["Dairy", "Egg"]
113
+ },
114
+ "onion_rings": {
115
+ "common_allergens": ["Gluten", "Wheat"],
116
+ "may_contain": ["Dairy", "Egg"]
117
+ }
118
+ }
app.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import streamlit as st
2
  from PIL import Image
3
  import torch
@@ -10,18 +11,26 @@ import requests
10
  import json
11
  import timm
12
  import numpy as np
13
- from huggingface_hub import hf_hub_download
14
- import time
15
 
16
  # Page Configuration
17
  st.set_page_config(
18
  page_title="🍽️ EatSmart Pro - AI Food Analysis",
19
  page_icon="🍽️",
20
  layout="wide",
21
- initial_sidebar_state="expanded"
22
  )
23
 
24
- # Custom CSS for Beautiful UI
 
 
 
 
 
 
 
 
 
 
25
  st.markdown("""
26
  <style>
27
  .stApp {
@@ -30,12 +39,12 @@ st.markdown("""
30
  }
31
 
32
  .main-header {
33
- background: linear-gradient(90deg, #ff6b6b 0%, #4ecdc4 50%, #45b7d1 100%);
34
  padding: 20px;
35
  border-radius: 15px;
36
  text-align: center;
37
  margin-bottom: 20px;
38
- box-shadow: 0 8px 32px rgba(0,0,0,0.3);
39
  }
40
 
41
  .main-header h1 {
@@ -51,45 +60,45 @@ st.markdown("""
51
  margin: 10px 0 0 0;
52
  }
53
 
54
- .stTabs [data-baseweb="tab-list"] {
55
- gap: 8px;
56
- background: rgba(240,240,240,0.8);
57
- border-radius: 10px;
58
- padding: 5px;
59
- }
60
-
61
- .stTabs [data-baseweb="tab"] {
62
- background: rgba(255,255,255,0.9);
63
- border-radius: 8px;
64
- color: #333333;
65
- font-weight: bold;
66
- padding: 10px 20px;
67
  }
68
 
69
- .stTabs [aria-selected="true"] {
70
- background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
 
 
 
 
71
  color: white;
 
72
  }
73
 
74
  .info-card {
75
- background: rgba(255,255,255,0.9);
76
  backdrop-filter: blur(10px);
77
  border-radius: 15px;
78
  padding: 20px;
79
  margin: 10px 0;
80
  border: 1px solid rgba(0,0,0,0.1);
81
- box-shadow: 0 8px 32px rgba(0,0,0,0.1);
82
  color: #333333;
83
  }
84
 
85
  .metric-card {
86
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
87
  padding: 15px;
88
  border-radius: 10px;
89
  text-align: center;
90
  color: white;
91
  margin: 5px;
92
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
93
  }
94
 
95
  .metric-value {
@@ -100,80 +109,105 @@ st.markdown("""
100
 
101
  .metric-label {
102
  font-size: 0.9rem;
103
- opacity: 0.8;
104
  }
105
 
106
  .health-score-excellent {
107
- background: linear-gradient(135deg, #56ab2f 0%, #a8e6cf 100%);
108
  color: white;
109
  padding: 15px;
110
  border-radius: 10px;
111
  text-align: center;
112
  font-weight: bold;
113
  margin: 10px 0;
 
114
  }
115
 
116
  .health-score-good {
117
- background: linear-gradient(135deg, #f7971e 0%, #ffd200 100%);
118
  color: white;
119
  padding: 15px;
120
  border-radius: 10px;
121
  text-align: center;
122
  font-weight: bold;
123
  margin: 10px 0;
 
124
  }
125
 
126
  .health-score-poor {
127
- background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%);
128
  color: white;
129
  padding: 15px;
130
  border-radius: 10px;
131
  text-align: center;
132
  font-weight: bold;
133
  margin: 10px 0;
134
- }
135
-
136
- .stButton > button {
137
- background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
138
- color: white;
139
- border: none;
140
- border-radius: 25px;
141
- padding: 10px 20px;
142
- font-weight: bold;
143
- transition: all 0.3s ease;
144
- }
145
-
146
- .stButton > button:hover {
147
- transform: translateY(-2px);
148
- box-shadow: 0 5px 15px rgba(0,0,0,0.3);
149
  }
150
 
151
  .allergen-alert {
152
- background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%);
153
  color: white;
154
  padding: 15px;
155
  border-radius: 10px;
156
  margin: 10px 0;
157
- border-left: 5px solid #ff0000;
 
 
 
 
 
 
 
 
158
  }
159
 
160
  .allergen-info {
161
- background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
162
  color: white;
163
  padding: 15px;
164
  border-radius: 10px;
165
  margin: 10px 0;
166
- border-left: 5px solid #0066cc;
 
167
  }
168
 
169
  .recipe-section {
170
- background: rgba(255,255,255,0.9);
171
- border-radius: 10px;
172
- padding: 15px;
173
  margin: 10px 0;
174
- border-left: 4px solid #4ecdc4;
175
  color: #333333;
176
  border: 1px solid rgba(0,0,0,0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  }
178
  </style>
179
  """, unsafe_allow_html=True)
@@ -217,45 +251,6 @@ if 'prediction_result' not in st.session_state:
217
  st.session_state.prediction_result = None
218
 
219
  # Helper Functions
220
- def download_model_with_progress():
221
- """Download model from HF Hub with progress tracking"""
222
- try:
223
- # Show download progress
224
- progress_bar = st.progress(0)
225
- status_text = st.empty()
226
-
227
- status_text.text("🔄 Initializing model download...")
228
- progress_bar.progress(20)
229
- time.sleep(0.3)
230
-
231
- status_text.text("📥 Downloading ConvNeXt Large model (2.3GB)...")
232
- progress_bar.progress(40)
233
-
234
- # Download the model file
235
- model_path = hf_hub_download(
236
- repo_id="Lumilife/eatSmartPro-models",
237
- filename="food_classifier_convnext_large_cpu_full.pth",
238
- cache_dir="./models"
239
- )
240
-
241
- progress_bar.progress(80)
242
- status_text.text("✅ Model downloaded successfully!")
243
- time.sleep(0.3)
244
-
245
- progress_bar.progress(100)
246
- status_text.text("🚀 Loading model into memory...")
247
- time.sleep(0.3)
248
-
249
- # Clear progress indicators
250
- progress_bar.empty()
251
- status_text.empty()
252
-
253
- return model_path
254
-
255
- except Exception as e:
256
- st.error(f"❌ Failed to download model: {str(e)}")
257
- return None
258
-
259
  def get_convnext_model(num_classes):
260
  """Creates the ConvNeXt Large model architecture"""
261
  print(f"🚀 Loading ConvNeXt Large model for inference...")
@@ -264,53 +259,80 @@ def get_convnext_model(num_classes):
264
  print(f"✅ Model loaded: {total_params:,} parameters (~{total_params * 4 / 1024**2:.1f} MB)")
265
  return model
266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  @st.cache_resource
268
  def load_model_resources():
269
- """Load model with HF Hub download"""
270
  num_classes = len(CLASS_NAMES)
271
 
272
- # Check if model exists locally first
273
- local_model_path = "./models/food_classifier_convnext_large_cpu_full.pth"
 
274
 
275
- if not os.path.exists(local_model_path):
276
- st.info("🔄 First time setup: Downloading high-accuracy model...")
277
- model_path = download_model_with_progress()
278
- if not model_path:
279
- st.error("❌ Failed to download model. Please refresh the page.")
280
- return None, None
281
- else:
282
- model_path = local_model_path
283
 
284
- try:
285
- st.info("🎯 Loading ConvNeXt Large model...")
286
- model = get_convnext_model(num_classes)
287
-
288
- # Load checkpoint
289
- checkpoint = torch.load(model_path, map_location='cpu')
290
-
291
- # Handle different checkpoint formats
292
- if isinstance(checkpoint, dict):
293
- if 'model_state_dict' in checkpoint:
294
- model.load_state_dict(checkpoint['model_state_dict'], strict=False)
295
- model_info = {
296
- "name": "ConvNeXt Large",
297
- "params": "197M",
298
- "accuracy": f"{checkpoint.get('best_acc', 89.8):.1f}%"
299
- }
 
 
300
  else:
301
  model.load_state_dict(checkpoint, strict=False)
302
  model_info = {"name": "ConvNeXt Large", "params": "197M", "accuracy": "89.8%"}
303
- else:
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  model.load_state_dict(checkpoint, strict=False)
305
- model_info = {"name": "ConvNeXt Large", "params": "197M", "accuracy": "89.8%"}
306
-
307
- model.eval()
308
- st.success("✅ High-accuracy model loaded successfully!")
309
- return model, model_info
310
-
311
- except Exception as e:
312
- st.error(f"❌ Failed to load model: {str(e)}")
 
313
  return None, None
 
 
314
 
315
  def load_json_data(path):
316
  """Load JSON data with error handling"""
@@ -376,25 +398,30 @@ def get_health_score(food_name, health_data):
376
  return nutrition.get('health_score', 'Good')
377
 
378
  def get_allergen_info(food_name, allergen_data):
379
- """Get allergen information"""
380
- return allergen_data.get(food_name, {
381
  'common_allergens': [],
382
  'may_contain': []
383
  })
 
 
384
 
385
  def get_common_ingredients(food_name):
386
- """Get common ingredients for a food item"""
387
  ingredients_db = {
388
- 'grilled_salmon': ['salmon fillet', 'olive oil', 'lemon', 'herbs', 'salt', 'pepper'],
389
- 'chicken_curry': ['chicken', 'curry spices', 'coconut milk', 'onions', 'garlic', 'ginger'],
390
- 'caesar_salad': ['romaine lettuce', 'parmesan cheese', 'croutons', 'caesar dressing'],
391
- 'hamburger': ['ground beef', 'burger bun', 'lettuce', 'tomato', 'onion', 'pickles'],
392
- 'pizza': ['pizza dough', 'tomato sauce', 'mozzarella cheese', 'various toppings'],
393
- 'sushi': ['sushi rice', 'nori seaweed', 'fresh fish', 'wasabi', 'soy sauce'],
394
- 'chocolate_cake': ['flour', 'cocoa powder', 'sugar', 'eggs', 'butter', 'vanilla'],
395
  'french_fries': ['potatoes', 'oil for frying', 'salt'],
396
- 'ice_cream': ['milk', 'cream', 'sugar', 'eggs', 'flavorings'],
397
- 'tacos': ['tortillas', 'meat or beans', 'lettuce', 'tomatoes', 'cheese', 'salsa']
 
 
 
398
  }
399
 
400
  return ingredients_db.get(food_name, [
@@ -405,8 +432,7 @@ def get_common_ingredients(food_name):
405
  ])
406
 
407
  def generate_recipe(food_name):
408
- """Generate personalized recipe using free Hugging Face models"""
409
- # For now, use fallback recipe system since HF inference can be unreliable
410
  food_display = food_name.replace('_', ' ').title()
411
 
412
  dietary_restrictions = ""
@@ -424,63 +450,75 @@ def generate_recipe(food_name):
424
  return generate_fallback_recipe(food_display, dietary_restrictions, allergen_restrictions, trans_fat_note)
425
 
426
  def generate_fallback_recipe(food_display, dietary_restrictions, allergen_restrictions, trans_fat_note):
427
- """Generate a structured fallback recipe when AI models are unavailable"""
428
 
429
- # Basic recipes database for common foods
430
  recipe_templates = {
431
  'grilled_salmon': {
432
- 'ingredients': ['4 salmon fillets', '2 tbsp olive oil', '1 lemon (juiced)', 'salt and pepper', 'fresh herbs (dill or parsley)'],
433
- 'instructions': ['Preheat grill to medium-high', 'Brush salmon with olive oil', 'Season with salt, pepper, and herbs', 'Grill 4-5 minutes per side', 'Drizzle with lemon juice before serving'],
434
  'prep_time': '15 minutes',
435
- 'servings': '4'
 
436
  },
437
  'chicken_curry': {
438
- 'ingredients': ['1 lb chicken breast (cubed)', '1 onion (diced)', '2 cloves garlic', '1 tbsp curry powder', '1 can coconut milk', '1 cup vegetables'],
439
- 'instructions': ['Sauté onion and garlic', 'Add chicken and curry powder', 'Pour in coconut milk', 'Add vegetables', 'Simmer 20 minutes until tender'],
440
  'prep_time': '30 minutes',
441
- 'servings': '4'
 
442
  },
443
  'caesar_salad': {
444
- 'ingredients': ['1 head romaine lettuce', '1/4 cup parmesan cheese', '2 tbsp olive oil', '1 tbsp lemon juice', 'croutons', 'black pepper'],
445
- 'instructions': ['Wash and chop lettuce', 'Make dressing with oil and lemon', 'Toss lettuce with dressing', 'Top with cheese and croutons', 'Season with pepper'],
446
  'prep_time': '10 minutes',
447
- 'servings': '2'
 
448
  },
449
  'hamburger': {
450
- 'ingredients': ['1 lb ground beef', '4 burger buns', 'lettuce', 'tomato', 'onion', 'cheese', 'condiments'],
451
- 'instructions': ['Form beef into patties', 'Season with salt and pepper', 'Grill or pan-fry 4-5 minutes per side', 'Toast buns lightly', 'Assemble with toppings'],
452
  'prep_time': '20 minutes',
453
- 'servings': '4'
 
454
  },
455
  'pizza': {
456
- 'ingredients': ['pizza dough', 'tomato sauce', '2 cups mozzarella cheese', 'toppings of choice', 'olive oil', 'herbs'],
457
- 'instructions': ['Preheat oven to 450°F', 'Roll out dough', 'Spread sauce evenly', 'Add cheese and toppings', 'Bake 12-15 minutes until golden'],
458
  'prep_time': '25 minutes',
459
- 'servings': '4'
 
460
  }
461
  }
462
 
463
  # Get template or create generic one
464
  food_key = food_display.lower().replace(' ', '_')
465
  template = recipe_templates.get(food_key, {
466
- 'ingredients': [f'Main ingredient for {food_display}', 'Seasonings and spices', 'Healthy cooking oil', 'Fresh vegetables', 'Herbs for flavor'],
467
- 'instructions': ['Prepare all ingredients', 'Use healthy cooking methods', 'Season appropriately', 'Cook until done', 'Serve with vegetables'],
468
  'prep_time': '20-30 minutes',
469
- 'servings': '2-4'
 
470
  })
471
 
472
  # Apply dietary modifications
473
  modifications = []
474
  if 'vegan' in dietary_restrictions.lower():
475
- modifications.append("🌱 Use plant-based ingredients only")
 
 
476
  if 'keto' in dietary_restrictions.lower():
477
- modifications.append("🥑 Keep carbs under 5g per serving")
 
 
478
  if 'gluten' in allergen_restrictions.lower():
479
- modifications.append("⚠️ Use gluten-free alternatives")
 
 
480
  if trans_fat_note:
481
- modifications.append("💚 Use healthy oils (olive, avocado, coconut)")
482
 
483
- recipe = f"""**🍽️ Healthy {food_display} Recipe**
484
 
485
  **Ingredients:**
486
  {chr(10).join(f'• {ingredient}' for ingredient in template['ingredients'])}
@@ -488,20 +526,244 @@ def generate_fallback_recipe(food_display, dietary_restrictions, allergen_restri
488
  **Instructions:**
489
  {chr(10).join(f'{i+1}. {instruction}' for i, instruction in enumerate(template['instructions']))}
490
 
491
- **Chef's Tips:**
492
- Use fresh, high-quality ingredients for best flavor
493
- Adjust seasonings to your taste preferences
494
- Include colorful vegetables for added nutrition
495
- • Control portion sizes for balanced eating
496
 
497
- **Prep Time:** {template['prep_time']}
498
- **Servings:** {template['servings']}"""
 
 
 
 
499
 
500
  if modifications:
501
  recipe += f"\n\n**🎯 Your Personalized Modifications:**\n{chr(10).join(f'• {mod}' for mod in modifications)}"
502
 
503
- recipe += "\n\n*💡 Recipe generated using built-in healthy cooking database - completely free!*"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  return recipe
506
 
507
  # Main App
@@ -510,7 +772,7 @@ def main():
510
  st.markdown("""
511
  <div class="main-header">
512
  <h1>🍽️ EatSmart Pro</h1>
513
- <p>AI-Powered Food Analysis & Healthy Living Assistant</p>
514
  </div>
515
  """, unsafe_allow_html=True)
516
 
@@ -519,62 +781,82 @@ def main():
519
  health_data, allergen_data = load_data()
520
 
521
  if not model:
522
- st.error("❌ Failed to load AI model. Please refresh the page.")
523
  return
524
 
525
- # Model status
526
- st.success(f"🎯 Using {model_info['name']} model ({model_info['params']} parameters, {model_info['accuracy']} accuracy)")
 
 
 
527
 
528
- # Sidebar - User Preferences
529
  with st.sidebar:
530
- st.markdown("## 👤 Your Preferences")
 
 
 
 
 
531
 
532
- # Allergen preferences
533
- st.markdown("### ⚠️ Allergen Alerts")
534
- allergen_options = [
535
- "Gluten", "Dairy", "Egg", "Fish", "Shellfish",
536
- "Nuts", "Peanuts", "Soy", "Sesame"
537
- ]
538
 
539
- st.session_state.user_allergens = st.multiselect(
540
- "Select allergens to avoid:",
541
- allergen_options,
542
- default=st.session_state.user_allergens,
543
- help="Get alerts when these allergens are detected"
544
- )
545
 
546
- # Dietary preferences
547
- st.markdown("### 🥗 Dietary Preferences")
548
- dietary_options = [
549
- "Vegetarian", "Vegan", "Keto", "Low-Carb", "High-Protein",
550
- "Mediterranean", "Paleo", "Gluten-Free", "Dairy-Free", "Low-Sodium"
551
- ]
552
-
553
- st.session_state.dietary_preferences = st.multiselect(
554
- "Select your dietary preferences:",
555
- dietary_options,
556
- default=st.session_state.dietary_preferences,
557
- help="Personalize recipes and recommendations"
558
- )
559
 
560
  # Trans fat settings
561
  st.markdown("### 🧪 Trans Fat Settings")
562
  st.session_state.avoid_trans_fat = st.checkbox(
563
- "Alert me about trans fats",
564
  value=st.session_state.avoid_trans_fat,
565
- help="Get warnings about potentially harmful trans fats"
566
  )
567
 
568
- # App info
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  st.markdown("---")
570
- st.markdown("### 🚀 Features")
571
  st.markdown("""
572
  ✅ **High-Accuracy AI Recognition**
573
  ✅ **Comprehensive Nutrition Analysis**
574
  ✅ **Personalized Allergen Alerts**
575
- ✅ **AI-Generated Healthy Recipes**
576
  ✅ **Trans Fat Detection**
577
- ✅ **Ingredient Analysis**
578
  ✅ **Health Score Assessment**
579
  """)
580
 
@@ -582,47 +864,47 @@ def main():
582
  col1, col2 = st.columns([1, 1])
583
 
584
  with col1:
 
585
  st.markdown("""
586
- <div style="text-align: center; padding: 15px; background: linear-gradient(135deg, #ff6b6b 0%, #4ecdc4 100%); border-radius: 10px; margin-bottom: 20px;">
587
- <h3 style="color: white; margin: 0;">📸 Upload Food Image</h3>
588
- <p style="color: #f0f0f0; margin: 5px 0; font-size: 0.9em;">Take a photo or upload from gallery</p>
589
  </div>
590
  """, unsafe_allow_html=True)
591
 
592
- # Image input options
593
- input_method = st.radio(
594
- "Choose input method:",
595
- ["📁 Upload from device", "📷 Take photo with camera"],
596
- horizontal=True
 
597
  )
 
 
 
 
 
 
 
 
598
 
599
- uploaded_image = None
600
-
601
- if input_method == "📁 Upload from device":
602
- uploaded_file = st.file_uploader(
603
- "Choose a food image...",
604
- type=["jpg", "jpeg", "png"],
605
- help="Upload a clear image of your food for best results"
606
- )
607
- if uploaded_file:
608
- try:
609
- uploaded_image = uploaded_file.getvalue()
610
- st.session_state.image_buffer = uploaded_image
611
- st.success("✅ Image uploaded successfully!")
612
- except Exception as e:
613
- st.error(f"❌ Error uploading image: {str(e)}")
614
- st.info("Please try a different image format (JPG, JPEG, or PNG).")
615
 
616
- elif input_method == "📷 Take photo with camera":
617
- camera_photo = st.camera_input("Take a picture of your food")
618
- if camera_photo:
619
- try:
620
- uploaded_image = camera_photo.getvalue()
621
- st.session_state.image_buffer = uploaded_image
622
- st.success("✅ Photo captured successfully!")
623
- except Exception as e:
624
- st.error(f" Error capturing photo: {str(e)}")
625
- st.info("Please try taking the photo again.")
626
 
627
  # Display uploaded image and auto-analyze
628
  if st.session_state.image_buffer:
@@ -645,7 +927,7 @@ def main():
645
  st.session_state.prediction_result = predictions
646
  st.session_state.last_image_buffer = st.session_state.image_buffer
647
  st.session_state.last_analyzed_buffer = st.session_state.image_buffer
648
- st.success("✅ Analysis complete! Check the results on the right →")
649
  except Exception as e:
650
  st.error(f"❌ Error analyzing image: {str(e)}")
651
  st.info("Please try uploading a different image or refresh the page.")
@@ -655,23 +937,24 @@ def main():
655
  st.info("The uploaded file may be corrupted. Please try uploading again.")
656
 
657
  with col2:
 
658
  st.markdown("""
659
- <div style="text-align: center; padding: 15px; background: linear-gradient(135deg, #00b894 0%, #00a085 100%); border-radius: 10px; margin-bottom: 20px;">
660
- <h3 style="color: white; margin: 0;">🔬 Smart Analysis & Recipes</h3>
661
- <p style="color: #ddd; margin: 5px 0; font-size: 0.9em;">AI-powered nutrition insights</p>
662
  </div>
663
  """, unsafe_allow_html=True)
664
 
665
  # Show instruction if no image uploaded
666
  if not st.session_state.image_buffer:
667
- st.info("👆 Upload an image above to start the analysis!")
668
 
669
  # Display results
670
  if st.session_state.prediction_result and st.session_state.last_image_buffer == st.session_state.image_buffer:
671
  predictions = st.session_state.prediction_result
672
  top_prediction = predictions[0]
673
 
674
- # Main prediction
675
  st.markdown(f"""
676
  <div class="info-card">
677
  <h3>🎯 Food Identified</h3>
@@ -686,16 +969,16 @@ def main():
686
  for pred in predictions[1:]:
687
  st.write(f"• {pred['display_name']} ({pred['confidence']:.1f}%)")
688
 
689
- # Tabs for detailed analysis
690
- tab1, tab2, tab3 = st.tabs(["🏥 Health Info", "⚠️ Allergen Alerts", "👨‍🍳 Smart Recipes"])
691
 
692
  with tab1:
693
- # Health information
694
  food_name = top_prediction['class']
695
  nutrition = get_nutrition_info(food_name, health_data)
696
  health_score = get_health_score(food_name, health_data)
697
 
698
- # Health score
699
  score_class = f"health-score-{health_score.lower()}"
700
  st.markdown(f"""
701
  <div class="{score_class}">
@@ -703,7 +986,7 @@ def main():
703
  </div>
704
  """, unsafe_allow_html=True)
705
 
706
- # Nutrition metrics
707
  col1, col2, col3, col4 = st.columns(4)
708
 
709
  with col1:
@@ -744,17 +1027,17 @@ def main():
744
  for benefit in benefits:
745
  st.markdown(f"• {benefit}")
746
 
747
- # Common ingredients
748
  st.markdown("### 🥘 Common Ingredients")
749
  ingredients = get_common_ingredients(food_name)
750
  for ingredient in ingredients:
751
  st.markdown(f"• {ingredient}")
752
 
753
  with tab2:
754
- # Allergen information
755
  allergen_info = get_allergen_info(food_name, allergen_data)
756
 
757
- # User-specific allergen alerts
758
  user_allergens_lower = [allergen.lower() for allergen in st.session_state.user_allergens]
759
  common_allergens_lower = [allergen.lower() for allergen in allergen_info.get('common_allergens', [])]
760
  may_contain_lower = [allergen.lower() for allergen in allergen_info.get('may_contain', [])]
@@ -769,11 +1052,11 @@ def main():
769
  elif user_allergen in may_contain_lower:
770
  may_contain_matches.append(user_allergen.title())
771
 
772
- # Display alerts
773
  if allergen_matches:
774
  st.markdown(f"""
775
  <div class="allergen-alert">
776
- <h3>⚠️ ALLERGEN ALERT</h3>
777
  <p>This food contains: <strong>{', '.join(allergen_matches)}</strong></p>
778
  <p>You have marked these as allergens to avoid!</p>
779
  </div>
@@ -782,7 +1065,7 @@ def main():
782
  if may_contain_matches:
783
  st.markdown(f"""
784
  <div class="allergen-info">
785
- <h3>⚠️ May Contain</h3>
786
  <p>This food may contain: <strong>{', '.join(may_contain_matches)}</strong></p>
787
  <p>Please check ingredients carefully.</p>
788
  </div>
@@ -805,33 +1088,146 @@ def main():
805
  for allergen in allergen_info['may_contain']:
806
  st.markdown(f"• {allergen}")
807
 
808
- # Trans fat warning
809
  if st.session_state.avoid_trans_fat:
810
- trans_fat_foods = ['french_fries', 'donuts', 'fried_calamari', 'onion_rings']
811
  if food_name in trans_fat_foods:
812
  st.markdown("""
813
  <div class="allergen-alert">
814
- <h3>⚠️ TRANS FAT WARNING</h3>
815
- <p>This food may contain trans fats from frying oils.</p>
816
- <p>Consider healthier preparation methods!</p>
 
817
  </div>
818
  """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
819
 
820
  with tab3:
821
- # Recipe generation
822
- st.markdown("### 👨‍🍳 Personalized Recipe")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823
 
824
- if st.button("🍳 Generate Healthy Recipe", type="primary"):
825
- with st.spinner("👨‍🍳 AI Chef is creating your personalized recipe..."):
826
- recipe = generate_recipe(food_name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
827
 
828
- st.markdown(f"""
829
- <div class="recipe-section">
830
- {recipe}
831
- </div>
832
- """, unsafe_allow_html=True)
833
-
834
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835
 
836
  if __name__ == "__main__":
837
  main()
 
1
+ # EatSmart Pro - Professional Version with All Features
2
  import streamlit as st
3
  from PIL import Image
4
  import torch
 
11
  import json
12
  import timm
13
  import numpy as np
 
 
14
 
15
  # Page Configuration
16
  st.set_page_config(
17
  page_title="🍽️ EatSmart Pro - AI Food Analysis",
18
  page_icon="🍽️",
19
  layout="wide",
20
+ initial_sidebar_state="collapsed" # Start with sidebar closed
21
  )
22
 
23
+ # Mobile menu indicator - restored from history
24
+ st.markdown("""
25
+ <div style="display: block; background: linear-gradient(90deg, #28a745 0%, #fd7e14 50%, #007bff 100%);
26
+ padding: 8px 15px; border-radius: 8px; margin-bottom: 15px; text-align: center;">
27
+ <p style="color: white; margin: 0; font-size: 14px;">
28
+ 📱 <strong>Mobile Users:</strong> Click the <strong>></strong> arrow (top-left) to set dietary preferences
29
+ </p>
30
+ </div>
31
+ """, unsafe_allow_html=True)
32
+
33
+ # Professional CSS with better colors - green, orange, light blue theme
34
  st.markdown("""
35
  <style>
36
  .stApp {
 
39
  }
40
 
41
  .main-header {
42
+ background: linear-gradient(90deg, #28a745 0%, #fd7e14 50%, #007bff 100%);
43
  padding: 20px;
44
  border-radius: 15px;
45
  text-align: center;
46
  margin-bottom: 20px;
47
+ box-shadow: 0 8px 32px rgba(0,0,0,0.1);
48
  }
49
 
50
  .main-header h1 {
 
60
  margin: 10px 0 0 0;
61
  }
62
 
63
+ .upload-section {
64
+ background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
65
+ padding: 20px;
66
+ border-radius: 15px;
67
+ text-align: center;
68
+ margin-bottom: 20px;
69
+ color: white;
70
+ box-shadow: 0 4px 15px rgba(40, 167, 69, 0.3);
 
 
 
 
 
71
  }
72
 
73
+ .analysis-section {
74
+ background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
75
+ padding: 20px;
76
+ border-radius: 15px;
77
+ text-align: center;
78
+ margin-bottom: 20px;
79
  color: white;
80
+ box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3);
81
  }
82
 
83
  .info-card {
84
+ background: rgba(255,255,255,0.95);
85
  backdrop-filter: blur(10px);
86
  border-radius: 15px;
87
  padding: 20px;
88
  margin: 10px 0;
89
  border: 1px solid rgba(0,0,0,0.1);
90
+ box-shadow: 0 4px 20px rgba(0,0,0,0.1);
91
  color: #333333;
92
  }
93
 
94
  .metric-card {
95
+ background: linear-gradient(135deg, #20c997 0%, #17a2b8 100%);
96
  padding: 15px;
97
  border-radius: 10px;
98
  text-align: center;
99
  color: white;
100
  margin: 5px;
101
+ box-shadow: 0 4px 15px rgba(32, 201, 151, 0.3);
102
  }
103
 
104
  .metric-value {
 
109
 
110
  .metric-label {
111
  font-size: 0.9rem;
112
+ opacity: 0.9;
113
  }
114
 
115
  .health-score-excellent {
116
+ background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
117
  color: white;
118
  padding: 15px;
119
  border-radius: 10px;
120
  text-align: center;
121
  font-weight: bold;
122
  margin: 10px 0;
123
+ box-shadow: 0 4px 15px rgba(40, 167, 69, 0.3);
124
  }
125
 
126
  .health-score-good {
127
+ background: linear-gradient(135deg, #17a2b8 0%, #20c997 100%);
128
  color: white;
129
  padding: 15px;
130
  border-radius: 10px;
131
  text-align: center;
132
  font-weight: bold;
133
  margin: 10px 0;
134
+ box-shadow: 0 4px 15px rgba(23, 162, 184, 0.3);
135
  }
136
 
137
  .health-score-poor {
138
+ background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
139
  color: white;
140
  padding: 15px;
141
  border-radius: 10px;
142
  text-align: center;
143
  font-weight: bold;
144
  margin: 10px 0;
145
+ box-shadow: 0 4px 15px rgba(220, 53, 69, 0.3);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  }
147
 
148
  .allergen-alert {
149
+ background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
150
  color: white;
151
  padding: 15px;
152
  border-radius: 10px;
153
  margin: 10px 0;
154
+ border-left: 5px solid #a71e2a;
155
+ box-shadow: 0 4px 15px rgba(220, 53, 69, 0.3);
156
+ animation: pulse 2s infinite;
157
+ }
158
+
159
+ @keyframes pulse {
160
+ 0% { box-shadow: 0 4px 15px rgba(220, 53, 69, 0.3); }
161
+ 50% { box-shadow: 0 4px 25px rgba(220, 53, 69, 0.6); }
162
+ 100% { box-shadow: 0 4px 15px rgba(220, 53, 69, 0.3); }
163
  }
164
 
165
  .allergen-info {
166
+ background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
167
  color: white;
168
  padding: 15px;
169
  border-radius: 10px;
170
  margin: 10px 0;
171
+ border-left: 5px solid #004085;
172
+ box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3);
173
  }
174
 
175
  .recipe-section {
176
+ background: rgba(255,255,255,0.95);
177
+ border-radius: 15px;
178
+ padding: 20px;
179
  margin: 10px 0;
180
+ border-left: 4px solid #28a745;
181
  color: #333333;
182
  border: 1px solid rgba(0,0,0,0.1);
183
+ box-shadow: 0 4px 20px rgba(0,0,0,0.1);
184
+ }
185
+
186
+ .stButton > button {
187
+ background: linear-gradient(45deg, #28a745, #007bff);
188
+ color: white;
189
+ border: none;
190
+ border-radius: 25px;
191
+ padding: 12px 24px;
192
+ font-weight: bold;
193
+ font-size: 1.1rem;
194
+ transition: all 0.3s ease;
195
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2);
196
+ }
197
+
198
+ .stButton > button:hover {
199
+ transform: translateY(-2px);
200
+ box-shadow: 0 6px 20px rgba(0,0,0,0.3);
201
+ }
202
+
203
+ .camera-section {
204
+ background: linear-gradient(135deg, #17a2b8 0%, #20c997 100%);
205
+ padding: 15px;
206
+ border-radius: 10px;
207
+ margin: 10px 0;
208
+ text-align: center;
209
+ color: white;
210
+ box-shadow: 0 4px 15px rgba(23, 162, 184, 0.3);
211
  }
212
  </style>
213
  """, unsafe_allow_html=True)
 
251
  st.session_state.prediction_result = None
252
 
253
  # Helper Functions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  def get_convnext_model(num_classes):
255
  """Creates the ConvNeXt Large model architecture"""
256
  print(f"🚀 Loading ConvNeXt Large model for inference...")
 
259
  print(f"✅ Model loaded: {total_params:,} parameters (~{total_params * 4 / 1024**2:.1f} MB)")
260
  return model
261
 
262
+ def get_efficientnet_model(num_classes):
263
+ """Creates EfficientNet-V2-S model for fallback"""
264
+ print(f"⚠️ Loading EfficientNet-V2-S model (fallback)...")
265
+ model = models.efficientnet_v2_s(weights=None)
266
+ num_features = model.classifier[1].in_features
267
+ model.classifier = nn.Sequential(
268
+ nn.Dropout(p=0.2),
269
+ nn.Linear(num_features, 256),
270
+ nn.ReLU(),
271
+ nn.Dropout(p=0.1),
272
+ nn.Linear(256, num_classes)
273
+ )
274
+ return model
275
+
276
  @st.cache_resource
277
  def load_model_resources():
278
+ """Load model with smart detection"""
279
  num_classes = len(CLASS_NAMES)
280
 
281
+ # Try to load ConvNeXt Large model first
282
+ convnext_path = "models/food_classifier_convnext_large_cpu_full.pth"
283
+ efficientnet_path = "models/food101_efficientnet_best.pth"
284
 
285
+ model = None
286
+ model_info = {"name": "Unknown", "params": 0, "accuracy": "Unknown"}
 
 
 
 
 
 
287
 
288
+ if os.path.exists(convnext_path):
289
+ try:
290
+ print("🎯 Loading ConvNeXt Large model...")
291
+ model = get_convnext_model(num_classes)
292
+ checkpoint = torch.load(convnext_path, map_location='cpu')
293
+
294
+ # Handle different checkpoint formats
295
+ if isinstance(checkpoint, dict):
296
+ if 'model_state_dict' in checkpoint:
297
+ model.load_state_dict(checkpoint['model_state_dict'], strict=False)
298
+ model_info = {
299
+ "name": "ConvNeXt Large",
300
+ "params": "197M",
301
+ "accuracy": f"{checkpoint.get('best_acc', 89.8):.1f}%"
302
+ }
303
+ else:
304
+ model.load_state_dict(checkpoint, strict=False)
305
+ model_info = {"name": "ConvNeXt Large", "params": "197M", "accuracy": "89.8%"}
306
  else:
307
  model.load_state_dict(checkpoint, strict=False)
308
  model_info = {"name": "ConvNeXt Large", "params": "197M", "accuracy": "89.8%"}
309
+
310
+ model.eval()
311
+ print("✅ ConvNeXt Large model loaded successfully!")
312
+
313
+ except Exception as e:
314
+ print(f"❌ Failed to load ConvNeXt model: {e}")
315
+ model = None
316
+
317
+ # Fallback to EfficientNet if ConvNeXt fails
318
+ if model is None and os.path.exists(efficientnet_path):
319
+ try:
320
+ print("🔄 Loading EfficientNet-V2-S model (fallback)...")
321
+ model = get_efficientnet_model(num_classes)
322
+ checkpoint = torch.load(efficientnet_path, map_location='cpu')
323
  model.load_state_dict(checkpoint, strict=False)
324
+ model.eval()
325
+ model_info = {"name": "EfficientNet-V2-S", "params": "21M", "accuracy": "85.2%"}
326
+ print("✅ EfficientNet model loaded successfully!")
327
+ except Exception as e:
328
+ print(f"❌ Failed to load EfficientNet model: {e}")
329
+ model = None
330
+
331
+ if model is None:
332
+ st.error("❌ No model could be loaded. Please check model files.")
333
  return None, None
334
+
335
+ return model, model_info
336
 
337
  def load_json_data(path):
338
  """Load JSON data with error handling"""
 
398
  return nutrition.get('health_score', 'Good')
399
 
400
  def get_allergen_info(food_name, allergen_data):
401
+ """Get allergen information with enhanced user-specific alerts"""
402
+ allergen_info = allergen_data.get(food_name, {
403
  'common_allergens': [],
404
  'may_contain': []
405
  })
406
+
407
+ return allergen_info
408
 
409
  def get_common_ingredients(food_name):
410
+ """Get common ingredients for a food item with enhanced protein focus"""
411
  ingredients_db = {
412
+ 'grilled_salmon': ['salmon fillet (high protein)', 'olive oil', 'lemon', 'herbs', 'salt', 'pepper'],
413
+ 'chicken_curry': ['chicken breast (high protein)', 'curry spices', 'coconut milk', 'onions', 'garlic', 'ginger'],
414
+ 'caesar_salad': ['romaine lettuce', 'parmesan cheese (protein)', 'croutons', 'caesar dressing'],
415
+ 'hamburger': ['ground beef (high protein)', 'burger bun', 'lettuce', 'tomato', 'onion', 'pickles'],
416
+ 'pizza': ['pizza dough', 'tomato sauce', 'mozzarella cheese (protein)', 'various toppings'],
417
+ 'sushi': ['sushi rice', 'nori seaweed', 'fresh fish (high protein)', 'wasabi', 'soy sauce'],
418
+ 'chocolate_cake': ['flour', 'cocoa powder', 'sugar', 'eggs (protein)', 'butter', 'vanilla'],
419
  'french_fries': ['potatoes', 'oil for frying', 'salt'],
420
+ 'ice_cream': ['milk (protein)', 'cream', 'sugar', 'eggs (protein)', 'flavorings'],
421
+ 'tacos': ['tortillas', 'meat or beans (protein)', 'lettuce', 'tomatoes', 'cheese (protein)', 'salsa'],
422
+ 'steak': ['beef steak (very high protein)', 'seasonings', 'cooking oil'],
423
+ 'eggs_benedict': ['eggs (high protein)', 'english muffin', 'canadian bacon (protein)', 'hollandaise sauce'],
424
+ 'greek_salad': ['lettuce', 'tomatoes', 'feta cheese (protein)', 'olives', 'olive oil', 'herbs']
425
  }
426
 
427
  return ingredients_db.get(food_name, [
 
432
  ])
433
 
434
  def generate_recipe(food_name):
435
+ """Generate personalized recipe using built-in database"""
 
436
  food_display = food_name.replace('_', ' ').title()
437
 
438
  dietary_restrictions = ""
 
450
  return generate_fallback_recipe(food_display, dietary_restrictions, allergen_restrictions, trans_fat_note)
451
 
452
  def generate_fallback_recipe(food_display, dietary_restrictions, allergen_restrictions, trans_fat_note):
453
+ """Generate a structured recipe with professional formatting"""
454
 
455
+ # Enhanced recipes database with more variety
456
  recipe_templates = {
457
  'grilled_salmon': {
458
+ 'ingredients': ['4 salmon fillets (6 oz each)', '2 tbsp extra virgin olive oil', '1 lemon (juiced)', 'fresh dill or parsley', 'sea salt and black pepper', 'garlic powder'],
459
+ 'instructions': ['Preheat grill to medium-high heat', 'Pat salmon dry and brush with olive oil', 'Season generously with salt, pepper, and garlic powder', 'Grill 4-5 minutes per side until flakes easily', 'Garnish with fresh herbs and lemon juice'],
460
  'prep_time': '15 minutes',
461
+ 'servings': '4',
462
+ 'protein_content': 'Very High (35g per serving)'
463
  },
464
  'chicken_curry': {
465
+ 'ingredients': ['1 lb chicken breast (cubed)', '1 large onion (diced)', '3 cloves garlic (minced)', '1 tbsp curry powder', '1 can coconut milk', '1 cup mixed vegetables', 'ginger', 'cilantro'],
466
+ 'instructions': ['Heat oil in large pan over medium heat', 'Sauté onion and garlic until fragrant', 'Add chicken and curry powder, cook until browned', 'Pour in coconut milk and simmer', 'Add vegetables and cook 15-20 minutes until tender'],
467
  'prep_time': '30 minutes',
468
+ 'servings': '4',
469
+ 'protein_content': 'High (28g per serving)'
470
  },
471
  'caesar_salad': {
472
+ 'ingredients': ['1 large head romaine lettuce', '1/3 cup parmesan cheese (grated)', '2 tbsp olive oil', '1 tbsp lemon juice', 'whole grain croutons', 'black pepper', 'caesar dressing'],
473
+ 'instructions': ['Wash and chop lettuce into bite-sized pieces', 'Make dressing with oil, lemon, and seasonings', 'Toss lettuce with dressing until well coated', 'Top with parmesan cheese and croutons', 'Season with fresh black pepper'],
474
  'prep_time': '10 minutes',
475
+ 'servings': '2-3',
476
+ 'protein_content': 'Moderate (8g per serving)'
477
  },
478
  'hamburger': {
479
+ 'ingredients': ['1 lb lean ground beef (80/20)', '4 whole grain burger buns', 'lettuce leaves', '2 tomatoes (sliced)', '1 onion (sliced)', 'pickles', 'low-fat cheese (optional)'],
480
+ 'instructions': ['Form beef into 4 equal patties', 'Season with salt and pepper', 'Grill or pan-cook 4-5 minutes per side', 'Toast buns lightly on grill', 'Assemble with fresh vegetables and condiments'],
481
  'prep_time': '20 minutes',
482
+ 'servings': '4',
483
+ 'protein_content': 'Very High (25g per serving)'
484
  },
485
  'pizza': {
486
+ 'ingredients': ['whole wheat pizza dough', 'tomato sauce (low sodium)', '1.5 cups mozzarella cheese', 'vegetables of choice', 'olive oil', 'Italian herbs', 'fresh basil'],
487
+ 'instructions': ['Preheat oven to 450°F (230°C)', 'Roll out dough on floured surface', 'Spread sauce evenly, leaving border for crust', 'Add cheese and favorite toppings', 'Bake 12-15 minutes until golden and bubbly'],
488
  'prep_time': '25 minutes',
489
+ 'servings': '4',
490
+ 'protein_content': 'Moderate (15g per serving)'
491
  }
492
  }
493
 
494
  # Get template or create generic one
495
  food_key = food_display.lower().replace(' ', '_')
496
  template = recipe_templates.get(food_key, {
497
+ 'ingredients': [f'Main protein source for {food_display}', 'Fresh vegetables', 'Healthy seasonings', 'Quality cooking oil', 'Herbs and spices'],
498
+ 'instructions': ['Prepare all ingredients fresh', 'Use healthy cooking methods (grill, bake, steam)', 'Season with herbs instead of excess salt', 'Cook until properly done', 'Serve with colorful vegetables'],
499
  'prep_time': '20-30 minutes',
500
+ 'servings': '2-4',
501
+ 'protein_content': 'Varies by ingredients'
502
  })
503
 
504
  # Apply dietary modifications
505
  modifications = []
506
  if 'vegan' in dietary_restrictions.lower():
507
+ modifications.append("🌱 Replace animal proteins with plant-based alternatives (tofu, tempeh, legumes)")
508
+ if 'vegetarian' in dietary_restrictions.lower():
509
+ modifications.append("🥬 Use vegetarian protein sources (eggs, dairy, plant proteins)")
510
  if 'keto' in dietary_restrictions.lower():
511
+ modifications.append("🥑 Keep carbs under 5g per serving, increase healthy fats")
512
+ if 'high-protein' in dietary_restrictions.lower():
513
+ modifications.append("💪 Add extra protein sources to reach 25g+ per serving")
514
  if 'gluten' in allergen_restrictions.lower():
515
+ modifications.append("⚠️ Use certified gluten-free alternatives for all grains")
516
+ if 'dairy' in allergen_restrictions.lower():
517
+ modifications.append("🥛 Replace dairy with plant-based alternatives (almond, oat milk)")
518
  if trans_fat_note:
519
+ modifications.append("💚 Use only healthy oils: olive, avocado, or coconut oil")
520
 
521
+ recipe = f"""**🍽️ Professional {food_display} Recipe**
522
 
523
  **Ingredients:**
524
  {chr(10).join(f'• {ingredient}' for ingredient in template['ingredients'])}
 
526
  **Instructions:**
527
  {chr(10).join(f'{i+1}. {instruction}' for i, instruction in enumerate(template['instructions']))}
528
 
529
+ **Nutritional Highlights:**
530
+ **Protein Content:** {template['protein_content']}
531
+ **Prep Time:** {template['prep_time']}
532
+ **Servings:** {template['servings']}
 
533
 
534
+ **Chef's Professional Tips:**
535
+ Use the freshest ingredients available for optimal flavor
536
+ • Control portion sizes for balanced nutrition
537
+ • Include a variety of colorful vegetables for micronutrients
538
+ • Season gradually and taste as you go
539
+ • Let proteins rest before serving for better texture"""
540
 
541
  if modifications:
542
  recipe += f"\n\n**🎯 Your Personalized Modifications:**\n{chr(10).join(f'• {mod}' for mod in modifications)}"
543
 
544
+ recipe += "\n\n*💡 Recipe crafted using professional culinary database - completely free and personalized!*"
545
+
546
+ return recipe
547
+
548
+ def generate_multiple_recipes(food_name):
549
+ """Generate 3 different recipe variations with food images"""
550
+ food_display = food_name.replace('_', ' ').title()
551
+
552
+ # Initialize recipe count in session state
553
+ if 'recipe_count' not in st.session_state:
554
+ st.session_state.recipe_count = 0
555
+ if 'generated_recipes' not in st.session_state:
556
+ st.session_state.generated_recipes = []
557
+
558
+ # Food images URLs - FIXED with correct food-specific images
559
+ food_images = {
560
+ 'grilled_salmon': [
561
+ 'https://images.unsplash.com/photo-1467003909585-2f8a72700288?w=300&h=200&fit=crop&auto=format',
562
+ 'https://images.unsplash.com/photo-1519708227418-c8fd9a32b7a2?w=300&h=200&fit=crop&auto=format',
563
+ 'https://images.unsplash.com/photo-1485704686097-ed47f7263ca4?w=300&h=200&fit=crop&auto=format',
564
+ 'https://images.unsplash.com/photo-1544943910-4c1dc44aab44?w=300&h=200&fit=crop&auto=format',
565
+ 'https://images.unsplash.com/photo-1559847844-d721426d6edc?w=300&h=200&fit=crop&auto=format',
566
+ 'https://images.unsplash.com/photo-1553979459-d2229ba7433a?w=300&h=200&fit=crop&auto=format',
567
+ 'https://images.unsplash.com/photo-1478145046317-39f10e56b5e9?w=300&h=200&fit=crop&auto=format',
568
+ 'https://images.unsplash.com/photo-1535140728325-781d5ecd3e95?w=300&h=200&fit=crop&auto=format',
569
+ 'https://images.unsplash.com/photo-1546833999-b9f581a1996d?w=300&h=200&fit=crop&auto=format'
570
+ ],
571
+ 'steak': [
572
+ 'https://images.unsplash.com/photo-1546833999-b9f581a1996d?w=300&h=200&fit=crop&auto=format&q=80',
573
+ 'https://images.unsplash.com/photo-1558030006-450675393462?w=300&h=200&fit=crop&auto=format&q=80',
574
+ 'https://images.unsplash.com/photo-1544025162-d76694265947?w=300&h=200&fit=crop&auto=format&q=80',
575
+ 'https://images.unsplash.com/photo-1504973960431-1c467e159aa4?w=300&h=200&fit=crop&auto=format&q=80',
576
+ 'https://images.unsplash.com/photo-1615937691194-97ddb5266e4a?w=300&h=200&fit=crop&auto=format&q=80',
577
+ 'https://images.unsplash.com/photo-1603360946369-dc9bb6258143?w=300&h=200&fit=crop&auto=format&q=80',
578
+ 'https://images.unsplash.com/photo-1529692236671-f1f6cf9683ba?w=300&h=200&fit=crop&auto=format&q=80',
579
+ 'https://images.unsplash.com/photo-1551782450-17144efb9c50?w=300&h=200&fit=crop&auto=format&q=80',
580
+ 'https://images.unsplash.com/photo-1572802419224-296b0aeee0d9?w=300&h=200&fit=crop&auto=format&q=80'
581
+ ],
582
+ 'pizza': [
583
+ 'https://images.unsplash.com/photo-1513104890138-7c749659a591?w=300&h=200&fit=crop&auto=format',
584
+ 'https://images.unsplash.com/photo-1565299624946-b28f40a0ca4b?w=300&h=200&fit=crop&auto=format',
585
+ 'https://images.unsplash.com/photo-1571407970349-bc81e7e96d47?w=300&h=200&fit=crop&auto=format',
586
+ 'https://images.unsplash.com/photo-1574071318508-1cdbab80d002?w=300&h=200&fit=crop&auto=format',
587
+ 'https://images.unsplash.com/photo-1506354666786-959d6d497f1a?w=300&h=200&fit=crop&auto=format',
588
+ 'https://images.unsplash.com/photo-1593560708920-61dd98c46a4e?w=300&h=200&fit=crop&auto=format',
589
+ 'https://images.unsplash.com/photo-1628840042765-356cda07504e?w=300&h=200&fit=crop&auto=format',
590
+ 'https://images.unsplash.com/photo-1585238342024-78d387f4a707?w=300&h=200&fit=crop&auto=format',
591
+ 'https://images.unsplash.com/photo-1571407970349-bc81e7e96d47?w=300&h=200&fit=crop&auto=format'
592
+ ],
593
+ 'chicken_curry': [
594
+ 'https://images.unsplash.com/photo-1565557623262-b51c2513a641?w=300&h=200&fit=crop&auto=format',
595
+ 'https://images.unsplash.com/photo-1574484284002-952d92456975?w=300&h=200&fit=crop&auto=format',
596
+ 'https://images.unsplash.com/photo-1588166524941-3bf61a9c41db?w=300&h=200&fit=crop&auto=format',
597
+ 'https://images.unsplash.com/photo-1631452180539-96aca7d48617?w=300&h=200&fit=crop&auto=format',
598
+ 'https://images.unsplash.com/photo-1565299585323-38174c5f1b8b?w=300&h=200&fit=crop&auto=format',
599
+ 'https://images.unsplash.com/photo-1603894584373-5ac82b2ae398?w=300&h=200&fit=crop&auto=format',
600
+ 'https://images.unsplash.com/photo-1627662168223-7df99068099a?w=300&h=200&fit=crop&auto=format',
601
+ 'https://images.unsplash.com/photo-1574484284002-952d92456975?w=300&h=200&fit=crop&auto=format',
602
+ 'https://images.unsplash.com/photo-1588166524941-3bf61a9c41db?w=300&h=200&fit=crop&auto=format'
603
+ ],
604
+ 'hamburger': [
605
+ 'https://images.unsplash.com/photo-1568901346375-23c9450c58cd?w=300&h=200&fit=crop&auto=format',
606
+ 'https://images.unsplash.com/photo-1550547660-d9450f859349?w=300&h=200&fit=crop&auto=format',
607
+ 'https://images.unsplash.com/photo-1571091718767-18b5b1457add?w=300&h=200&fit=crop&auto=format',
608
+ 'https://images.unsplash.com/photo-1553979459-d2229ba7433a?w=300&h=200&fit=crop&auto=format',
609
+ 'https://images.unsplash.com/photo-1572802419224-296b0aeee0d9?w=300&h=200&fit=crop&auto=format',
610
+ 'https://images.unsplash.com/photo-1594212699903-ec8a3eca50f5?w=300&h=200&fit=crop&auto=format',
611
+ 'https://images.unsplash.com/photo-1586816001966-79b736744398?w=300&h=200&fit=crop&auto=format',
612
+ 'https://images.unsplash.com/photo-1551782450-17144efb9c50?w=300&h=200&fit=crop&auto=format',
613
+ 'https://images.unsplash.com/photo-1565299624946-b28f40a0ca4b?w=300&h=200&fit=crop&auto=format'
614
+ ],
615
+ 'default': [
616
+ 'https://images.unsplash.com/photo-1546793665-c74683f339c1?w=300&h=200&fit=crop&auto=format',
617
+ 'https://images.unsplash.com/photo-1565299624946-b28f40a0ca4b?w=300&h=200&fit=crop&auto=format',
618
+ 'https://images.unsplash.com/photo-1504674900247-0877df9cc836?w=300&h=200&fit=crop&auto=format',
619
+ 'https://images.unsplash.com/photo-1555939594-58d7cb561ad1?w=300&h=200&fit=crop&auto=format',
620
+ 'https://images.unsplash.com/photo-1567620905732-2d1ec7ab7445?w=300&h=200&fit=crop&auto=format',
621
+ 'https://images.unsplash.com/photo-1482049016688-2d3e1b311543?w=300&h=200&fit=crop&auto=format',
622
+ 'https://images.unsplash.com/photo-1540189549336-e6e99c3679fe?w=300&h=200&fit=crop&auto=format',
623
+ 'https://images.unsplash.com/photo-1559847844-d721426d6edc?w=300&h=200&fit=crop&auto=format',
624
+ 'https://images.unsplash.com/photo-1565299624946-b28f40a0ca4b?w=300&h=200&fit=crop&auto=format'
625
+ ]
626
+ }
627
+
628
+ # Get images for this food or use default
629
+ images = food_images.get(food_name, food_images['default'])
630
+
631
+ # Generate recipe styles based on current count
632
+ recipe_styles = ['healthy', 'quick', 'gourmet', 'traditional', 'fusion', 'low-carb', 'protein-rich', 'vegetarian', 'spicy']
633
+
634
+ # Generate 3 different recipe styles
635
+ recipes = []
636
+ start_idx = st.session_state.recipe_count
637
+
638
+ for i in range(3):
639
+ style_idx = (start_idx + i) % len(recipe_styles)
640
+ style = recipe_styles[style_idx]
641
+ image_idx = (start_idx + i) % len(images)
642
+
643
+ recipes.append({
644
+ 'title': f'{style.title()} {food_display}',
645
+ 'image_url': images[image_idx],
646
+ 'recipe': generate_recipe_variation(food_display, style)
647
+ })
648
+
649
+ # Update recipe count
650
+ st.session_state.recipe_count += 3
651
+
652
+ return recipes
653
+
654
+ def generate_recipe_variation(food_display, style):
655
+ """Generate a recipe variation based on style"""
656
 
657
+ dietary_restrictions = ""
658
+ if st.session_state.dietary_preferences:
659
+ dietary_restrictions = f"Make it {', '.join(st.session_state.dietary_preferences).lower()}. "
660
+
661
+ allergen_restrictions = ""
662
+ if st.session_state.user_allergens:
663
+ allergen_restrictions = f"Avoid using {', '.join(st.session_state.user_allergens).lower()}. "
664
+
665
+ trans_fat_note = ""
666
+ if st.session_state.avoid_trans_fat:
667
+ trans_fat_note = "Use only healthy oils and avoid trans fats. "
668
+
669
+ # Expanded style-specific modifications
670
+ style_modifications = {
671
+ 'healthy': {
672
+ 'prefix': '🥗 **HEALTHY VERSION**',
673
+ 'cooking_methods': ['grilled', 'baked', 'steamed', 'air-fried'],
674
+ 'ingredients_focus': 'organic and fresh ingredients',
675
+ 'special_notes': 'Low sodium, high fiber, nutrient-dense preparation',
676
+ 'prep_time': 25,
677
+ 'difficulty': 2
678
+ },
679
+ 'quick': {
680
+ 'prefix': '⚡ **QUICK & EASY VERSION**',
681
+ 'cooking_methods': ['pan-seared', 'stir-fried', 'microwaved', 'one-pot'],
682
+ 'ingredients_focus': 'simple and accessible ingredients',
683
+ 'special_notes': 'Ready in 15-20 minutes, minimal prep time',
684
+ 'prep_time': 15,
685
+ 'difficulty': 1
686
+ },
687
+ 'gourmet': {
688
+ 'prefix': '🌟 **GOURMET VERSION**',
689
+ 'cooking_methods': ['sous-vide', 'braised', 'roasted', 'flambéed'],
690
+ 'ingredients_focus': 'premium and artisanal ingredients',
691
+ 'special_notes': 'Restaurant-quality presentation and techniques',
692
+ 'prep_time': 45,
693
+ 'difficulty': 4
694
+ },
695
+ 'traditional': {
696
+ 'prefix': '🏛️ **TRADITIONAL VERSION**',
697
+ 'cooking_methods': ['slow-cooked', 'braised', 'roasted', 'simmered'],
698
+ 'ingredients_focus': 'classic and time-tested ingredients',
699
+ 'special_notes': 'Authentic preparation methods passed down through generations',
700
+ 'prep_time': 60,
701
+ 'difficulty': 3
702
+ },
703
+ 'fusion': {
704
+ 'prefix': '🌍 **FUSION VERSION**',
705
+ 'cooking_methods': ['stir-fried', 'grilled', 'pan-seared', 'wok-tossed'],
706
+ 'ingredients_focus': 'international spices and modern techniques',
707
+ 'special_notes': 'Creative blend of culinary traditions and flavors',
708
+ 'prep_time': 30,
709
+ 'difficulty': 3
710
+ },
711
+ 'low-carb': {
712
+ 'prefix': '🥑 **LOW-CARB VERSION**',
713
+ 'cooking_methods': ['grilled', 'sautéed', 'roasted', 'steamed'],
714
+ 'ingredients_focus': 'high-protein, low-carbohydrate ingredients',
715
+ 'special_notes': 'Under 10g carbs per serving, keto-friendly',
716
+ 'prep_time': 20,
717
+ 'difficulty': 2
718
+ },
719
+ 'protein-rich': {
720
+ 'prefix': '💪 **HIGH-PROTEIN VERSION**',
721
+ 'cooking_methods': ['grilled', 'baked', 'pan-seared', 'broiled'],
722
+ 'ingredients_focus': 'lean proteins and muscle-building nutrients',
723
+ 'special_notes': '25g+ protein per serving, perfect for fitness goals',
724
+ 'prep_time': 25,
725
+ 'difficulty': 2
726
+ },
727
+ 'vegetarian': {
728
+ 'prefix': '🌱 **VEGETARIAN VERSION**',
729
+ 'cooking_methods': ['roasted', 'sautéed', 'grilled', 'steamed'],
730
+ 'ingredients_focus': 'plant-based proteins and fresh vegetables',
731
+ 'special_notes': 'No meat, rich in plant proteins and nutrients',
732
+ 'prep_time': 30,
733
+ 'difficulty': 2
734
+ },
735
+ 'spicy': {
736
+ 'prefix': '🌶️ **SPICY VERSION**',
737
+ 'cooking_methods': ['stir-fried', 'grilled', 'blackened', 'seared'],
738
+ 'ingredients_focus': 'hot peppers, spices, and bold flavors',
739
+ 'special_notes': 'Heat level: Medium to Hot, full of flavor',
740
+ 'prep_time': 20,
741
+ 'difficulty': 2
742
+ }
743
+ }
744
+
745
+ style_info = style_modifications.get(style, style_modifications['healthy'])
746
+
747
+ recipe = f"""{style_info['prefix']}
748
+
749
+ **Cooking Method:** {', '.join(style_info['cooking_methods']).title()}
750
+ **Focus:** {style_info['ingredients_focus'].title()}
751
+
752
+ **Key Features:**
753
+ • {style_info['special_notes']}
754
+ • {dietary_restrictions.strip() if dietary_restrictions else 'Customizable to your dietary needs'}
755
+ • {allergen_restrictions.strip() if allergen_restrictions else 'Allergen-conscious preparation'}
756
+ • {trans_fat_note.strip() if trans_fat_note else 'Heart-healthy cooking methods'}
757
+
758
+ **Professional Tips:**
759
+ • Use high-quality, fresh ingredients for best results
760
+ • Season gradually and taste as you cook
761
+ • Control portion sizes for balanced nutrition
762
+ • Pair with colorful vegetables for complete nutrition
763
+
764
+ **Prep Time:** {style_info['prep_time']} minutes
765
+ **Difficulty:** {style_info['difficulty']}/5 stars"""
766
+
767
  return recipe
768
 
769
  # Main App
 
772
  st.markdown("""
773
  <div class="main-header">
774
  <h1>🍽️ EatSmart Pro</h1>
775
+ <p>🌟 Your AI-Powered Nutrition Assistant 🌟</p>
776
  </div>
777
  """, unsafe_allow_html=True)
778
 
 
781
  health_data, allergen_data = load_data()
782
 
783
  if not model:
784
+ st.error("❌ Failed to load AI model. Please check the setup.")
785
  return
786
 
787
+ # Model status with professional styling
788
+ if model_info["name"] == "ConvNeXt Large":
789
+ st.success(f"🎯 **HIGH ACCURACY MODEL ACTIVE** | {model_info['name']} ({model_info['params']} parameters, {model_info['accuracy']} accuracy)")
790
+ else:
791
+ st.warning(f"⚠️ Using {model_info['name']} model ({model_info['params']} parameters, {model_info['accuracy']} accuracy)")
792
 
793
+ # Professional Sidebar - Enhanced from chat history
794
  with st.sidebar:
795
+ st.markdown("""
796
+ <div style="text-align: center; padding: 15px; background: linear-gradient(135deg, #28a745 0%, #007bff 100%); border-radius: 10px; margin-bottom: 20px;">
797
+ <h3 style="color: white; margin: 0;">⚙️ Your Preferences</h3>
798
+ <p style="color: #f8f9fa; margin: 5px 0; font-size: 0.9em;">Personalize your analysis</p>
799
+ </div>
800
+ """, unsafe_allow_html=True)
801
 
802
+ # Allergen preferences with enhanced UI from history
803
+ st.markdown("### 🚨 Allergen Alerts")
804
+ st.markdown("*Select allergens you want to be warned about:*")
 
 
 
805
 
806
+ allergen_options = ["Gluten", "Dairy", "Egg", "Fish", "Shellfish", "Nuts", "Peanuts", "Soy", "Sesame", "Wheat"]
 
 
 
 
 
807
 
808
+ # Enhanced allergen selection from chat history
809
+ for allergen in allergen_options:
810
+ if st.checkbox(f"🔴 {allergen}", key=f"allergen_{allergen}",
811
+ value=allergen in st.session_state.user_allergens):
812
+ if allergen not in st.session_state.user_allergens:
813
+ st.session_state.user_allergens.append(allergen)
814
+ else:
815
+ if allergen in st.session_state.user_allergens:
816
+ st.session_state.user_allergens.remove(allergen)
 
 
 
 
817
 
818
  # Trans fat settings
819
  st.markdown("### 🧪 Trans Fat Settings")
820
  st.session_state.avoid_trans_fat = st.checkbox(
821
+ "⚠️ Alert me about trans fats",
822
  value=st.session_state.avoid_trans_fat,
823
+ help="Get warnings about foods that may contain trans fats"
824
  )
825
 
826
+ # Enhanced dietary preferences from history
827
+ st.markdown("### 🌱 Dietary Preferences")
828
+ dietary_options = ["Vegetarian", "Vegan", "Keto", "Low-Carb", "High-Protein", "Mediterranean", "Paleo", "Gluten-Free", "Dairy-Free", "Low-Sodium"]
829
+
830
+ for diet in dietary_options:
831
+ if st.checkbox(f"🥬 {diet}", key=f"diet_{diet}",
832
+ value=diet in st.session_state.dietary_preferences):
833
+ if diet not in st.session_state.dietary_preferences:
834
+ st.session_state.dietary_preferences.append(diet)
835
+ else:
836
+ if diet in st.session_state.dietary_preferences:
837
+ st.session_state.dietary_preferences.remove(diet)
838
+
839
+ # Active preferences summary from history
840
+ if st.session_state.user_allergens or st.session_state.dietary_preferences or st.session_state.avoid_trans_fat:
841
+ st.markdown("---")
842
+ st.markdown("### 📋 Active Preferences")
843
+ if st.session_state.user_allergens:
844
+ st.markdown(f"🚨 **Allergen Alerts:** {', '.join(st.session_state.user_allergens)}")
845
+ if st.session_state.dietary_preferences:
846
+ st.markdown(f"🌱 **Diet:** {', '.join(st.session_state.dietary_preferences)}")
847
+ if st.session_state.avoid_trans_fat:
848
+ st.markdown("🧪 **Trans Fat Alerts:** Enabled")
849
+
850
+ # Professional features list
851
  st.markdown("---")
852
+ st.markdown("### 🚀 Professional Features")
853
  st.markdown("""
854
  ✅ **High-Accuracy AI Recognition**
855
  ✅ **Comprehensive Nutrition Analysis**
856
  ✅ **Personalized Allergen Alerts**
857
+ ✅ **Professional Recipe Generation**
858
  ✅ **Trans Fat Detection**
859
+ ✅ **Protein Content Analysis**
860
  ✅ **Health Score Assessment**
861
  """)
862
 
 
864
  col1, col2 = st.columns([1, 1])
865
 
866
  with col1:
867
+ # Professional upload section
868
  st.markdown("""
869
+ <div class="upload-section">
870
+ <h3 style="margin: 0;">📸 Upload Food Image</h3>
871
+ <p style="margin: 5px 0; font-size: 0.9em;">Choose your preferred method below</p>
872
  </div>
873
  """, unsafe_allow_html=True)
874
 
875
+ # File upload - no radio buttons as requested
876
+ st.markdown("#### 📁 Browse Files")
877
+ uploaded_file = st.file_uploader(
878
+ "Choose a food image from your device...",
879
+ type=["jpg", "jpeg", "png"],
880
+ help="Upload a clear image of your food for best results"
881
  )
882
+ if uploaded_file:
883
+ try:
884
+ uploaded_image = uploaded_file.getvalue()
885
+ st.session_state.image_buffer = uploaded_image
886
+ st.success("✅ Image uploaded successfully!")
887
+ except Exception as e:
888
+ st.error(f"❌ Error uploading image: {str(e)}")
889
+ st.info("Please try a different image format (JPG, JPEG, or PNG).")
890
 
891
+ # Camera functionality - restored from history
892
+ st.markdown("#### 📷 Take Photo")
893
+ st.markdown("""
894
+ <div class="camera-section">
895
+ <p style="margin: 5px 0;">Use your device camera to capture food</p>
896
+ </div>
897
+ """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
898
 
899
+ camera_photo = st.camera_input("Take a picture of your food")
900
+ if camera_photo:
901
+ try:
902
+ uploaded_image = camera_photo.getvalue()
903
+ st.session_state.image_buffer = uploaded_image
904
+ st.success("✅ Photo captured successfully!")
905
+ except Exception as e:
906
+ st.error(f"❌ Error capturing photo: {str(e)}")
907
+ st.info("Please try taking the photo again.")
 
908
 
909
  # Display uploaded image and auto-analyze
910
  if st.session_state.image_buffer:
 
927
  st.session_state.prediction_result = predictions
928
  st.session_state.last_image_buffer = st.session_state.image_buffer
929
  st.session_state.last_analyzed_buffer = st.session_state.image_buffer
930
+ st.success("✅ Analysis complete! Ready for checking")
931
  except Exception as e:
932
  st.error(f"❌ Error analyzing image: {str(e)}")
933
  st.info("Please try uploading a different image or refresh the page.")
 
937
  st.info("The uploaded file may be corrupted. Please try uploading again.")
938
 
939
  with col2:
940
+ # Professional analysis section
941
  st.markdown("""
942
+ <div class="analysis-section">
943
+ <h3 style="margin: 0;">🔬 Smart Analysis & Insights</h3>
944
+ <p style="margin: 5px 0; font-size: 0.9em;">AI-powered nutrition analysis</p>
945
  </div>
946
  """, unsafe_allow_html=True)
947
 
948
  # Show instruction if no image uploaded
949
  if not st.session_state.image_buffer:
950
+ st.info("👆 Upload an image or take a photo above to start the analysis!")
951
 
952
  # Display results
953
  if st.session_state.prediction_result and st.session_state.last_image_buffer == st.session_state.image_buffer:
954
  predictions = st.session_state.prediction_result
955
  top_prediction = predictions[0]
956
 
957
+ # Main prediction with professional styling
958
  st.markdown(f"""
959
  <div class="info-card">
960
  <h3>🎯 Food Identified</h3>
 
969
  for pred in predictions[1:]:
970
  st.write(f"• {pred['display_name']} ({pred['confidence']:.1f}%)")
971
 
972
+ # Professional tabs for detailed analysis
973
+ tab1, tab2, tab3 = st.tabs(["🏥 Health Analysis", "⚠️ Allergen Alerts", "👨‍🍳 Professional Recipes"])
974
 
975
  with tab1:
976
+ # Enhanced health information
977
  food_name = top_prediction['class']
978
  nutrition = get_nutrition_info(food_name, health_data)
979
  health_score = get_health_score(food_name, health_data)
980
 
981
+ # Professional health score
982
  score_class = f"health-score-{health_score.lower()}"
983
  st.markdown(f"""
984
  <div class="{score_class}">
 
986
  </div>
987
  """, unsafe_allow_html=True)
988
 
989
+ # Professional nutrition metrics
990
  col1, col2, col3, col4 = st.columns(4)
991
 
992
  with col1:
 
1027
  for benefit in benefits:
1028
  st.markdown(f"• {benefit}")
1029
 
1030
+ # Enhanced ingredients with protein focus
1031
  st.markdown("### 🥘 Common Ingredients")
1032
  ingredients = get_common_ingredients(food_name)
1033
  for ingredient in ingredients:
1034
  st.markdown(f"• {ingredient}")
1035
 
1036
  with tab2:
1037
+ # Enhanced allergen information from history
1038
  allergen_info = get_allergen_info(food_name, allergen_data)
1039
 
1040
+ # User-specific allergen alerts with enhanced styling
1041
  user_allergens_lower = [allergen.lower() for allergen in st.session_state.user_allergens]
1042
  common_allergens_lower = [allergen.lower() for allergen in allergen_info.get('common_allergens', [])]
1043
  may_contain_lower = [allergen.lower() for allergen in allergen_info.get('may_contain', [])]
 
1052
  elif user_allergen in may_contain_lower:
1053
  may_contain_matches.append(user_allergen.title())
1054
 
1055
+ # Enhanced alert display with animation
1056
  if allergen_matches:
1057
  st.markdown(f"""
1058
  <div class="allergen-alert">
1059
+ <h3>🚨 CRITICAL ALLERGEN ALERT</h3>
1060
  <p>This food contains: <strong>{', '.join(allergen_matches)}</strong></p>
1061
  <p>You have marked these as allergens to avoid!</p>
1062
  </div>
 
1065
  if may_contain_matches:
1066
  st.markdown(f"""
1067
  <div class="allergen-info">
1068
+ <h3>⚠️ May Contain Alert</h3>
1069
  <p>This food may contain: <strong>{', '.join(may_contain_matches)}</strong></p>
1070
  <p>Please check ingredients carefully.</p>
1071
  </div>
 
1088
  for allergen in allergen_info['may_contain']:
1089
  st.markdown(f"• {allergen}")
1090
 
1091
+ # Enhanced trans fat warning
1092
  if st.session_state.avoid_trans_fat:
1093
+ trans_fat_foods = ['french_fries', 'donuts', 'fried_calamari', 'onion_rings', 'churros', 'chicken_wings', 'fish_and_chips']
1094
  if food_name in trans_fat_foods:
1095
  st.markdown("""
1096
  <div class="allergen-alert">
1097
+ <h3>🚨 TRANS FAT WARNING</h3>
1098
+ <p><strong>This food may contain trans fats from frying oils!</strong></p>
1099
+ <p>⚠️ Trans fats can increase bad cholesterol and heart disease risk</p>
1100
+ <p>💡 <strong>Healthier alternatives:</strong> Baked, grilled, or air-fried versions</p>
1101
  </div>
1102
  """, unsafe_allow_html=True)
1103
+
1104
+ # Add specific recommendations
1105
+ st.markdown("### 💚 Healthier Preparation Tips")
1106
+ st.markdown("• **Bake instead of fry** - Use oven at 425°F")
1107
+ st.markdown("• **Air fry** - Reduces oil by 80%")
1108
+ st.markdown("• **Use healthy oils** - Olive oil, avocado oil")
1109
+ st.markdown("• **Grill or steam** - No added fats needed")
1110
+ else:
1111
+ st.success("✅ This food is typically low in trans fats!")
1112
+ else:
1113
+ st.info("💡 Enable trans fat alerts in preferences to get warnings about potentially harmful trans fats.")
1114
 
1115
  with tab3:
1116
+ # Professional recipe generation with multiple recipes and limits
1117
+ st.markdown("### 👨‍🍳 Professional Recipes")
1118
+
1119
+ # Initialize recipe tracking for this food item
1120
+ if 'current_food_recipes' not in st.session_state:
1121
+ st.session_state.current_food_recipes = {}
1122
+ if 'last_food_analyzed' not in st.session_state:
1123
+ st.session_state.last_food_analyzed = None
1124
+
1125
+ # Reset recipe count if analyzing a different food
1126
+ if st.session_state.last_food_analyzed != food_name:
1127
+ st.session_state.recipe_count = 0
1128
+ st.session_state.current_food_recipes = {}
1129
+ st.session_state.last_food_analyzed = food_name
1130
+
1131
+ # Show current recipe count
1132
+ current_count = st.session_state.get('recipe_count', 0)
1133
+ remaining = 9 - current_count
1134
 
1135
+ if current_count > 0:
1136
+ st.info(f"📊 **Recipes Generated:** {current_count}/9 | **Remaining:** {remaining}")
1137
+
1138
+ # Button logic based on recipe count
1139
+ if current_count < 9:
1140
+ button_text = f"🍳 Generate {min(3, remaining)} More Professional Recipes"
1141
+ if current_count == 0:
1142
+ button_text = "🍳 Generate 3 Professional Recipes"
1143
+
1144
+ if st.button(button_text, type="primary", key=f"recipe_btn_{current_count}"):
1145
+ with st.spinner("👨‍🍳 Professional chef is creating your personalized recipes..."):
1146
+ # Generate 3 different recipe variations
1147
+ recipes = generate_multiple_recipes(food_name)
1148
+
1149
+ # Store recipes in session state
1150
+ if food_name not in st.session_state.current_food_recipes:
1151
+ st.session_state.current_food_recipes[food_name] = []
1152
+ st.session_state.current_food_recipes[food_name].extend(recipes)
1153
+
1154
+ st.success(f"✅ {len(recipes)} new recipes generated!")
1155
+ st.rerun()
1156
+ else:
1157
+ st.warning("🔒 **Recipe Limit Reached!** You've generated 9 recipes for this food item.")
1158
+ st.info("💡 **Tip:** Analyze a different food to get more recipe variations!")
1159
+
1160
+ # Display all generated recipes for this food
1161
+ if food_name in st.session_state.current_food_recipes:
1162
+ all_recipes = st.session_state.current_food_recipes[food_name]
1163
+
1164
+ for i, recipe_data in enumerate(all_recipes, 1):
1165
+ st.markdown(f"#### Recipe {i}: {recipe_data['title']}")
1166
 
1167
+ # Display food image and recipe
1168
+ col_img, col_recipe = st.columns([1, 2])
1169
+
1170
+ with col_img:
1171
+ # Always use styled placeholder - more reliable and professional
1172
+ # Get recipe style for color
1173
+ style_colors = {
1174
+ 'healthy': '#28a745',
1175
+ 'quick': '#fd7e14',
1176
+ 'gourmet': '#6f42c1',
1177
+ 'traditional': '#dc3545',
1178
+ 'fusion': '#e83e8c',
1179
+ 'low-carb': '#20c997',
1180
+ 'protein-rich': '#007bff',
1181
+ 'vegetarian': '#28a745',
1182
+ 'spicy': '#dc3545'
1183
+ }
1184
+
1185
+ # Get food-specific emoji
1186
+ food_emojis = {
1187
+ 'caesar_salad': '🥗',
1188
+ 'grilled_salmon': '🐟',
1189
+ 'steak': '🥩',
1190
+ 'pizza': '🍕',
1191
+ 'hamburger': '🍔',
1192
+ 'chicken_curry': '🍛',
1193
+ 'sushi': '🍣',
1194
+ 'tacos': '🌮',
1195
+ 'ice_cream': '🍦',
1196
+ 'chocolate_cake': '🍰'
1197
+ }
1198
+
1199
+ recipe_style = recipe_data['title'].split()[0].lower()
1200
+ color = style_colors.get(recipe_style, '#17a2b8')
1201
+ emoji = food_emojis.get(food_name, '🍽️')
1202
+
1203
+ st.markdown(f"""
1204
+ <div style="width: 200px; height: 133px; background: linear-gradient(135deg, {color}, #17a2b8);
1205
+ border-radius: 15px; display: flex; align-items: center; justify-content: center;
1206
+ color: white; font-weight: bold; text-align: center; padding: 15px; box-sizing: border-box;
1207
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2); margin-bottom: 10px;">
1208
+ <div>
1209
+ <div style="font-size: 3em; margin-bottom: 8px; filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.3));">{emoji}</div>
1210
+ <div style="font-size: 0.85em; line-height: 1.2; text-shadow: 1px 1px 2px rgba(0,0,0,0.5);">{recipe_data['title']}</div>
1211
+ </div>
1212
+ </div>
1213
+ """, unsafe_allow_html=True)
1214
+
1215
+ with col_recipe:
1216
+ st.markdown(f"""
1217
+ <div class="recipe-section">
1218
+ {recipe_data['recipe']}
1219
+ </div>
1220
+ """, unsafe_allow_html=True)
1221
+
1222
+ st.markdown("---")
1223
+
1224
+ # Reset button for new food analysis
1225
+ if current_count > 0:
1226
+ if st.button("🔄 Clear All Recipes (Start Fresh)", type="secondary"):
1227
+ st.session_state.recipe_count = 0
1228
+ st.session_state.current_food_recipes = {}
1229
+ st.success("✅ All recipes cleared! You can now generate new ones.")
1230
+ st.rerun()
1231
 
1232
  if __name__ == "__main__":
1233
  main()
health_info.json ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "grilled_salmon": {
3
+ "calories": "231",
4
+ "protein": "25.4g",
5
+ "carbs": "0g",
6
+ "fat": "13.4g",
7
+ "fiber": "0g",
8
+ "health_score": "Excellent",
9
+ "benefits": [
10
+ "Rich in high-quality protein for muscle building",
11
+ "Excellent source of omega-3 fatty acids for heart health",
12
+ "Contains vitamin D for bone health",
13
+ "High in B vitamins for energy metabolism",
14
+ "Anti-inflammatory properties"
15
+ ]
16
+ },
17
+ "pizza": {
18
+ "calories": "285",
19
+ "protein": "12.2g",
20
+ "carbs": "35.6g",
21
+ "fat": "10.4g",
22
+ "fiber": "2.5g",
23
+ "health_score": "Good",
24
+ "benefits": [
25
+ "Provides carbohydrates for energy",
26
+ "Contains protein from cheese",
27
+ "Tomato sauce provides lycopene antioxidants",
28
+ "Can be made healthier with vegetable toppings"
29
+ ]
30
+ },
31
+ "chicken_curry": {
32
+ "calories": "217",
33
+ "protein": "19.8g",
34
+ "carbs": "9.2g",
35
+ "fat": "11.5g",
36
+ "fiber": "2.1g",
37
+ "health_score": "Good",
38
+ "benefits": [
39
+ "High-quality lean protein source",
40
+ "Spices provide anti-inflammatory compounds",
41
+ "Contains turmeric with curcumin benefits",
42
+ "Good source of essential amino acids"
43
+ ]
44
+ },
45
+ "caesar_salad": {
46
+ "calories": "158",
47
+ "protein": "7.3g",
48
+ "carbs": "8.9g",
49
+ "fat": "11.2g",
50
+ "fiber": "3.2g",
51
+ "health_score": "Good",
52
+ "benefits": [
53
+ "Rich in vitamins A and K from romaine lettuce",
54
+ "Contains calcium from parmesan cheese",
55
+ "Good source of folate",
56
+ "Provides dietary fiber for digestion"
57
+ ]
58
+ },
59
+ "hamburger": {
60
+ "calories": "540",
61
+ "protein": "25.8g",
62
+ "carbs": "40.3g",
63
+ "fat": "31.0g",
64
+ "fiber": "2.2g",
65
+ "health_score": "Poor",
66
+ "benefits": [
67
+ "High protein content for muscle maintenance",
68
+ "Provides iron from beef",
69
+ "Contains B vitamins",
70
+ "Can be made healthier with lean meat and whole grain bun"
71
+ ]
72
+ },
73
+ "sushi": {
74
+ "calories": "200",
75
+ "protein": "8.8g",
76
+ "carbs": "43.8g",
77
+ "fat": "0.6g",
78
+ "fiber": "0.3g",
79
+ "health_score": "Good",
80
+ "benefits": [
81
+ "Low in calories and fat",
82
+ "High-quality protein from fish",
83
+ "Contains omega-3 fatty acids",
84
+ "Seaweed provides iodine and minerals"
85
+ ]
86
+ },
87
+ "chocolate_cake": {
88
+ "calories": "352",
89
+ "protein": "5.0g",
90
+ "carbs": "50.7g",
91
+ "fat": "16.4g",
92
+ "fiber": "2.0g",
93
+ "health_score": "Poor",
94
+ "benefits": [
95
+ "Provides quick energy from carbohydrates",
96
+ "Dark chocolate contains antioxidants",
97
+ "Can boost mood temporarily",
98
+ "Best enjoyed in moderation"
99
+ ]
100
+ },
101
+ "french_fries": {
102
+ "calories": "365",
103
+ "protein": "4.0g",
104
+ "carbs": "63.2g",
105
+ "fat": "17.0g",
106
+ "fiber": "5.7g",
107
+ "health_score": "Poor",
108
+ "benefits": [
109
+ "Provides potassium from potatoes",
110
+ "Contains some vitamin C",
111
+ "Source of carbohydrates for energy",
112
+ "Better when baked instead of fried"
113
+ ]
114
+ },
115
+ "ice_cream": {
116
+ "calories": "207",
117
+ "protein": "3.5g",
118
+ "carbs": "23.6g",
119
+ "fat": "11.0g",
120
+ "fiber": "0.7g",
121
+ "health_score": "Poor",
122
+ "benefits": [
123
+ "Contains calcium from dairy",
124
+ "Provides some protein",
125
+ "Can be part of balanced diet in moderation",
126
+ "Frozen yogurt alternatives are healthier"
127
+ ]
128
+ },
129
+ "tacos": {
130
+ "calories": "226",
131
+ "protein": "9.4g",
132
+ "carbs": "18.0g",
133
+ "fat": "13.8g",
134
+ "fiber": "3.2g",
135
+ "health_score": "Good",
136
+ "benefits": [
137
+ "Balanced macronutrients",
138
+ "Contains protein from meat or beans",
139
+ "Vegetables provide vitamins and minerals",
140
+ "Can be made very healthy with fresh ingredients"
141
+ ]
142
+ },
143
+ "steak": {
144
+ "calories": "271",
145
+ "protein": "26.1g",
146
+ "carbs": "0g",
147
+ "fat": "17.4g",
148
+ "fiber": "0g",
149
+ "health_score": "Good",
150
+ "benefits": [
151
+ "Excellent source of high-quality protein",
152
+ "Rich in iron and zinc",
153
+ "Contains vitamin B12",
154
+ "Provides essential amino acids"
155
+ ]
156
+ }
157
+ }