Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from transformers import pipeline
|
| 3 |
+
|
| 4 |
+
#
|
| 5 |
+
# 1) Load a broad food classification model
|
| 6 |
+
# This recognizes 100+ food categories (food101).
|
| 7 |
+
#
|
| 8 |
+
food_classifier = pipeline(
|
| 9 |
+
"image-classification",
|
| 10 |
+
model="nateraw/food101"
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
def estimate_health_and_calories(dish_name: str):
|
| 14 |
+
|
| 15 |
+
dish_lower = dish_name.lower()
|
| 16 |
+
|
| 17 |
+
# Basic logic: healthy if it sounds like salad, fruit, etc.,
|
| 18 |
+
# less healthy if it sounds like fried, sugary, or dessert.
|
| 19 |
+
|
| 20 |
+
if any(k in dish_lower for k in ["salad", "fruit", "broccoli", "tomato", "carrot", "spinach"]):
|
| 21 |
+
health = 9
|
| 22 |
+
calories = 80
|
| 23 |
+
elif any(k in dish_lower for k in ["fried", "pizza", "burger", "bacon", "cream", "chips"]):
|
| 24 |
+
health = 3
|
| 25 |
+
calories = 350
|
| 26 |
+
elif any(k in dish_lower for k in ["cake", "pastry", "dessert", "cookie", "chocolate"]):
|
| 27 |
+
health = 2
|
| 28 |
+
calories = 400
|
| 29 |
+
elif any(k in dish_lower for k in ["soup", "stew", "chili"]):
|
| 30 |
+
health = 7
|
| 31 |
+
calories = 150
|
| 32 |
+
elif any(k in dish_lower for k in ["sandwich", "wrap", "taco"]):
|
| 33 |
+
health = 6
|
| 34 |
+
calories = 250
|
| 35 |
+
else:
|
| 36 |
+
# Default fallback
|
| 37 |
+
health = 5
|
| 38 |
+
calories = 200
|
| 39 |
+
|
| 40 |
+
return health, calories
|
| 41 |
+
|
| 42 |
+
def analyze_image(image):
|
| 43 |
+
|
| 44 |
+
# Run the model
|
| 45 |
+
outputs = food_classifier(image)
|
| 46 |
+
|
| 47 |
+
# Each output item is like {'label': 'omelette', 'score': 0.98}
|
| 48 |
+
# Sort by descending confidence (not strictly necessary if pipeline does so by default)
|
| 49 |
+
outputs = sorted(outputs, key=lambda x: x["score"], reverse=True)
|
| 50 |
+
top_label = outputs[0]["label"]
|
| 51 |
+
top_score = outputs[0]["score"]
|
| 52 |
+
|
| 53 |
+
# Confidence threshold to decide if it's "real food" or not
|
| 54 |
+
if top_score < 0.5:
|
| 55 |
+
return "The picture does not depict any food, please upload a different photo."
|
| 56 |
+
|
| 57 |
+
# If we pass the threshold, treat the top label as recognized dish
|
| 58 |
+
health_rating, cal_estimate = estimate_health_and_calories(top_label)
|
| 59 |
+
|
| 60 |
+
# Build response text
|
| 61 |
+
return (
|
| 62 |
+
f"**Food Identified**: {top_label} (confidence: {top_score:.2f})\n\n"
|
| 63 |
+
f"**Health Rating** (1 = extremely unhealthy, 10 = extremely healthy): **{health_rating}**\n\n"
|
| 64 |
+
f"**Estimated Calories**: ~{cal_estimate} kcal per serving\n\n"
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
# Build a nice Gradio interface
|
| 69 |
+
demo = gr.Interface(
|
| 70 |
+
fn=analyze_image,
|
| 71 |
+
inputs=gr.Image(type="pil"), # PIL image
|
| 72 |
+
outputs="markdown",
|
| 73 |
+
title="Universal Food Recognizer",
|
| 74 |
+
description=(
|
| 75 |
+
"Upload a photo of a dish or ingredient. "
|
| 76 |
+
"We'll attempt to recognize it (from 100+ categories) and rate how healthy it is, "
|
| 77 |
+
"along with a rough calorie estimate. "
|
| 78 |
+
"If no food is detected, you'll see an error message."
|
| 79 |
+
),
|
| 80 |
+
allow_flagging="never", # optional: hides the 'flag' button for simpler UI
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
if __name__ == "__main__":
|
| 84 |
+
demo.launch()
|