dev2607 commited on
Commit
bfaa1e6
·
verified ·
1 Parent(s): 68cd547

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +300 -134
app.py CHANGED
@@ -3,97 +3,44 @@ import subprocess
3
  import sys
4
  import re
5
  import numpy as np
 
6
  import gradio as gr
7
  import requests
8
  import json
9
  from dotenv import load_dotenv
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  # Load environment variables
12
  load_dotenv()
13
 
14
  # Mistral API Key
15
- MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY", "GlrVCBWyvTYjWGKl5jqtK4K41uWWJ79F") # Retrieve from environment or default
16
 
17
- # Open Food Facts API for product lookup
18
- def get_product_ingredients(product_name):
19
- """
20
- Look up a product by name using the Open Food Facts API and return its ingredients
21
- """
22
- if not product_name or not product_name.strip():
23
- return None, "Please enter a product name"
24
-
25
- try:
26
- # Search for products matching the name
27
- search_url = f"https://world.openfoodfacts.org/cgi/search.pl?search_terms={product_name}&search_simple=1&action=process&json=1"
28
- response = requests.get(search_url)
29
-
30
- if response.status_code != 200:
31
- return None, f"Error connecting to food database: {response.status_code}"
32
-
33
- data = response.json()
34
-
35
- # Check if any products were found
36
- if data["count"] == 0:
37
- return None, f"No products found matching '{product_name}'"
38
-
39
- # Get the first (most relevant) product
40
- product = data["products"][0]
41
-
42
- # Extract product information
43
- product_info = {
44
- "name": product.get("product_name", "Unknown product"),
45
- "brand": product.get("brands", "Unknown brand"),
46
- "ingredients_text": product.get("ingredients_text", ""),
47
- "image_url": product.get("image_url", ""),
48
- "ingredients_list": []
49
- }
50
-
51
- # If ingredients are available in structured format
52
- if "ingredients" in product and isinstance(product["ingredients"], list):
53
- for ing in product["ingredients"]:
54
- if "text" in ing and ing["text"]:
55
- product_info["ingredients_list"].append(ing["text"].lower())
56
-
57
- # If no structured ingredients but we have text, parse it
58
- elif product_info["ingredients_text"]:
59
- product_info["ingredients_list"] = parse_ingredients(product_info["ingredients_text"])
60
-
61
- # If we still don't have ingredients
62
- if not product_info["ingredients_list"]:
63
- return None, f"Found product '{product_info['name']}' by {product_info['brand']}, but no ingredients information is available"
64
-
65
- return product_info, None
66
-
67
- except requests.exceptions.RequestException as e:
68
- return None, f"Network error retrieving product information: {str(e)}"
69
- except Exception as e:
70
- return None, f"Error retrieving product information: {str(e)}"
71
-
72
- # Function to parse ingredients from text
73
- def parse_ingredients(text):
74
- if not text:
75
- return []
76
-
77
- # Clean up the text
78
- text = re.sub(r'^ingredients:?\s*', '', text.lower(), flags=re.IGNORECASE)
79
-
80
- # Remove common OCR errors and extraneous characters
81
- text = re.sub(r'[|\\/@#$%^&*()_+=]', '', text)
82
-
83
- # Split by common ingredient separators
84
- ingredients = re.split(r',|;|\n', text)
85
-
86
- # Clean up each ingredient
87
- cleaned_ingredients = []
88
- for i in ingredients:
89
- i = i.strip().lower()
90
- if i and len(i) > 1: # Ignore single characters which are likely errors
91
- cleaned_ingredients.append(i)
92
-
93
- return cleaned_ingredients
94
 
95
  # Import and configure Mistral API
96
- def analyze_ingredients_with_mistral(ingredients_list, product_name="", health_conditions=None):
97
  """
98
  Use Mistral AI to analyze ingredients and provide health insights.
99
  """
