Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
# Line 1
|
| 2 |
import os
|
| 3 |
import base64
|
| 4 |
from io import BytesIO
|
|
@@ -68,14 +67,24 @@ def crop_image_to_food(img, yolo_results, confidence_threshold=0.2):
|
|
| 68 |
detected_objects = []
|
| 69 |
seen_labels = set()
|
| 70 |
for result in yolo_results:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
for box, cls, conf in zip(result.boxes.xyxy, result.boxes.cls, result.boxes.conf):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
if conf >= confidence_threshold:
|
| 73 |
-
label = result.names[
|
| 74 |
if label not in seen_labels: # Avoid duplicates
|
| 75 |
detected_objects.append({
|
| 76 |
"label": label,
|
| 77 |
"box": box,
|
| 78 |
-
"confidence": conf
|
| 79 |
})
|
| 80 |
seen_labels.add(label)
|
| 81 |
|
|
@@ -286,21 +295,31 @@ def calculate_nutrients(food_items, portion_size, yolo_detections):
|
|
| 286 |
|
| 287 |
return nutrients, micronutrients, 0
|
| 288 |
|
| 289 |
-
# FastAPI endpoint for food analysis
|
| 290 |
@app.post("/analyze_food")
|
| 291 |
async def analyze_food(request: ImageRequest):
|
| 292 |
try:
|
| 293 |
img = decode_base64_image(request.image)
|
| 294 |
yolo_results = yolo_model(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
cropped_img, was_cropped = crop_image_to_food(img, yolo_results)
|
| 296 |
|
| 297 |
# Store YOLO detections for fallback
|
| 298 |
-
yolo_detections = [
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 304 |
|
| 305 |
# Combine LogMeal and Clarifai results with weighted scoring
|
| 306 |
logmeal_results = logmeal_classifier(cropped_img)
|
|
@@ -321,10 +340,15 @@ async def analyze_food(request: ImageRequest):
|
|
| 321 |
food_items = {k: v for k, v in food_items.items() if v >= 0.15}
|
| 322 |
logger.info(f"Combined food items detected: {food_items}")
|
| 323 |
|
| 324 |
-
non_food_items = [
|
| 325 |
-
|
| 326 |
-
for cls in r.boxes.cls
|
| 327 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
is_non_food = len(food_items) == 0 or (len(non_food_items) > len(food_items) and max(food_items.values(), default=0) < 0.3)
|
| 329 |
logger.info(f"Non-food items: {non_food_items}, is_non_food: {is_non_food}")
|
| 330 |
|
|
@@ -338,7 +362,6 @@ async def analyze_food(request: ImageRequest):
|
|
| 338 |
for food, prob in food_items.items()
|
| 339 |
]
|
| 340 |
|
| 341 |
-
# Line ~275: Ensured proper dictionary syntax
|
| 342 |
return {
|
| 343 |
"is_non_food": is_non_food,
|
| 344 |
"non_food_items": non_food_items,
|
|
@@ -368,6 +391,7 @@ async def gradio_analyze(image):
|
|
| 368 |
request = ImageRequest(image=base64_image, portion_size=100.0)
|
| 369 |
return await analyze_food(request)
|
| 370 |
except Exception as e:
|
|
|
|
| 371 |
return {"error": str(e)}
|
| 372 |
|
| 373 |
# Gradio interface
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
import base64
|
| 3 |
from io import BytesIO
|
|
|
|
| 67 |
detected_objects = []
|
| 68 |
seen_labels = set()
|
| 69 |
for result in yolo_results:
|
| 70 |
+
# Log YOLO output shapes
|
| 71 |
+
logger.info(f"YOLO output - Boxes: {len(result.boxes.xyxy)}, Classes: {len(result.boxes.cls)}, Confidences: {len(result.boxes.conf)}")
|
| 72 |
+
# Validate array lengths
|
| 73 |
+
if not (len(result.boxes.xyxy) == len(result.boxes.cls) == len(result.boxes.conf)):
|
| 74 |
+
logger.error(f"Mismatched YOLO output lengths: Boxes={len(result.boxes.xyxy)}, Classes={len(result.boxes.cls)}, Confidences={len(result.boxes.conf)}")
|
| 75 |
+
continue
|
| 76 |
for box, cls, conf in zip(result.boxes.xyxy, result.boxes.cls, result.boxes.conf):
|
| 77 |
+
cls_idx = int(cls)
|
| 78 |
+
if cls_idx >= len(result.names):
|
| 79 |
+
logger.error(f"Invalid class index {cls_idx}, max allowed: {len(result.names)-1}")
|
| 80 |
+
continue
|
| 81 |
if conf >= confidence_threshold:
|
| 82 |
+
label = result.names[cls_idx]
|
| 83 |
if label not in seen_labels: # Avoid duplicates
|
| 84 |
detected_objects.append({
|
| 85 |
"label": label,
|
| 86 |
"box": box,
|
| 87 |
+
"confidence": float(conf)
|
| 88 |
})
|
| 89 |
seen_labels.add(label)
|
| 90 |
|
|
|
|
| 295 |
|
| 296 |
return nutrients, micronutrients, 0
|
| 297 |
|
| 298 |
+
# FastAPI endpoint for food analysis
|
| 299 |
@app.post("/analyze_food")
|
| 300 |
async def analyze_food(request: ImageRequest):
|
| 301 |
try:
|
| 302 |
img = decode_base64_image(request.image)
|
| 303 |
yolo_results = yolo_model(img)
|
| 304 |
+
|
| 305 |
+
# Log YOLO model details
|
| 306 |
+
logger.info(f"YOLO model classes: {len(yolo_model.names)}, Names: {yolo_model.names}")
|
| 307 |
+
|
| 308 |
cropped_img, was_cropped = crop_image_to_food(img, yolo_results)
|
| 309 |
|
| 310 |
# Store YOLO detections for fallback
|
| 311 |
+
yolo_detections = []
|
| 312 |
+
for r in yolo_results:
|
| 313 |
+
if len(r.boxes.cls) != len(r.boxes.conf):
|
| 314 |
+
logger.error(f"Mismatched YOLO cls and conf lengths: Classes={len(r.boxes.cls)}, Confidences={len(r.boxes.conf)}")
|
| 315 |
+
continue
|
| 316 |
+
for cls, conf in zip(r.boxes.cls, r.boxes.conf):
|
| 317 |
+
cls_idx = int(cls)
|
| 318 |
+
if cls_idx >= len(r.names):
|
| 319 |
+
logger.error(f"Invalid class index {cls_idx}, max allowed: {len(r.names)-1}")
|
| 320 |
+
continue
|
| 321 |
+
if float(conf) >= 0.2:
|
| 322 |
+
yolo_detections.append({"label": r.names[cls_idx], "confidence": float(conf)})
|
| 323 |
|
| 324 |
# Combine LogMeal and Clarifai results with weighted scoring
|
| 325 |
logmeal_results = logmeal_classifier(cropped_img)
|
|
|
|
| 340 |
food_items = {k: v for k, v in food_items.items() if v >= 0.15}
|
| 341 |
logger.info(f"Combined food items detected: {food_items}")
|
| 342 |
|
| 343 |
+
non_food_items = []
|
| 344 |
+
for r in yolo_results:
|
| 345 |
+
for cls, conf in zip(r.boxes.cls, r.boxes.conf):
|
| 346 |
+
cls_idx = int(cls)
|
| 347 |
+
if cls_idx >= len(r.names):
|
| 348 |
+
logger.error(f"Invalid class index {cls_idx} in non_food_items, max allowed: {len(r.names)-1}")
|
| 349 |
+
continue
|
| 350 |
+
if r.names[cls_idx] not in food_items and float(conf) >= 0.2:
|
| 351 |
+
non_food_items.append(r.names[cls_idx])
|
| 352 |
is_non_food = len(food_items) == 0 or (len(non_food_items) > len(food_items) and max(food_items.values(), default=0) < 0.3)
|
| 353 |
logger.info(f"Non-food items: {non_food_items}, is_non_food: {is_non_food}")
|
| 354 |
|
|
|
|
| 362 |
for food, prob in food_items.items()
|
| 363 |
]
|
| 364 |
|
|
|
|
| 365 |
return {
|
| 366 |
"is_non_food": is_non_food,
|
| 367 |
"non_food_items": non_food_items,
|
|
|
|
| 391 |
request = ImageRequest(image=base64_image, portion_size=100.0)
|
| 392 |
return await analyze_food(request)
|
| 393 |
except Exception as e:
|
| 394 |
+
logger.error(f"Gradio analysis failed: {str(e)}")
|
| 395 |
return {"error": str(e)}
|
| 396 |
|
| 397 |
# Gradio interface
|