AdeogunTechno's picture
Update app.py
e626858 verified
Raw
History Blame
3.66 kB
"""
FastAPI service exposing BinhQuocNguyen/food‑recognition‑model.
"""
# ------------------------------------------------------------
# 1️⃣ Imports
# ------------------------------------------------------------
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import base64
import io
from PIL import Image
from transformers import pipeline
# ------------------------------------------------------------
# 2️⃣ Load the model once at startup (fast, no re‑load per request)
# ------------------------------------------------------------
classifier = pipeline(
"image-classification",
model="BinhQuocNguyen/food-recognition-model"
)
# ------------------------------------------------------------
# 3️⃣ Simple in‑memory “nutritional DB”
# (calories per 100 g, average portion weight in grams)
# ------------------------------------------------------------
nutrient_db = {
"Apple": {"calories_per_100g": 52, "portion_g": 182},
"Banana": {"calories_per_100g": 89, "portion_g": 118},
"Orange": {"calories_per_100g": 43, "portion_g": 131},
"Pizza": {"calories_per_100g": 266, "portion_g": 200},
"Bread": {"calories_per_100g": 265, "portion_g": 30},
# ← add the rest of your favourite foods here
}
# ------------------------------------------------------------
# 4️⃣ Pydantic model for the incoming JSON payload
# ------------------------------------------------------------
class ImageRequest(BaseModel):
"""Base64‑encoded image sent by the client."""
image: str
# ------------------------------------------------------------
# 5️⃣ FastAPI app & health‑check endpoint
# ------------------------------------------------------------
app = FastAPI()
@app.get("/")
def root():
"""Simple health‑check."""
return {"message": "Food‑Recognition API is up"}
# ------------------------------------------------------------
# 6️⃣ Main inference endpoint
# ------------------------------------------------------------
@app.post("/analyze")
def analyze(request: ImageRequest):
"""
1️⃣ Decode the base64 image.
2️⃣ Run the classifier.
3️⃣ Look up (or fall back to) nutritional information.
4️⃣ Return a JSON response.
"""
# ---- 1️⃣ decode the base64 image ---------------------------------
try:
raw_bytes = base64.b64decode(request.image)
pil_img = Image.open(io.BytesIO(raw_bytes)).convert("RGB")
except Exception as e: # pragma: no cover
raise HTTPException(status_code=400, detail="Invalid base64 image") from e
# ---- 2️⃣ run the classifier --------------------------------------
results = classifier(pil_img)
if not results:
raise HTTPException(status_code=500, detail="Model returned no results")
top = results[0]
label = top.get("label")
confidence = top.get("score")
# ---- 3️⃣ look up nutrition data ----------------------------------
# Fallback values if the label isn’t in the DB
nutrition = nutrient_db.get(label, {"calories_per_100g": 0, "portion_g": 100})
calories_per_100g = nutrition["calories_per_100g"]
portion_g = nutrition["portion_g"]
# ---- 4️⃣ estimated calories for the default portion size ----------
est_calories = calories_per_100g * (portion_g / 100.0)
# ---- 5️⃣ build the JSON response --------------------------------
return {
"label": label,
"confidence": confidence,
"estimated_portion_g": portion_g,
"calories_per_100g": calories_per_100g,
"estimated_calories": round(est_calories, 2),
}