rishab1090 commited on
Commit
c2cd6cd
Β·
verified Β·
1 Parent(s): a23564e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -30
app.py CHANGED
@@ -5,6 +5,7 @@ import requests
5
  from PIL import Image
6
  from difflib import get_close_matches
7
  from functools import lru_cache
 
8
 
9
  # =====================
10
  # ENV
@@ -20,18 +21,27 @@ with open("nutrition_db.json", "r") as f:
20
  print("βœ… Loaded DB:", len(NUTRITION_DB))
21
 
22
  # =====================
23
- # NORMALIZATION
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  # =====================
25
  def normalize_food_name(name):
26
  name = name.lower()
27
 
28
  mapping = {
29
- "chapati": "wheat",
30
- "roti": "wheat",
31
- "naan": "wheat",
32
- "paratha": "wheat",
33
- "omelette": "egg",
34
- "omellete": "egg",
35
  "fried rice": "rice",
36
  "plain rice": "rice"
37
  }
@@ -87,7 +97,7 @@ def get_nutrition(dish, grams):
87
  return compute_nutrition_cached(food_key, grams)
88
 
89
  # =====================
90
- # QUANTITY
91
  # =====================
92
  def estimate_quantity(pred):
93
  width = pred.get("width", 0)
@@ -100,53 +110,42 @@ def estimate_quantity(pred):
100
  return round(grams, 1)
101
 
102
  # =====================
103
- # ROBOFLOW (HTTP)
104
  # =====================
105
-
106
-
107
- import requests
108
- import os
109
-
110
  def detect(image_path):
111
  api_key = os.getenv("ROBOFLOW_API_KEY")
112
 
113
  if not api_key:
114
  return "❌ API KEY NOT FOUND"
115
 
116
- # model_id = "almost-final/1"
117
  url = "https://detect.roboflow.com/almost-final/2"
118
 
119
  try:
120
  with open(image_path, "rb") as f:
121
  response = requests.post(
122
  url,
123
- files={"file": f}, # βœ… correct format
124
  params={"api_key": api_key},
125
  timeout=15
126
  )
127
 
128
- print("STATUS:", response.status_code)
129
- print("RESPONSE:", response.text)
130
-
131
  if response.status_code != 200:
132
  return f"❌ Roboflow Error: {response.text}"
133
 
134
  data = response.json()
135
-
136
  return data.get("predictions", [])
137
 
138
  except Exception as e:
139
  return f"❌ Request Failed: {str(e)}"
 
140
  # =====================
141
- # MAIN FUNCTION
142
  # =====================
143
  def analyze_image(image):
144
  if image is None:
145
  return "Please upload an image"
146
 
147
  path = "temp.jpg"
148
-
149
- # PIL image save
150
  image.save(path)
151
 
152
  preds = detect(path)
@@ -157,17 +156,53 @@ def analyze_image(image):
157
  if len(preds) == 0:
158
  return "❌ No food detected"
159
 
 
 
 
 
 
160
  output = ""
161
  total = {"calories": 0, "protein": 0, "carbs": 0, "fat": 0}
162
 
163
- for pred in preds:
164
- dish = pred.get("class", "unknown")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
- grams = estimate_quantity(pred)
167
- nutrition = get_nutrition(dish, grams)
168
 
169
- output += f"🍽️ {dish}\n"
170
- output += f"πŸ“ {grams} g\n"
 
171
  output += f"πŸ”₯ {nutrition['calories']} kcal\n"
172
  output += f"πŸ’ͺ Protein: {nutrition['protein']} g\n"
173
  output += f"🍞 Carbs: {nutrition['carbs']} g\n"
@@ -177,6 +212,7 @@ def analyze_image(image):
177
  for k in total:
178
  total[k] += nutrition[k]
179
 
 
180
  output += "\n🧾 TOTAL:\n"
181
  output += f"πŸ”₯ Calories: {round(total['calories'],2)}\n"
182
  output += f"πŸ’ͺ Protein: {round(total['protein'],2)} g\n"
@@ -190,7 +226,7 @@ def analyze_image(image):
190
  # =====================
