AdeogunTechno commited on
Commit
e626858
·
verified ·
1 Parent(s): b343718

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +100 -1
app.py CHANGED
@@ -1 +1,100 @@
1
- python <br># ------------------------------------------------------------ <br># FastAPI service exposing BinhQuocNguyen/food‑recognition‑model <br># ------------------------------------------------------------ <br>from fastapi import FastAPI, HTTPException <br>from pydantic import BaseModel <br>import base64, io <br>from PIL import Image <br>from transformers import pipeline <br> <br># ------------------------------------------------------------------- <br># 1️⃣ Load the model once at startup (fast, no re‑load per request) <br># ------------------------------------------------------------ <br>classifier = pipeline( <br> \"image-classification\", <br> model=\"BinhQuocNguyen/food-recognition-model\" <br>) <br> <br># ------------------------------------------------------------------- <br># 2️⃣ Simple in‑memory “nutritional DB” – you can extend it with all 101 classes <br># ------------------------------------------------------------------- <br># (calories per 100 g, avg portion weight in grams) <br>nutrient_db = { <br> \"Apple\": {\"calories_per_100g\": 52, \"portion_g\": 182}, <br> \"Banana\": {\"calories_per_100g\": 89, \"portion_g\": 118}, <br> \"Orange\": {\"calories_per_100g\": 43, \"portion_g\": 131}, <br> \"Pizza\": {\"calories_per_100g\": 266, \"portion_g\": 200}, <br> \"Bread\": {\"calories_per_100g\": 265, \"portion_g\": 30}, <br> # ← add the rest of your favourite foods here <br>} <br> <br># ------------------------------------------------------------------- <br># 3️⃣ Pydantic model for the incoming JSON payload <br># ------------------------------------------------------------------- <br>class ImageRequest(BaseModel): <br> image: str <br> <br>app = FastAPI() <br> <br># ------------------------------------------------------------ <br># Health‑check endpoint (optional) <br># ------------------------------------------------------------ <br>@app.get(\"/\") <br>def root(): <br> return {\"message\": \"Food‑Recognition API is up\"} <br> <br># ------------------------------------------------------------ <br># 4️⃣ Main inference endpoint <br># ------------------------------------------------------------ <br>@app.post(\"/analyze\") <br>def analyze(request: ImageRequest): <br> # ---- decode the base64 image -------------------------------- <br> try: <br> raw_bytes = base64.b64decode(request.image) <br> pil_img = Image.open(io.BytesIO(raw_bytes)).convert(\"RGB\") <br> except Exception as e: <br> raise HTTPException(status_code=400, detail=\"Invalid base64 image\") <br> <br> # ---- run the classifier -------------------------------------- <br> results = classifier(pil_img) <br> if not results: <br> raise HTTPException(status_code=500, detail=\"Model returned no results\") <br> top = results[0] <br> label = top.get(\"label\") <br> confidence = top.get(\"score\") <br> <br> # ---- look up nutrition data ----------------------------------- <br> # The model’s own DB is not directly exposed, so we use the inline dict above <br> nutrition = nutrient_db.get(label, {\"calories_per_100g\": 0, \"portion_g\": 100}) <br> calories_per_100g = nutrition[\"calories_per_100g\"] <br> portion_g = nutrition[\"portion_g\"] <br> # Estimated calories for the (default) portion size <br> est_calories = calories_per_100g * (portion_g / 100.0) <br> <br> # ---- build the JSON response -------------------------------- <br> return { <br> \"label\": label, <br> \"confidence\": confidence, <br> \"estimated_portion_g\": portion_g, <br> \"calories_per_100g\": calories_per_100g, <br> \"estimated_calories\": round(est_calories, 2) <br> } <br>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ FastAPI service exposing BinhQuocNguyen/food‑recognition‑model.
3
+ """
4
+
5
+ # ------------------------------------------------------------
6
+ # 1️⃣ Imports
7
+ # ------------------------------------------------------------
8
+ from fastapi import FastAPI, HTTPException
9
+ from pydantic import BaseModel
10
+ import base64
11
+ import io
12
+
13
+ from PIL import Image
14
+ from transformers import pipeline
15
+
16
+ # ------------------------------------------------------------
17
+ # 2️⃣ Load the model once at startup (fast, no re‑load per request)
18
+ # ------------------------------------------------------------
19
+ classifier = pipeline(
20
+ "image-classification",
21
+ model="BinhQuocNguyen/food-recognition-model"
22
+ )
23
+
24
+ # ------------------------------------------------------------
25
+ # 3️⃣ Simple in‑memory “nutritional DB”
26
+ # (calories per 100 g, average portion weight in grams)
27
+ # ------------------------------------------------------------
28
+ nutrient_db = {
29
+ "Apple": {"calories_per_100g": 52, "portion_g": 182},
30
+ "Banana": {"calories_per_100g": 89, "portion_g": 118},
31
+ "Orange": {"calories_per_100g": 43, "portion_g": 131},
32
+ "Pizza": {"calories_per_100g": 266, "portion_g": 200},
33
+ "Bread": {"calories_per_100g": 265, "portion_g": 30},
34
+ # ← add the rest of your favourite foods here
35
+ }
36
+
37
+ # ------------------------------------------------------------
38
+ # 4️⃣ Pydantic model for the incoming JSON payload
39
+ # ------------------------------------------------------------
40
+ class ImageRequest(BaseModel):
41
+ """Base64‑encoded image sent by the client."""
42
+ image: str
43
+
44
+
45
+ # ------------------------------------------------------------
46
+ # 5️⃣ FastAPI app & health‑check endpoint
47
+ # ------------------------------------------------------------
48
+ app = FastAPI()
49
+
50
+
51
+ @app.get("/")
52
+ def root():
53
+ """Simple health‑check."""
54
+ return {"message": "Food‑Recognition API is up"}
55
+
56
+
57
+ # ------------------------------------------------------------
58
+ # 6️⃣ Main inference endpoint
59
+ # ------------------------------------------------------------
60
+ @app.post("/analyze")
61
+ def analyze(request: ImageRequest):
62
+ """
63
+ 1️⃣ Decode the base64 image.
64
+ 2️⃣ Run the classifier.
65
+ 3️⃣ Look up (or fall back to) nutritional information.
66
+ 4️⃣ Return a JSON response.
67
+ """
68
+ # ---- 1️⃣ decode the base64 image ---------------------------------
69
+ try:
70
+ raw_bytes = base64.b64decode(request.image)
71
+ pil_img = Image.open(io.BytesIO(raw_bytes)).convert("RGB")
72
+ except Exception as e: # pragma: no cover
73
+ raise HTTPException(status_code=400, detail="Invalid base64 image") from e
74
+
75
+ # ---- 2️⃣ run the classifier --------------------------------------
76
+ results = classifier(pil_img)
77
+ if not results:
78
+ raise HTTPException(status_code=500, detail="Model returned no results")
79
+
80
+ top = results[0]
81
+ label = top.get("label")
82
+ confidence = top.get("score")
83
+
84
+ # ---- 3️⃣ look up nutrition data ----------------------------------
85
+ # Fallback values if the label isn’t in the DB
86
+ nutrition = nutrient_db.get(label, {"calories_per_100g": 0, "portion_g": 100})
87
+ calories_per_100g = nutrition["calories_per_100g"]
88
+ portion_g = nutrition["portion_g"]
89
+
90
+ # ---- 4️⃣ estimated calories for the default portion size ----------
91
+ est_calories = calories_per_100g * (portion_g / 100.0)
92
+
93
+ # ---- 5️⃣ build the JSON response --------------------------------
94
+ return {
95
+ "label": label,
96
+ "confidence": confidence,
97
+ "estimated_portion_g": portion_g,
98
+ "calories_per_100g": calories_per_100g,
99
+ "estimated_calories": round(est_calories, 2),
100
+ }