BetaGen commited on
Commit
1681485
Β·
verified Β·
1 Parent(s): ad85f78

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +701 -0
app.py ADDED
@@ -0,0 +1,701 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import base64
4
+ import io
5
+ import json
6
+ import numpy as np
7
+ from PIL import Image, ImageDraw, ImageFont
8
+ from typing import List, Dict, Any, Tuple
9
+ import requests
10
+ from sentence_transformers import SentenceTransformer
11
+ import faiss
12
+ from groq import Groq
13
+ import tempfile
14
+ import re
15
+
16
+ class FoodRAGApplication:
17
+ def __init__(self):
18
+ """Initialize the Food Recognition RAG application"""
19
+ # Initialize Groq client for vision and text
20
+ self.groq_client = Groq(api_key=os.environ.get("GROQ_API_KEY"))
21
+
22
+ # Initialize embedding model for nutrition database
23
+ self.embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
24
+
25
+ # Initialize FAISS index for nutrition knowledge
26
+ self.dimension = 384
27
+ self.nutrition_index = faiss.IndexFlatIP(self.dimension)
28
+
29
+ # Comprehensive nutrition database
30
+ self.nutrition_database = self._create_nutrition_database()
31
+ self.nutrition_embeddings = []
32
+ self.is_nutrition_indexed = False
33
+
34
+ # Build nutrition index
35
+ self._build_nutrition_index()
36
+
37
+ def _create_nutrition_database(self) -> List[Dict]:
38
+ """Create a comprehensive nutrition database for common foods"""
39
+ nutrition_db = [
40
+ # Fruits
41
+ {
42
+ "food_name": "Apple",
43
+ "category": "Fruit",
44
+ "calories_per_100g": 52,
45
+ "carbs": 14,
46
+ "fiber": 2.4,
47
+ "sugar": 10,
48
+ "protein": 0.3,
49
+ "fat": 0.2,
50
+ "vitamin_c": 4.6,
51
+ "potassium": 107,
52
+ "origin": "Central Asia",
53
+ "season": "Fall",
54
+ "health_benefits": "Rich in antioxidants, supports heart health, aids digestion",
55
+ "description": "Crisp, sweet fruit high in fiber and vitamin C"
56
+ },
57
+ {
58
+ "food_name": "Banana",
59
+ "category": "Fruit",
60
+ "calories_per_100g": 89,
61
+ "carbs": 23,
62
+ "fiber": 2.6,
63
+ "sugar": 12,
64
+ "protein": 1.1,
65
+ "fat": 0.3,
66
+ "vitamin_c": 8.7,
67
+ "potassium": 358,
68
+ "origin": "Southeast Asia",
69
+ "season": "Year-round",
70
+ "health_benefits": "High in potassium, supports muscle function, quick energy source",
71
+ "description": "Tropical fruit rich in potassium and natural sugars"
72
+ },
73
+ {
74
+ "food_name": "Orange",
75
+ "category": "Fruit",
76
+ "calories_per_100g": 47,
77
+ "carbs": 12,
78
+ "fiber": 2.4,
79
+ "sugar": 9,
80
+ "protein": 0.9,
81
+ "fat": 0.1,
82
+ "vitamin_c": 53.2,
83
+ "potassium": 181,
84
+ "origin": "China",
85
+ "season": "Winter",
86
+ "health_benefits": "Excellent source of vitamin C, boosts immunity, supports skin health",
87
+ "description": "Citrus fruit packed with vitamin C and folate"
88
+ },
89
+ {
90
+ "food_name": "Strawberry",
91
+ "category": "Fruit",
92
+ "calories_per_100g": 32,
93
+ "carbs": 8,
94
+ "fiber": 2,
95
+ "sugar": 4.9,
96
+ "protein": 0.7,
97
+ "fat": 0.3,
98
+ "vitamin_c": 58.8,
99
+ "potassium": 153,
100
+ "origin": "Europe and North America",
101
+ "season": "Spring-Summer",
102
+ "health_benefits": "High in antioxidants, supports brain health, anti-inflammatory",
103
+ "description": "Sweet berry rich in vitamin C and antioxidants"
104
+ },
105
+ {
106
+ "food_name": "Grapes",
107
+ "category": "Fruit",
108
+ "calories_per_100g": 62,
109
+ "carbs": 16,
110
+ "fiber": 0.9,
111
+ "sugar": 16,
112
+ "protein": 0.6,
113
+ "fat": 0.2,
114
+ "vitamin_c": 3.2,
115
+ "potassium": 191,
116
+ "origin": "Middle East",
117
+ "season": "Late summer-Fall",
118
+ "health_benefits": "Contains resveratrol, supports heart health, antioxidant properties",
119
+ "description": "Sweet fruit rich in natural sugars and antioxidants"
120
+ },
121
+
122
+ # Vegetables
123
+ {
124
+ "food_name": "Carrot",
125
+ "category": "Vegetable",
126
+ "calories_per_100g": 41,
127
+ "carbs": 10,
128
+ "fiber": 2.8,
129
+ "sugar": 4.7,
130
+ "protein": 0.9,
131
+ "fat": 0.2,
132
+ "vitamin_c": 5.9,
133
+ "potassium": 320,
134
+ "vitamin_a": 835,
135
+ "origin": "Afghanistan",
136
+ "season": "Fall-Winter",
137
+ "health_benefits": "High in beta-carotene, supports eye health, immune function",
138
+ "description": "Root vegetable rich in beta-carotene and fiber"
139
+ },
140
+ {
141
+ "food_name": "Broccoli",
142
+ "category": "Vegetable",
143
+ "calories_per_100g": 34,
144
+ "carbs": 7,
145
+ "fiber": 2.6,
146
+ "sugar": 1.5,
147
+ "protein": 2.8,
148
+ "fat": 0.4,
149
+ "vitamin_c": 89.2,
150
+ "potassium": 316,
151
+ "origin": "Mediterranean",
152
+ "season": "Fall-Spring",
153
+ "health_benefits": "High in vitamin C and K, supports bone health, cancer-fighting compounds",
154
+ "description": "Cruciferous vegetable packed with vitamins and minerals"
155
+ },
156
+ {
157
+ "food_name": "Spinach",
158
+ "category": "Vegetable",
159
+ "calories_per_100g": 23,
160
+ "carbs": 3.6,
161
+ "fiber": 2.2,
162
+ "sugar": 0.4,
163
+ "protein": 2.9,
164
+ "fat": 0.4,
165
+ "vitamin_c": 28.1,
166
+ "potassium": 558,
167
+ "iron": 2.7,
168
+ "origin": "Persia",
169
+ "season": "Spring-Fall",
170
+ "health_benefits": "High in iron and folate, supports blood health, rich in antioxidants",
171
+ "description": "Leafy green vegetable high in iron and vitamins"
172
+ },
173
+ {
174
+ "food_name": "Tomato",
175
+ "category": "Vegetable",
176
+ "calories_per_100g": 18,
177
+ "carbs": 3.9,
178
+ "fiber": 1.2,
179
+ "sugar": 2.6,
180
+ "protein": 0.9,
181
+ "fat": 0.2,
182
+ "vitamin_c": 13.7,
183
+ "potassium": 237,
184
+ "origin": "South America",
185
+ "season": "Summer",
186
+ "health_benefits": "Rich in lycopene, supports heart health, anti-cancer properties",
187
+ "description": "Versatile fruit-vegetable rich in lycopene and vitamin C"
188
+ },
189
+ {
190
+ "food_name": "Bell Pepper",
191
+ "category": "Vegetable",
192
+ "calories_per_100g": 31,
193
+ "carbs": 7,
194
+ "fiber": 2.5,
195
+ "sugar": 4.2,
196
+ "protein": 1,
197
+ "fat": 0.3,
198
+ "vitamin_c": 127.7,
199
+ "potassium": 211,
200
+ "origin": "Central America",
201
+ "season": "Summer-Fall",
202
+ "health_benefits": "Extremely high in vitamin C, supports immune system, antioxidant rich",
203
+ "description": "Colorful vegetable with exceptional vitamin C content"
204
+ },
205
+
206
+ # Nuts and Seeds
207
+ {
208
+ "food_name": "Almonds",
209
+ "category": "Nut",
210
+ "calories_per_100g": 579,
211
+ "carbs": 22,
212
+ "fiber": 12.5,
213
+ "sugar": 4.4,
214
+ "protein": 21,
215
+ "fat": 50,
216
+ "vitamin_c": 0,
217
+ "potassium": 733,
218
+ "origin": "Middle East",
219
+ "season": "Late summer",
220
+ "health_benefits": "High in healthy fats, supports heart health, good protein source",
221
+ "description": "Tree nut rich in healthy fats, protein, and vitamin E"
222
+ },
223
+ {
224
+ "food_name": "Avocado",
225
+ "category": "Fruit",
226
+ "calories_per_100g": 160,
227
+ "carbs": 9,
228
+ "fiber": 7,
229
+ "sugar": 0.7,
230
+ "protein": 2,
231
+ "fat": 15,
232
+ "vitamin_c": 10,
233
+ "potassium": 485,
234
+ "origin": "South Central Mexico",
235
+ "season": "Year-round",
236
+ "health_benefits": "Rich in monounsaturated fats, supports heart health, nutrient dense",
237
+ "description": "Creamy fruit high in healthy fats and fiber"
238
+ }
239
+ ]
240
+ return nutrition_db
241
+
242
+ def _build_nutrition_index(self):
243
+ """Build FAISS index for nutrition database"""
244
+ try:
245
+ # Create text descriptions for embedding
246
+ nutrition_texts = []
247
+ for food in self.nutrition_database:
248
+ text = f"{food['food_name']} {food['category']} {food['description']} {food['health_benefits']} {food['origin']}"
249
+ nutrition_texts.append(text)
250
+
251
+ # Create embeddings
252
+ embeddings = self.embedding_model.encode(nutrition_texts)
253
+ faiss.normalize_L2(embeddings)
254
+
255
+ # Add to index
256
+ self.nutrition_index.add(embeddings)
257
+ self.nutrition_embeddings = embeddings
258
+ self.is_nutrition_indexed = True
259
+
260
+ except Exception as e:
261
+ print(f"Error building nutrition index: {e}")
262
+
263
+ def encode_image_to_base64(self, image: Image.Image) -> str:
264
+ """Convert PIL Image to base64 string"""
265
+ buffered = io.BytesIO()
266
+ image.save(buffered, format="JPEG")
267
+ img_str = base64.b64encode(buffered.getvalue()).decode()
268
+ return f"data:image/jpeg;base64,{img_str}"
269
+
270
+ def identify_food_with_groq(self, image: Image.Image) -> str:
271
+ """Use Groq vision model to identify food in image"""
272
+ try:
273
+ # Convert image to base64
274
+ base64_image = self.encode_image_to_base64(image)
275
+
276
+ # Call Groq vision API
277
+ completion = self.groq_client.chat.completions.create(
278
+ model="llama-3.2-11b-vision-preview",
279
+ messages=[
280
+ {
281
+ "role": "user",
282
+ "content": [
283
+ {
284
+ "type": "text",
285
+ "text": "Identify the food item(s) in this image. Provide the name of the food, whether it's a fruit, vegetable, or other category. Be specific and concise. If there are multiple food items, list them all."
286
+ },
287
+ {
288
+ "type": "image_url",
289
+ "image_url": {
290
+ "url": base64_image
291
+ }
292
+ }
293
+ ]
294
+ }
295
+ ],
296
+ temperature=0.1,
297
+ max_completion_tokens=512,
298
+ top_p=1,
299
+ stream=False,
300
+ stop=None,
301
+ )
302
+
303
+ return completion.choices[0].message.content
304
+
305
+ except Exception as e:
306
+ return f"Error identifying food: {str(e)}"
307
+
308
+ def search_nutrition_info(self, food_identification: str, top_k: int = 3) -> List[Dict]:
309
+ """Search nutrition database for relevant food information"""
310
+ if not self.is_nutrition_indexed:
311
+ return []
312
+
313
+ try:
314
+ # Create query embedding
315
+ query_embedding = self.embedding_model.encode([food_identification])
316
+ faiss.normalize_L2(query_embedding)
317
+
318
+ # Search in nutrition index
319
+ scores, indices = self.nutrition_index.search(query_embedding, top_k)
320
+
321
+ results = []
322
+ for score, idx in zip(scores[0], indices[0]):
323
+ if idx < len(self.nutrition_database):
324
+ food_info = self.nutrition_database[idx].copy()
325
+ food_info['similarity_score'] = float(score)
326
+ results.append(food_info)
327
+
328
+ return results
329
+
330
+ except Exception as e:
331
+ print(f"Nutrition search error: {e}")
332
+ return []
333
+
334
+ def generate_nutrition_response(self, food_identification: str, nutrition_matches: List[Dict]) -> str:
335
+ """Generate comprehensive nutrition response using Groq"""
336
+ try:
337
+ # Prepare nutrition context
338
+ context = ""
339
+ for i, food in enumerate(nutrition_matches):
340
+ context += f"""
341
+ Food {i+1}: {food['food_name']} ({food['category']})
342
+ - Calories per 100g: {food['calories_per_100g']}
343
+ - Carbohydrates: {food['carbs']}g
344
+ - Protein: {food['protein']}g
345
+ - Fat: {food['fat']}g
346
+ - Fiber: {food['fiber']}g
347
+ - Vitamin C: {food['vitamin_c']}mg
348
+ - Potassium: {food['potassium']}mg
349
+ - Origin: {food['origin']}
350
+ - Season: {food['season']}
351
+ - Health Benefits: {food['health_benefits']}
352
+ - Description: {food['description']}
353
+ """
354
+
355
+ # Create comprehensive prompt
356
+ prompt = f"""Based on the food identification: "{food_identification}" and the following nutrition database information, provide a comprehensive answer about the nutritional content and other relevant information.
357
+
358
+ Nutrition Database:
359
+ {context}
360
+
361
+ Please provide:
362
+ 1. Nutritional breakdown (calories, macronutrients, key vitamins/minerals)
363
+ 2. Health benefits
364
+ 3. Origin and seasonal information
365
+ 4. Any interesting facts about the food
366
+ 5. Serving size recommendations
367
+
368
+ Make the response informative, engaging, and well-structured. If the identified food matches closely with the database, use that information. If not, provide general nutritional guidance based on the food type identified.
369
+ """
370
+
371
+ # Call Groq for response generation
372
+ completion = self.groq_client.chat.completions.create(
373
+ model="llama-3.3-70b-versatile",
374
+ messages=[
375
+ {
376
+ "role": "system",
377
+ "content": "You are a nutrition expert providing detailed, accurate information about foods. Always cite specific nutritional values when available and give practical health advice."
378
+ },
379
+ {
380
+ "role": "user",
381
+ "content": prompt
382
+ }
383
+ ],
384
+ temperature=0.3,
385
+ max_completion_tokens=1000,
386
+ top_p=1,
387
+ stream=False,
388
+ )
389
+
390
+ return completion.choices[0].message.content
391
+
392
+ except Exception as e:
393
+ return f"Error generating nutrition response: {str(e)}"
394
+
395
+ def process_food_image(self, image: Image.Image) -> Tuple[str, str, str]:
396
+ """Main function to process food image and return nutrition information"""
397
+ if image is None:
398
+ return "Please upload an image of food.", "", ""
399
+
400
+ try:
401
+ # Step 1: Identify food using vision model
402
+ food_identification = self.identify_food_with_groq(image)
403
+
404
+ # Step 2: Search nutrition database
405
+ nutrition_matches = self.search_nutrition_info(food_identification)
406
+
407
+ # Step 3: Generate comprehensive response
408
+ nutrition_response = self.generate_nutrition_response(food_identification, nutrition_matches)
409
+
410
+ # Step 4: Create detailed breakdown
411
+ breakdown = "πŸ” **Food Identification:**\n"
412
+ breakdown += f"{food_identification}\n\n"
413
+
414
+ if nutrition_matches:
415
+ breakdown += "πŸ“Š **Matching Nutrition Data:**\n"
416
+ for i, food in enumerate(nutrition_matches[:2]):
417
+ breakdown += f"**{food['food_name']}** ({food['category']})\n"
418
+ breakdown += f"β€’ Calories: {food['calories_per_100g']} per 100g\n"
419
+ breakdown += f"β€’ Similarity Score: {food['similarity_score']:.3f}\n\n"
420
+
421
+ return nutrition_response, breakdown, food_identification
422
+
423
+ except Exception as e:
424
+ return f"Error processing image: {str(e)}", "", ""
425
+
426
+ # Initialize the application
427
+ food_app = FoodRAGApplication()
428
+
429
+ def create_food_pattern_background():
430
+ """Create an attractive food pattern background"""
431
+ # Create a large canvas
432
+ width, height = 1200, 800
433
+ background = Image.new('RGB', (width, height), '#f8f9fa')
434
+ draw = ImageDraw.Draw(background)
435
+
436
+ # Food emojis and colors
437
+ food_items = ['🍎', '🍊', '🍌', 'πŸ₯•', 'πŸ₯¬', 'πŸ‡', 'πŸ“', 'πŸ₯‘', 'πŸ…', 'πŸ₯’']
438
+ colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#feca57', '#ff9ff3', '#54a0ff', '#5f27cd']
439
+
440
+ # Create pattern
441
+ for i in range(0, width, 100):
442
+ for j in range(0, height, 100):
443
+ # Add subtle circles
444
+ circle_color = colors[(i//100 + j//100) % len(colors)]
445
+ draw.ellipse([i+20, j+20, i+80, j+80], fill=circle_color + '20')
446
+
447
+ return background
448
+
449
+ # Custom CSS with food theme
450
+ custom_css = """
451
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
452
+
453
+ .gradio-container {
454
+ font-family: 'Poppins', sans-serif !important;
455
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
456
+ min-height: 100vh;
457
+ }
458
+
459
+ .main-header {
460
+ text-align: center;
461
+ background: linear-gradient(135deg, #ff9a56, #ff6b95);
462
+ color: white;
463
+ padding: 3rem 2rem;
464
+ border-radius: 20px;
465
+ margin: 1rem;
466
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
467
+ position: relative;
468
+ overflow: hidden;
469
+ }
470
+
471
+ .main-header::before {
472
+ content: '🍎πŸ₯•πŸŠπŸ₯¬πŸ‡πŸ“';
473
+ position: absolute;
474
+ top: -10px;
475
+ right: -10px;
476
+ font-size: 2rem;
477
+ opacity: 0.2;
478
+ animation: float 3s ease-in-out infinite;
479
+ }
480
+
481
+ @keyframes float {
482
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
483
+ 50% { transform: translateY(-10px) rotate(5deg); }
484
+ }
485
+
486
+ .food-upload-area {
487
+ background: linear-gradient(145deg, #ffffff, #f0f0f0);
488
+ border: 3px dashed #ff9a56;
489
+ border-radius: 20px;
490
+ padding: 2rem;
491
+ text-align: center;
492
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
493
+ transition: all 0.3s ease;
494
+ }
495
+
496
+ .food-upload-area:hover {
497
+ border-color: #ff6b95;
498
+ transform: translateY(-2px);
499
+ box-shadow: 0 8px 25px rgba(255, 154, 86, 0.3);
500
+ }
501
+
502
+ .nutrition-panel {
503
+ background: linear-gradient(145deg, #ffffff, #f8f9ff);
504
+ border-radius: 15px;
505
+ padding: 1.5rem;
506
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
507
+ border-left: 4px solid #ff9a56;
508
+ }
509
+
510
+ .btn-analyze {
511
+ background: linear-gradient(135deg, #ff9a56, #ff6b95) !important;
512
+ border: none !important;
513
+ color: white !important;
514
+ font-weight: 600 !important;
515
+ padding: 12px 30px !important;
516
+ border-radius: 25px !important;
517
+ font-size: 16px !important;
518
+ transition: all 0.3s ease !important;
519
+ box-shadow: 0 4px 15px rgba(255, 154, 86, 0.4) !important;
520
+ }
521
+
522
+ .btn-analyze:hover {
523
+ transform: translateY(-2px) !important;
524
+ box-shadow: 0 6px 20px rgba(255, 154, 86, 0.6) !important;
525
+ }
526
+
527
+ .food-facts {
528
+ background: linear-gradient(145deg, #e8f5e8, #f0fff0);
529
+ border-radius: 15px;
530
+ padding: 1.5rem;
531
+ margin-top: 1rem;
532
+ border-left: 4px solid #4ecdc4;
533
+ }
534
+
535
+ .nutrition-grid {
536
+ display: grid;
537
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
538
+ gap: 1rem;
539
+ margin-top: 1rem;
540
+ }
541
+
542
+ .nutrient-card {
543
+ background: white;
544
+ padding: 1rem;
545
+ border-radius: 10px;
546
+ text-align: center;
547
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
548
+ transition: transform 0.2s ease;
549
+ }
550
+
551
+ .nutrient-card:hover {
552
+ transform: translateY(-3px);
553
+ }
554
+
555
+ /* Custom scrollbar */
556
+ ::-webkit-scrollbar {
557
+ width: 8px;
558
+ }
559
+
560
+ ::-webkit-scrollbar-track {
561
+ background: #f1f1f1;
562
+ border-radius: 10px;
563
+ }
564
+
565
+ ::-webkit-scrollbar-thumb {
566
+ background: linear-gradient(135deg, #ff9a56, #ff6b95);
567
+ border-radius: 10px;
568
+ }
569
+
570
+ ::-webkit-scrollbar-thumb:hover {
571
+ background: linear-gradient(135deg, #ff6b95, #ff9a56);
572
+ }
573
+ """
574
+
575
+ def create_interface():
576
+ """Create the Gradio interface"""
577
+ with gr.Blocks(css=custom_css, title="🍎 AI Food Nutritionist", theme=gr.themes.Soft()) as interface:
578
+
579
+ # Header with food theme
580
+ gr.HTML("""
581
+ <div class="main-header">
582
+ <h1 style="font-size: 2.5rem; margin: 0; font-weight: 700;">🍎 AI Food Nutritionist</h1>
583
+ <p style="font-size: 1.2rem; margin: 10px 0 0 0; opacity: 0.9;">Upload food images and discover nutritional insights with AI-powered analysis!</p>
584
+ </div>
585
+ """)
586
+
587
+ with gr.Row():
588
+ # Left panel - Image upload
589
+ with gr.Column(scale=1):
590
+ gr.HTML("<div style='text-align: center; padding: 1rem;'><h2 style='color: #333; margin-bottom: 1rem;'>πŸ“Έ Upload Food Image</h2></div>")
591
+
592
+ image_input = gr.Image(
593
+ label="Food Image",
594
+ type="pil",
595
+ height=400,
596
+ elem_classes=["food-upload-area"]
597
+ )
598
+
599
+ analyze_btn = gr.Button(
600
+ "πŸ” Analyze Nutrition",
601
+ variant="primary",
602
+ size="lg",
603
+ elem_classes=["btn-analyze"]
604
+ )
605
+
606
+ # Quick facts panel
607
+ gr.HTML("""
608
+ <div class="food-facts">
609
+ <h3 style="color: #2c3e50; margin-top: 0;">πŸ’‘ Did you know?</h3>
610
+ <ul style="color: #555; line-height: 1.6;">
611
+ <li>πŸ₯• Carrots contain beta-carotene for eye health</li>
612
+ <li>🍌 Bananas are rich in potassium for heart health</li>
613
+ <li>πŸ₯¬ Leafy greens provide folate and iron</li>
614
+ <li>πŸ“ Berries are packed with antioxidants</li>
615
+ </ul>
616
+ </div>
617
+ """)
618
+
619
+ # Right panel - Results
620
+ with gr.Column(scale=2):
621
+ gr.HTML("<div style='text-align: center; padding: 1rem;'><h2 style='color: #333; margin-bottom: 1rem;'>πŸ“Š Nutrition Analysis</h2></div>")
622
+
623
+ with gr.Tabs():
624
+ with gr.TabItem("🍽️ Detailed Analysis"):
625
+ nutrition_output = gr.Textbox(
626
+ label="AI Nutrition Analysis",
627
+ lines=15,
628
+ interactive=False,
629
+ placeholder="Upload a food image and click 'Analyze Nutrition' to get detailed nutritional information...",
630
+ elem_classes=["nutrition-panel"]
631
+ )
632
+
633
+ with gr.TabItem("πŸ” Food Identification"):
634
+ identification_output = gr.Textbox(
635
+ label="Food Identification Details",
636
+ lines=10,
637
+ interactive=False,
638
+ placeholder="Food identification details will appear here...",
639
+ elem_classes=["nutrition-panel"]
640
+ )
641
+
642
+ with gr.TabItem("πŸ“ˆ Quick Stats"):
643
+ stats_output = gr.Textbox(
644
+ label="Quick Nutritional Breakdown",
645
+ lines=10,
646
+ interactive=False,
647
+ placeholder="Quick nutritional statistics will appear here...",
648
+ elem_classes=["nutrition-panel"]
649
+ )
650
+
651
+ # Example images section
652
+ gr.HTML("""
653
+ <div style="margin-top: 2rem; text-align: center; padding: 2rem; background: rgba(255, 255, 255, 0.1); border-radius: 15px; backdrop-filter: blur(10px);">
654
+ <h3 style="color: white; margin-bottom: 1rem;">🌟 Try These Examples</h3>
655
+ <p style="color: white; opacity: 0.9;">Upload images of fruits, vegetables, nuts, or other foods to get instant nutritional analysis!</p>
656
+ <div style="margin-top: 1rem; font-size: 2rem;">
657
+ 🍎 πŸ₯• 🍌 πŸ₯¬ πŸ‡ πŸ“ πŸ₯‘ πŸ… πŸ₯’ 🌽
658
+ </div>
659
+ </div>
660
+ """)
661
+
662
+ # Processing status
663
+ status_display = gr.HTML(visible=False)
664
+
665
+ # Event handler
666
+ def analyze_food_wrapper(image):
667
+ if image is None:
668
+ return "Please upload an image first! πŸ“Έ", "", ""
669
+
670
+ # Show processing status
671
+ status_html = """
672
+ <div style="text-align: center; padding: 1rem; background: #e3f2fd; border-radius: 10px; margin: 1rem;">
673
+ <h3 style="color: #1976d2;">πŸ”„ Processing your food image...</h3>
674
+ <p>AI is analyzing the nutritional content. Please wait...</p>
675
+ </div>
676
+ """
677
+
678
+ try:
679
+ nutrition_info, breakdown, identification = food_app.process_food_image(image)
680
+ return nutrition_info, breakdown, identification
681
+ except Exception as e:
682
+ error_msg = f"❌ Error analyzing image: {str(e)}"
683
+ return error_msg, "", ""
684
+
685
+ analyze_btn.click(
686
+ fn=analyze_food_wrapper,
687
+ inputs=[image_input],
688
+ outputs=[nutrition_output, stats_output, identification_output]
689
+ )
690
+
691
+ return interface
692
+
693
+ # Launch the application
694
+ if __name__ == "__main__":
695
+ interface = create_interface()
696
+ interface.launch(
697
+ share=True,
698
+ server_name="0.0.0.0",
699
+ server_port=7860,
700
+ show_error=True
701
+ )