tdurzynski commited on
Commit
536cfbe
·
verified ·
1 Parent(s): aff331d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +155 -0
app.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import cv2
3
+ import numpy as np
4
+ from transformers import pipeline
5
+ import requests
6
+ from PIL import Image
7
+ from autogen import AssistantAgent, GroupChat, GroupChatManager
8
+ import os
9
+ import openai
10
+
11
+ # Multi-label recognition model (placeholder - swap for fine-tuned multi-label later)
12
+ recognizer = pipeline("image-classification", model="google/vit-base-patch16-224")
13
+
14
+ # Agent Definitions
15
+ food_recognizer = AssistantAgent(
16
+ name="FoodRecognizer",
17
+ system_message="Identify all food items in the image and return a list of (label, probability) pairs."
18
+ )
19
+
20
+ size_estimator = AssistantAgent(
21
+ name="SizeEstimator",
22
+ system_message="Estimate portion sizes in grams for each recognized food based on the image."
23
+ )
24
+
25
+ nutrition_fetcher = AssistantAgent(
26
+ name="NutritionFetcher",
27
+ system_message="Fetch nutritional data from the Nutritionix API using the user's key."
28
+ )
29
+
30
+ advice_agent = AssistantAgent(
31
+ name="NutritionAdvisor",
32
+ system_message="Provide basic nutrition advice using the user's OpenAI/Grok key."
33
+ )
34
+
35
+ orchestrator = AssistantAgent(
36
+ name="Orchestrator",
37
+ system_message="Coordinate the workflow and format output."
38
+ )
39
+
40
+ group_chat = GroupChat(
41
+ agents=[food_recognizer, size_estimator, nutrition_fetcher, advice_agent, orchestrator],
42
+ messages=[],
43
+ max_round=10
44
+ )
45
+ manager = GroupChatManager(groupchat=group_chat)
46
+
47
+ # Agent Functions
48
+ def recognize_foods(image):
49
+ pil_image = Image.fromarray(image)
50
+ predictions = recognizer(pil_image)
51
+ foods = [(pred["label"], pred["score"]) for pred in predictions if pred["score"] > 0.5]
52
+ return foods
53
+
54
+ def estimate_sizes(image, foods):
55
+ img_cv = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
56
+ height, width = img_cv.shape[:2]
57
+ total_pixels = height * width
58
+ portion_per_food = total_pixels / len(foods)
59
+ sizes = {food: min(500, int(portion_per_food / 1000 * 100)) for food, _ in foods}
60
+ return sizes
61
+
62
+ def fetch_nutrition(foods_with_sizes, nutritionix_key):
63
+ if not nutritionix_key:
64
+ return "Please provide a Nutritionix API key for nutrition data."
65
+
66
+ url = "https://trackapi.nutritionix.com/v2/natural/nutrients"
67
+ headers = {
68
+ "x-app-id": "your_nutritionix_app_id", # Your app ID in HF Secrets
69
+ "x-app-key": nutritionix_key, # User's key
70
+ "Content-Type": "application/json"
71
+ }
72
+ # Build query from foods and sizes
73
+ query = "\n".join([f"{size}g {food}" for food, size in foods_with_sizes.items()])
74
+ body = {"query": query}
75
+
76
+ response = requests.post(url, headers=headers, json=body)
77
+ if response.status_code != 200:
78
+ return f"Nutritionix API error: {response.text}"
79
+
80
+ data = response.json().get("foods", [])
81
+ nutrition_data = {}
82
+ for item in data:
83
+ food_name = item["food_name"]
84
+ nutrition_data[food_name] = {
85
+ "calories": item.get("nf_calories", 0),
86
+ "protein": item.get("nf_protein", 0),
87
+ "fat": item.get("nf_total_fat", 0),
88
+ "carbs": item.get("nf_total_carbohydrate", 0)
89
+ }
90
+ return nutrition_data
91
+
92
+ def get_nutrition_advice(nutrition_data, llm_key):
93
+ if not llm_key:
94
+ return "No OpenAI/Grok key provided—skipping advice."
95
+ try:
96
+ openai.api_key = llm_key
97
+ prompt = "Given this nutritional data, suggest a dietary tip:\n"
98
+ for food, data in nutrition_data.items():
99
+ prompt += f"- {food}: {data['calories']} cal, {data['protein']}g protein, {data['fat']}g fat, {data['carbs']}g carbs\n"
100
+
101
+ response = openai.Completion.create(
102
+ model="text-davinci-003", # Swap for Grok if xAI API is available
103
+ prompt=prompt,
104
+ max_tokens=50
105
+ )
106
+ return response.choices[0].text.strip()
107
+ except Exception as e:
108
+ return f"Error with LLM key: {str(e)}"
109
+
110
+ def orchestrate_workflow(image, nutritionix_key, llm_key):
111
+ # Step 1: Recognize foods
112
+ foods = recognize_foods(image)
113
+ if not foods:
114
+ return "No foods recognized. Try a clearer image!", ""
115
+
116
+ # Step 2: Estimate sizes
117
+ sizes = estimate_sizes(image, foods)
118
+
119
+ # Step 3: Fetch nutrition with user's Nutritionix key
120
+ nutrition = fetch_nutrition({food: size for food, _ in foods}, nutritionix_key)
121
+ if isinstance(nutrition, str): # Error message
122
+ return nutrition, ""
123
+
124
+ # Step 4: Generate advice with user's LLM key
125
+ advice = get_nutrition_advice(nutrition, llm_key)
126
+
127
+ # Format output
128
+ result = "Food Analysis:\n"
129
+ for food, prob in foods:
130
+ if food in nutrition:
131
+ data = nutrition[food]
132
+ result += (f"- {food} ({sizes[food]}g, {prob:.2%} confidence): "
133
+ f"{data['calories']} cal, {data['protein']:.1f}g protein, "
134
+ f"{data['fat']:.1f}g fat, {data['carbs']:.1f}g carbs\n")
135
+
136
+ return result, advice
137
+
138
+ # Gradio Interface
139
+ interface = gr.Interface(
140
+ fn=orchestrate_workflow,
141
+ inputs=[
142
+ gr.Image(type="numpy", label="Upload a Food Photo"),
143
+ gr.Textbox(type="password", label="Your Nutritionix API Key (required)"),
144
+ gr.Textbox(type="password", label="Your OpenAI/Grok API Key (optional for advice)")
145
+ ],
146
+ outputs=[
147
+ gr.Textbox(label="Nutrition Breakdown"),
148
+ gr.Textbox(label="Nutrition Advice")
149
+ ],
150
+ title="Food Nutrition Analyzer",
151
+ description="Upload a food photo and provide your Nutritionix API key. Add an OpenAI/Grok key for advice."
152
+ )
153
+
154
+ if __name__ == "__main__":
155
+ interface.launch()