191
  demo = gr.Interface(
192
  fn=analyze_image,
193
- inputs=gr.Image(type="pil"), # βœ… FIXED
194
  outputs="text",
195
  title="🍽️ AI Nutritionist",
196
  description="Upload food image to get calories & macros"
 
5
  from PIL import Image
6
  from difflib import get_close_matches
7
  from functools import lru_cache
8
+ from collections import Counter
9
 
10
  # =====================
11
  # ENV
 
21
  print("βœ… Loaded DB:", len(NUTRITION_DB))
22
 
23
  # =====================
24
+ # COUNTABLE FOODS (NEW)
25
+ # =====================
26
+ COUNTABLE_FOODS = {
27
+ "roti": {"calories": 120, "protein": 3, "carbs": 20, "fat": 2},
28
+ "bread": {"calories": 80, "protein": 3, "carbs": 15, "fat": 1},
29
+ "samosa": {"calories": 260, "protein": 5, "carbs": 30, "fat": 14},
30
+ "gulab jamun": {"calories": 150, "protein": 2, "carbs": 30, "fat": 5},
31
+ "laddu": {"calories": 180, "protein": 3, "carbs": 25, "fat": 8},
32
+ "idli": {"calories": 60, "protein": 2, "carbs": 12, "fat": 1},
33
+ "vada": {"calories": 150, "protein": 4, "carbs": 20, "fat": 8}
34
+ }
35
+
36
+ # =====================
37
+ # NORMALIZATION (FIXED)
38
  # =====================
39
  def normalize_food_name(name):
40
  name = name.lower()
41
 
42
  mapping = {
43
+ "chapati": "roti",
44
+ "omellete": "omelette",
 
 
 
 
45
  "fried rice": "rice",
46
  "plain rice": "rice"
47
  }
 
97
  return compute_nutrition_cached(food_key, grams)
98
 
99
  # =====================
100
+ # QUANTITY ESTIMATION
101
  # =====================
102
  def estimate_quantity(pred):
103
  width = pred.get("width", 0)
 
110
  return round(grams, 1)
111
 
112
  # =====================
113
+ # ROBOFLOW DETECTION
114
  # =====================
 
 
 
 
 
115
  def detect(image_path):
116
  api_key = os.getenv("ROBOFLOW_API_KEY")
117
 
118
  if not api_key:
119
  return "❌ API KEY NOT FOUND"
120
 
 
121
  url = "https://detect.roboflow.com/almost-final/2"
122
 
123
  try:
124
  with open(image_path, "rb") as f:
125
  response = requests.post(
126
  url,
127
+ files={"file": f},
128
  params={"api_key": api_key},
129
  timeout=15
130
  )
131
 
 
 
 
132
  if response.status_code != 200:
133
  return f"❌ Roboflow Error: {response.text}"
134
 
135
  data = response.json()
 
136
  return data.get("predictions", [])
137
 
138
  except Exception as e:
139
  return f"❌ Request Failed: {str(e)}"
140
+
141
  # =====================
142
+ # MAIN FUNCTION (HYBRID)
143
  # =====================
144
  def analyze_image(image):
145
  if image is None:
146
  return "Please upload an image"
147
 
148
  path = "temp.jpg"
 
 
149
  image.save(path)
150
 
151
  preds = detect(path)
 
156
  if len(preds) == 0:
157
  return "❌ No food detected"
158
 
159
+ # GROUP ITEMS
160
+ dish_counts = Counter([
161
+ normalize_food_name(p.get("class", "unknown")) for p in preds
162
+ ])
163
+
164
  output = ""
165
  total = {"calories": 0, "protein": 0, "carbs": 0, "fat": 0}
166
 
167
+ for dish, count in dish_counts.items():
168
+
169
+ if dish == "unknown":
170
+ continue
171
+
172
+ # =========================
173
+ # COUNTABLE FOODS
174
+ # =========================
175
+ if dish in COUNTABLE_FOODS:
176
+ base = COUNTABLE_FOODS[dish]
177
+
178
+ nutrition = {
179
+ "calories": base["calories"] * count,
180
+ "protein": base["protein"] * count,
181
+ "carbs": base["carbs"] * count,
182
+ "fat": base["fat"] * count,
183
+ }
184
+
185
+ output += f"🍽️ {dish} ({count} pcs)\n"
186
+
187
+ # =========================
188
+ # WEIGHT-BASED FOODS
189
+ # =========================
190
+ else:
191
+ relevant_preds = [
192
+ p for p in preds if normalize_food_name(p.get("class")) == dish
193
+ ]
194
+
195
+ grams_list = [estimate_quantity(p) for p in relevant_preds]
196
+ grams = sum(grams_list)
197
+
198
+ nutrition = get_nutrition(dish, grams)
199
 
200
+ output += f"🍽️ {dish}\n"
201
+ output += f"πŸ“ {grams:.1f} g\n"
202
 
203
+ # =========================
204
+ # OUTPUT
205
+ # =========================
206
  output += f"πŸ”₯ {nutrition['calories']} kcal\n"
207
  output += f"πŸ’ͺ Protein: {nutrition['protein']} g\n"
208
  output += f"🍞 Carbs: {nutrition['carbs']} g\n"
 
212
  for k in total:
213
  total[k] += nutrition[k]
214
 
215
+ # TOTAL
216
  output += "\n🧾 TOTAL:\n"
217
  output += f"πŸ”₯ Calories: {round(total['calories'],2)}\n"
218
  output += f"πŸ’ͺ Protein: {round(total['protein'],2)} g\n"
 
226
  # =====================
227
  demo = gr.Interface(
228
  fn=analyze_image,
229
+ inputs=gr.Image(type="pil"),
230
  outputs="text",
231
  title="🍽️ AI Nutritionist",
232
  description="Upload food image to get calories & macros"