version_2 / app.py
rishab1090's picture
Update app.py
e5f294b verified
import gradio as gr
import os
import json
import requests
from PIL import Image
from difflib import get_close_matches
from functools import lru_cache
# =====================
# ENV
# =====================
ROBOFLOW_API_KEY = os.getenv("ROBOFLOW_API_KEY")
# =====================
# LOAD DB
# =====================
with open("nutrition_db.json", "r") as f:
NUTRITION_DB = json.load(f)
print("βœ… Loaded DB:", len(NUTRITION_DB))
# =====================
# NORMALIZATION
# =====================
def normalize_food_name(name):
name = name.lower()
mapping = {
"chapati": "wheat",
"roti": "wheat",
"naan": "wheat",
"paratha": "wheat",
"omelette": "egg",
"omellete": "egg",
"fried rice": "rice",
"plain rice": "rice"
}
return mapping.get(name, name)
# =====================
# FIND MATCH
# =====================
def find_food(name):
if name in NUTRITION_DB:
return name
matches = get_close_matches(name, NUTRITION_DB.keys(), n=1, cutoff=0.6)
return matches[0] if matches else None
# =====================
# FALLBACK
# =====================
def estimate_unknown_food(grams):
return {
"calories": round(1.5 * grams, 2),
"protein": round(0.05 * grams, 2),
"carbs": round(0.2 * grams, 2),
"fat": round(0.05 * grams, 2),
}
# =====================
# CACHE
# =====================
@lru_cache(maxsize=1000)
def compute_nutrition_cached(food_key, grams):
base = NUTRITION_DB[food_key]
factor = grams / 100
return {
"calories": round(base["calories"] * factor, 2),
"protein": round(base["protein"] * factor, 2),
"carbs": round(base["carbs"] * factor, 2),
"fat": round(base["fat"] * factor, 2),
}
# =====================
# GET NUTRITION
# =====================
def get_nutrition(dish, grams):
dish = normalize_food_name(dish)
food_key = find_food(dish)
if not food_key:
return estimate_unknown_food(grams)
return compute_nutrition_cached(food_key, grams)
# =====================
# QUANTITY
# =====================
def estimate_quantity(pred):
width = pred.get("width", 0)
height = pred.get("height", 0)
area = width * height
ratio = area / (640 * 640)
grams = 150 + (ratio * 300)
return round(grams, 1)
# =====================
# ROBOFLOW (HTTP)
# =====================
import requests
import os
def detect(image_path):
api_key = os.getenv("ROBOFLOW_API_KEY")
if not api_key:
return "❌ API KEY NOT FOUND"
# model_id = "almost-final/1"
url = "https://detect.roboflow.com/almost-final/1"
try:
with open(image_path, "rb") as f:
response = requests.post(
url,
files={"file": f}, # βœ… correct format
params={"api_key": api_key},
timeout=15
)
print("STATUS:", response.status_code)
print("RESPONSE:", response.text)
if response.status_code != 200:
return f"❌ Roboflow Error: {response.text}"
data = response.json()
return data.get("predictions", [])
except Exception as e:
return f"❌ Request Failed: {str(e)}"
# =====================
# MAIN FUNCTION
# =====================
def analyze_image(image):
if image is None:
return "Please upload an image"
path = "temp.jpg"
# PIL image save
image.save(path)
preds = detect(path)
if isinstance(preds, str):
return preds
if len(preds) == 0:
return "❌ No food detected"
output = ""
total = {"calories": 0, "protein": 0, "carbs": 0, "fat": 0}
for pred in preds:
dish = pred.get("class", "unknown")
grams = estimate_quantity(pred)
nutrition = get_nutrition(dish, grams)
output += f"🍽️ {dish}\n"
output += f"πŸ“ {grams} g\n"
output += f"πŸ”₯ {nutrition['calories']} kcal\n"
output += f"πŸ’ͺ Protein: {nutrition['protein']} g\n"
output += f"🍞 Carbs: {nutrition['carbs']} g\n"
output += f"🧈 Fat: {nutrition['fat']} g\n"
output += "-"*30 + "\n"
for k in total:
total[k] += nutrition[k]
output += "\n🧾 TOTAL:\n"
output += f"πŸ”₯ Calories: {round(total['calories'],2)}\n"
output += f"πŸ’ͺ Protein: {round(total['protein'],2)} g\n"
output += f"🍞 Carbs: {round(total['carbs'],2)} g\n"
output += f"🧈 Fat: {round(total['fat'],2)} g\n"
return output
# =====================
# UI
# =====================
demo = gr.Interface(
fn=analyze_image,
inputs=gr.Image(type="pil"), # βœ… FIXED
outputs="text",
title="🍽️ AI Nutritionist",
description="Upload food image to get calories & macros"
)
# =====================
# RUN
# =====================
if __name__ == "__main__":
demo.launch(ssr_mode=False)