@@ -102,13 +49,11 @@ def analyze_ingredients_with_mistral(ingredients_list, product_name="", health_c
102
 
103
  # Prepare the list of ingredients for the prompt
104
  ingredients_text = ", ".join(ingredients_list)
105
-
106
- product_context = f"for the product '{product_name}'" if product_name else ""
107
 
108
  # Create a prompt for Mistral
109
  if health_conditions and health_conditions.strip():
110
  prompt = f"""
111
- Analyze the following food ingredients {product_context} for a person with these health conditions: {health_conditions}
112
  Ingredients: {ingredients_text}
113
  For each ingredient:
114
  1. Provide its potential health benefits
@@ -119,7 +64,7 @@ def analyze_ingredients_with_mistral(ingredients_list, product_name="", health_c
119
  """
120
  else:
121
  prompt = f"""
122
- Analyze the following food ingredients {product_context}:
123
  Ingredients: {ingredients_text}
124
  For each ingredient:
125
  1. Provide its potential health benefits
@@ -155,13 +100,11 @@ def analyze_ingredients_with_mistral(ingredients_list, product_name="", health_c
155
 
156
  return analysis + disclaimer
157
 
158
- except requests.exceptions.RequestException as e:
159
- # Fallback to basic analysis if API call fails
160
- return dummy_analyze(ingredients_list, health_conditions) + f"\n\n(Using fallback analysis: Network error - {str(e)})"
161
  except Exception as e:
162
  # Fallback to basic analysis if API call fails
163
  return dummy_analyze(ingredients_list, health_conditions) + f"\n\n(Using fallback analysis: {str(e)})"
164
 
 
165
  # Dummy analysis function for when API is not available
166
  def dummy_analyze(ingredients_list, health_conditions=None):
167
  ingredients_text = ", ".join(ingredients_list)
@@ -193,55 +136,275 @@ def dummy_analyze(ingredients_list, health_conditions=None):
193
 
194
  return report
195
 
196
- # Function to process product name input
197
- def process_product_input(product_name, manual_ingredients, use_manual, health_conditions):
198
- if use_manual:
199
- if manual_ingredients and manual_ingredients.strip():
200
- ingredients = parse_ingredients(manual_ingredients)
201
- return f"Analyzing manually entered ingredients:\n\n{analyze_ingredients_with_mistral(ingredients, '', health_conditions)}", manual_ingredients
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  else:
203
  return "No ingredients entered. Please try again.", ""
204
- else:
205
- if not product_name or not product_name.strip():
206
- return "Please enter a product name", ""
207
-
208
- product_info, error = get_product_ingredients(product_name)
209
-
210
- if error:
211
- return error, ""
212
-
213
- # Display analysis using the ingredients
214
- return f"# Analysis for {product_info['name']} by {product_info['brand']}\n\n{analyze_ingredients_with_mistral(product_info['ingredients_list'], product_info['name'], health_conditions)}", ", ".join(product_info['ingredients_list'])
215
 
216
  # Create the Gradio interface
217
  with gr.Blocks(title="AI Ingredient Scanner") as app:
218
  gr.Markdown("# AI Ingredient Scanner")
219
- gr.Markdown("Find and analyze product ingredients for health benefits, risks, and potential allergens.")
220
 
221
  with gr.Row():
222
  with gr.Column():
223
- # Option to use manual ingredients or product lookup
224
- use_manual_ingredients = gr.Checkbox(
225
- label="Enter ingredients manually instead of product lookup",
226
- value=False
227
- )
228
-
229
- # Product name input
230
- product_name_input = gr.Textbox(
231
- label="Enter product name",
232
- placeholder="Oreo cookies, Coca Cola, Nutella, etc.",
233
- lines=1
234
  )
235
-
236
- # Manual ingredients input (initially hidden)
237
- manual_ingredients_input = gr.Textbox(
 
 
 
 
 
 
238
  label="Enter ingredients list (comma separated)",
239
  placeholder="milk, sugar, flour, eggs, vanilla extract",
240
  lines=3,
241
  visible=False
242
  )
243
 
244
- # Health conditions input
245
  health_conditions = gr.Textbox(
246
  label="Enter your health concerns (optional)",
247
  placeholder="diabetes, high blood pressure, peanut allergy, etc.",
@@ -253,32 +416,32 @@ with gr.Blocks(title="AI Ingredient Scanner") as app:
253
 
254
  with gr.Column():
255
  output = gr.Markdown(label="Analysis Results")
256
- ingredients_output = gr.Textbox(label="Identified Ingredients", lines=3)
257
 
258
- # Show/hide inputs based on checkbox
259
- def update_visible_inputs(use_manual):
260
  return {
261
- product_name_input: gr.update(visible=not use_manual),
262
- manual_ingredients_input: gr.update(visible=use_manual)
 
263
  }
264
 
265
- use_manual_ingredients.change(update_visible_inputs, use_manual_ingredients, [product_name_input, manual_ingredients_input])
266
 
267
  # Set up event handlers
268
  analyze_button.click(
269
- fn=process_product_input,
270
- inputs=[product_name_input, manual_ingredients_input, use_manual_ingredients, health_conditions],
271
- outputs=[output, ingredients_output]
272
  )
273
 
274
  gr.Markdown("### How to use")
275
  gr.Markdown("""
276
- 1. Enter a product name (e.g., "Oreo cookies", "Coca Cola", "Nutella")
277
- 2. Or check the box to enter ingredients manually if you prefer
278
  3. Optionally enter your health concerns
279
  4. Click "Analyze Ingredients" to get your personalized analysis
280
-
281
- The AI will automatically find the product's ingredients and analyze their health implications and potential impact on your specific health concerns.
282
  """)
283
 
284
  gr.Markdown("### Examples of what you can ask")
@@ -294,9 +457,10 @@ with gr.Blocks(title="AI Ingredient Scanner") as app:
294
 
295
  gr.Markdown("### Tips for best results")
296
  gr.Markdown("""
297
- - Use the full product name and brand if possible
 
 
298
  - Be specific about your health concerns for more targeted analysis
299
- - If a product can't be found, try entering the ingredients manually
300
  """)
301
 
302
  gr.Markdown("### Disclaimer")
@@ -307,4 +471,6 @@ with gr.Blocks(title="AI Ingredient Scanner") as app:
307
 
308
  # Launch the app
309
  if __name__ == "__main__":
 
 
310
  app.launch()
 
3
  import sys
4
  import re
5
  import numpy as np
6
+ from PIL import Image
7
  import gradio as gr
8
  import requests
9
  import json
10
  from dotenv import load_dotenv
11
 
12
+ # Attempt to install pytesseract if not found
13
+ try:
14
+ import pytesseract
15
+ except ImportError:
16
+ subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pytesseract'])
17
+ import pytesseract
18
+
19
+ # AFTER importing pytesseract, then set the path
20
+ try:
21
+ # First try the default path
22
+ if os.path.exists('/usr/bin/tesseract'):
23
+ pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract'
24
+ # Try to find it on the PATH
25
+ else:
26
+ tesseract_path = subprocess.check_output(['which', 'tesseract']).decode().strip()
27
+ if tesseract_path:
28
+ pytesseract.pytesseract.tesseract_cmd = tesseract_path
29
+ except:
30
+ # If all else fails, try the default installation path
31
+ pytesseract.pytesseract.tesseract_cmd = 'tesseract'
32
+
33
  # Load environment variables
34
  load_dotenv()
35
 
36
  # Mistral API Key
37
+ MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY", "GlrVCBWyvTYjWGKl5jqtK4K41uWWJ79F")
38
 
39
+ # OpenAI API Key for Product Identification
40
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "sk-exampleapikey") # Replace with your actual OpenAI API key
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  # Import and configure Mistral API
43
+ def analyze_ingredients_with_mistral(ingredients_list, health_conditions=None):
44
  """
45
  Use Mistral AI to analyze ingredients and provide health insights.
46
  """
 
49
 
50
  # Prepare the list of ingredients for the prompt
51
  ingredients_text = ", ".join(ingredients_list)
 
 
52
 
53
  # Create a prompt for Mistral
54
  if health_conditions and health_conditions.strip():
55
  prompt = f"""
56
+ Analyze the following food ingredients for a person with these health conditions: {health_conditions}
57
  Ingredients: {ingredients_text}
58
  For each ingredient:
59
  1. Provide its potential health benefits
 
64
  """
65
  else:
66
  prompt = f"""
67
+ Analyze the following food ingredients:
68
  Ingredients: {ingredients_text}
69
  For each ingredient:
70
  1. Provide its potential health benefits
 
100
 
101
  return analysis + disclaimer
102
 
 
 
 
103
  except Exception as e:
104
  # Fallback to basic analysis if API call fails
105
  return dummy_analyze(ingredients_list, health_conditions) + f"\n\n(Using fallback analysis: {str(e)})"
106
 
107
+
108
  # Dummy analysis function for when API is not available
109
  def dummy_analyze(ingredients_list, health_conditions=None):
110
  ingredients_text = ", ".join(ingredients_list)
 
136
 
137
  return report
138
 
139
+ # Function to extract text from images using OCR
140
+ def extract_text_from_image(image):
141
+ try:
142
+ if image is None:
143
+ return "No image captured. Please try again."
144
+
145
+ # Verify Tesseract executable is accessible
146
+ try:
147
+ subprocess.run([pytesseract.pytesseract.tesseract_cmd, "--version"],
148
+ check=True, capture_output=True, text=True)
149
+ except (subprocess.SubprocessError, FileNotFoundError):
150
+ return "Tesseract OCR is not installed or not properly configured. Please check installation."
151
+
152
+ # Import necessary libraries
153
+ import cv2
154
+ import numpy as np
155
+ from PIL import Image, ImageOps, ImageEnhance
156
+
157
+ # First approach: Invert the image for light text on dark background
158
+ inverted_image = ImageOps.invert(image)
159
+
160
+ # Try OCR on inverted image
161
+ custom_config = r'--oem 3 --psm 6 -l eng --dpi 300'
162
+ inverted_text = pytesseract.image_to_string(inverted_image, config=custom_config)
163
+
164
+ # Second approach: OpenCV processing for colored backgrounds
165
+ img_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
166
+
167
+ # Convert to grayscale
168
+ gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
169
+
170
+ # Apply bilateral filter to preserve edges while reducing noise
171
+ filtered = cv2.bilateralFilter(gray, 11, 17, 17)
172
+
173
+ # Adaptive thresholding to handle varied lighting
174
+ thresh = cv2.adaptiveThreshold(filtered, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
175
+ cv2.THRESH_BINARY, 11, 2)
176
+
177
+ # Invert the image (if text is light on dark background)
178
+ inverted_thresh = cv2.bitwise_not(thresh)
179
+
180
+ # Try OCR on processed image
181
+ cv_text = pytesseract.image_to_string(
182
+ Image.fromarray(inverted_thresh),
183
+ config=custom_config
184
+ )
185
+
186
+ # Third approach: Color filtering to isolate text from colored background
187
+ # Convert to HSV color space to better isolate colors
188
+ hsv = cv2.cvtColor(img_cv, cv2.COLOR_BGR2HSV)
189
+
190
+ # Create a mask to extract light colored text (assuming white/light text)
191
+ lower_white = np.array([0, 0, 150])
192
+ upper_white = np.array([180, 30, 255])
193
+ mask = cv2.inRange(hsv, lower_white, upper_white)
194
+
195
+ # Apply morphological operations to clean up the mask
196
+ kernel = np.ones((2, 2), np.uint8)
197
+ mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
198
+ mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
199
+
200
+ # Improve character connectivity
201
+ mask = cv2.dilate(mask, kernel, iterations=1)
202
+
203
+ # Try OCR on color filtered image
204
+ color_text = pytesseract.image_to_string(
205
+ Image.fromarray(mask),
206
+ config=r'--oem 3 --psm 6 -l eng --dpi 300'
207
+ )
208
+
209
+ # Fourth approach: Try directly with the image but with different configs
210
+ direct_text = pytesseract.image_to_string(
211
+ image,
212
+ config=r'--oem 3 --psm 11 -l eng --dpi 300'
213
+ )
214
+
215
+ # Compare results and select the best one
216
+ results = [inverted_text, cv_text, color_text, direct_text]
217
+
218
+ # Select the result with the most alphanumeric characters
219
+ def count_alphanumeric(text):
220
+ return sum(c.isalnum() for c in text)
221
+
222
+ best_text = max(results, key=count_alphanumeric)
223
+
224
+ # If still poor results, try with explicit text color inversion in tesseract
225
+ if count_alphanumeric(best_text) < 20:
226
+ # Try with tesseract's built-in inversion
227
+ neg_text = pytesseract.image_to_string(
228
+ image,
229
+ config=r'--oem 3 --psm 6 -c textord_heavy_nr=1 -c textord_debug_printable=0 -l eng --dpi 300'
230
+ )
231
+ if count_alphanumeric(neg_text) > count_alphanumeric(best_text):
232
+ best_text = neg_text
233
+
234
+ # Clean up the text
235
+ best_text = re.sub(r'[^\w\s,;:%.()\n\'-]', '', best_text)
236
+ best_text = best_text.replace('\n\n', '\n')
237
+
238
+ # Special case for ingredients list format
239
+ if "ingredient" in best_text.lower() or any(x in best_text.lower() for x in ["sugar", "cocoa", "milk", "contain"]):
240
+ # Specific cleaning for ingredient lists
241
+ best_text = re.sub(r'([a-z])([A-Z])', r'\1 \2', best_text) # Add space between lowercase and uppercase
242
+ best_text = re.sub(r'(\d+)([a-zA-Z])', r'\1 \2', best_text) # Add space between number and letter
243
+
244
+ if not best_text.strip():
245
+ return "No text could be extracted. Ensure image is clear and readable."
246
+
247
+ return best_text.strip()
248
+ except Exception as e:
249
+ return f"Error extracting text: {str(e)}"
250
+
251
+ # Function to parse ingredients from text
252
+ def parse_ingredients(text):
253
+ if not text:
254
+ return []
255
+
256
+ # Clean up the text
257
+ text = re.sub(r'^ingredients:?\s*', '', text.lower(), flags=re.IGNORECASE)
258
+
259
+ # Remove common OCR errors and extraneous characters
260
+ text = re.sub(r'[|\\/@#$%^&*()_+=]', '', text)
261
+
262
+ # Replace common OCR errors
263
+ text = re.sub(r'\bngredients\b', 'ingredients', text)
264
+
265
+ # Handle common OCR misreads
266
+ replacements = {
267
+ '0': 'o', 'l': 'i', '1': 'i',
268
+ '5': 's', '8': 'b', 'Q': 'g',
269
+ }
270
+
271
+ for error, correction in replacements.items():
272
+ text = text.replace(error, correction)
273
+
274
+ # Split by common ingredient separators
275
+ ingredients = re.split(r',|;|\n', text)
276
+
277
+ # Clean up each ingredient
278
+ cleaned_ingredients = []
279
+ for i in ingredients:
280
+ i = i.strip().lower()
281
+ if i and len(i) > 1: # Ignore single characters which are likely OCR errors
282
+ cleaned_ingredients.append(i)
283
+
284
+ return cleaned_ingredients
285
+
286
+ def identify_product_and_get_ingredients(image):
287
+ """
288
+ Identifies the product from the image using OpenAI and retrieves ingredients.
289
+ """
290
+ try:
291
+ # Encode the image to base64
292
+ buffered = io.BytesIO()
293
+ image.save(buffered, format="JPEG")
294
+ img_str = base64.b64encode(buffered.getvalue()).decode('utf-8')
295
+
296
+ headers = {
297
+ "Content-Type": "application/json",
298
+ "Authorization": f"Bearer {OPENAI_API_KEY}"
299
+ }
300
+
301
+ payload = {
302
+ "model": "gpt-4-vision-preview",
303
+ "messages": [
304
+ {
305
+ "role": "user",
306
+ "content": [
307
+ {
308
+ "type": "text",
309
+ "text": "Identify the food product in this image. If identifiable, also find its ingredients."
310
+ },
311
+ {
312
+ "type": "image_url",
313
+ "image_url": {
314
+ "url": f"data:image/jpeg;base64,{img_str}"
315
+ }
316
+ }
317
+ ]
318
+ }
319
+ ],
320
+ "max_tokens": 500
321
+ }
322
+
323
+ response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
324
+ response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
325
+
326
+ data = response.json()
327
+ response_text = data['choices'][0]['message']['content']
328
+
329
+ # Attempt to extract ingredients from the response
330
+ ingredients_match = re.search(r"Ingredients:\s*(.+)", response_text, re.IGNORECASE)
331
+ if ingredients_match:
332
+ ingredients_text = ingredients_match.group(1)
333
+ ingredients = parse_ingredients(ingredients_text)
334
+ return ingredients, response_text
335
+ else:
336
+ # If ingredients not found, return the full response for further handling
337
+ return None, response_text
338
+
339
+ except requests.exceptions.RequestException as e:
340
+ return None, f"Error during OpenAI API request: {e}"
341
+ except json.JSONDecodeError as e:
342
+ return None, f"Error decoding JSON response from OpenAI: {e}"
343
+ except Exception as e:
344
+ return None, f"Error identifying product: {e}"
345
+
346
+ # Function to process input based on method (camera, upload, or manual entry)
347
+ def process_input(input_method, text_input, camera_input, upload_input, health_conditions):
348
+ if input_method == "Camera":
349
+ if camera_input is not None:
350
+ ingredients, response_text = identify_product_and_get_ingredients(camera_input)
351
+
352
+ if ingredients:
353
+ return analyze_ingredients_with_mistral(ingredients, health_conditions), response_text
354
+ else:
355
+ return f"Could not identify ingredients from the image. Response from OpenAI:\n\n{response_text}", response_text
356
+
357
+ else:
358
+ return "No camera image captured. Please try again.", ""
359
+
360
+ elif input_method == "Image Upload":
361
+ if upload_input is not None:
362
+ ingredients, response_text = identify_product_and_get_ingredients(upload_input)
363
+ if ingredients:
364
+ return analyze_ingredients_with_mistral(ingredients, health_conditions), response_text
365
+ else:
366
+ return f"Could not identify ingredients from the image. Response from OpenAI:\n\n{response_text}", response_text
367
+
368
+ else:
369
+ return "No image uploaded. Please try again.", ""
370
+
371
+ elif input_method == "Manual Entry":
372
+ if text_input and text_input.strip():
373
+ ingredients = parse_ingredients(text_input)
374
+ return analyze_ingredients_with_mistral(ingredients, health_conditions), ""
375
  else:
376
  return "No ingredients entered. Please try again.", ""
377
+
378
+ return "Please provide input using one of the available methods.", ""
 
 
 
 
 
 
 
 
 
379
 
380
  # Create the Gradio interface
381
  with gr.Blocks(title="AI Ingredient Scanner") as app:
382
  gr.Markdown("# AI Ingredient Scanner")
383
+ gr.Markdown("Scan product ingredients and analyze them for health benefits, risks, and potential allergens.")
384
 
385
  with gr.Row():
386
  with gr.Column():
387
+ input_method = gr.Radio(
388
+ ["Camera", "Image Upload", "Manual Entry"],
389
+ label="Input Method",
390
+ value="Camera"
 
 
 
 
 
 
 
391
  )
392
+
393
+ # Camera input
394
+ camera_input = gr.Image(label="Capture image of product", type="pil", visible=True)
395
+
396
+ # Image upload
397
+ upload_input = gr.Image(label="Upload image of product", type="pil", visible=False)
398
+
399
+ # Text input
400
+ text_input = gr.Textbox(
401
  label="Enter ingredients list (comma separated)",
402
  placeholder="milk, sugar, flour, eggs, vanilla extract",
403
  lines=3,
404
  visible=False
405
  )
406
 
407
+ # Health conditions input - now optional and more flexible
408
  health_conditions = gr.Textbox(
409
  label="Enter your health concerns (optional)",
410
  placeholder="diabetes, high blood pressure, peanut allergy, etc.",
 
416
 
417
  with gr.Column():
418
  output = gr.Markdown(label="Analysis Results")
419
+ extracted_text_output = gr.Textbox(label="Extracted Response from OpenAI", lines=5)
420
 
421
+ # Show/hide inputs based on selection
422
+ def update_visible_inputs(choice):
423
  return {
424
+ upload_input: gr.update(visible=(choice == "Image Upload")),
425
+ camera_input: gr.update(visible=(choice == "Camera")),
426
+ text_input: gr.update(visible=(choice == "Manual Entry"))
427
  }
428
 
429
+ input_method.change(update_visible_inputs, input_method, [upload_input, camera_input, text_input])
430
 
431
  # Set up event handlers
432
  analyze_button.click(
433
+ fn=process_input,
434
+ inputs=[input_method, text_input, camera_input, upload_input, health_conditions],
435
+ outputs=[output, extracted_text_output]
436
  )
437
 
438
  gr.Markdown("### How to use")
439
  gr.Markdown("""
440
+ 1. Choose your input method (Camera, Image Upload, or Manual Entry)
441
+ 2. Take a photo of the product or upload an image, or enter ingredients manually
442
  3. Optionally enter your health concerns
443
  4. Click "Analyze Ingredients" to get your personalized analysis
444
+ The AI will automatically identify the product and analyze the ingredients, their health implications, and their potential impact on your specific health concerns.
 
445
  """)
446
 
447
  gr.Markdown("### Examples of what you can ask")
 
457
 
458
  gr.Markdown("### Tips for best results")
459
  gr.Markdown("""
460
+ - Hold the camera steady and ensure good lighting
461
+ - Focus directly on the product, including its label
462
+ - Make sure the product is clearly visible
463
  - Be specific about your health concerns for more targeted analysis
 
464
  """)
465
 
466
  gr.Markdown("### Disclaimer")
 
471
 
472
  # Launch the app
473
  if __name__ == "__main__":
474
+ import io
475
+ import base64
476
  app.launch()