Spaces:
Sleeping
Sleeping
har1zarD
commited on
Commit
·
9f2e248
1
Parent(s):
decaf6f
app
Browse files
app.py
CHANGED
|
@@ -748,25 +748,32 @@ async def analyze(file: UploadFile = File(...)):
|
|
| 748 |
raise HTTPException(status_code=500, detail=f"Error reading image: {e}")
|
| 749 |
|
| 750 |
try:
|
| 751 |
-
#
|
| 752 |
-
is_food, food_confidence =
|
| 753 |
|
| 754 |
-
if not is_food and food_confidence >
|
| 755 |
return JSONResponse(content={
|
| 756 |
"success": False,
|
| 757 |
"error": "Non-food object detected",
|
| 758 |
-
"message": "Image doesn't contain food. Please upload a food image.",
|
| 759 |
-
"confidence": food_confidence
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 760 |
})
|
| 761 |
|
| 762 |
-
#
|
| 763 |
-
logger.info("
|
| 764 |
-
|
| 765 |
|
| 766 |
-
if
|
| 767 |
raise HTTPException(
|
| 768 |
status_code=422,
|
| 769 |
-
detail=f"Low confidence ({
|
|
|
|
| 770 |
)
|
| 771 |
|
| 772 |
except HTTPException:
|
|
@@ -775,36 +782,51 @@ async def analyze(file: UploadFile = File(...)):
|
|
| 775 |
logger.error(f"Classification error: {e}")
|
| 776 |
raise HTTPException(status_code=500, detail=f"Classification error: {e}")
|
| 777 |
|
| 778 |
-
#
|
| 779 |
-
logger.info(f"
|
| 780 |
-
nutrition_data = search_nutrition_data(result["primary_label"])
|
| 781 |
|
| 782 |
-
# Prepare response
|
| 783 |
response = {
|
| 784 |
"success": True,
|
| 785 |
-
|
| 786 |
-
|
| 787 |
-
"
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
| 791 |
-
|
| 792 |
-
|
| 793 |
-
#
|
| 794 |
-
"
|
| 795 |
-
|
| 796 |
-
|
| 797 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 798 |
},
|
| 799 |
|
| 800 |
-
#
|
| 801 |
-
"
|
| 802 |
-
"
|
| 803 |
-
"
|
| 804 |
-
"
|
| 805 |
-
"
|
| 806 |
-
|
| 807 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 808 |
}
|
| 809 |
}
|
| 810 |
|
|
@@ -849,18 +871,45 @@ async def analyze_custom(
|
|
| 849 |
raise HTTPException(status_code=500, detail=f"Error reading image: {e}")
|
| 850 |
|
| 851 |
try:
|
| 852 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 853 |
|
| 854 |
return JSONResponse(content={
|
| 855 |
"success": True,
|
| 856 |
-
"
|
| 857 |
-
|
| 858 |
-
|
| 859 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 860 |
"model_info": {
|
| 861 |
-
"
|
| 862 |
-
"
|
| 863 |
-
"
|
| 864 |
}
|
| 865 |
})
|
| 866 |
|
|
@@ -880,7 +929,7 @@ def root():
|
|
| 880 |
"status": "🟢 Online & Ready",
|
| 881 |
"tagline": "Jednostavan i moćan food recognition sa zero-shot learning",
|
| 882 |
"model": {
|
| 883 |
-
"name":
|
| 884 |
"type": "Vision-Language Model (CLIP)",
|
| 885 |
"capabilities": "Zero-shot classification",
|
| 886 |
"device": device.upper(),
|
|
|
|
| 748 |
raise HTTPException(status_code=500, detail=f"Error reading image: {e}")
|
| 749 |
|
| 750 |
try:
|
| 751 |
+
# Advanced food detection
|
| 752 |
+
is_food, food_confidence, detection_details = recognizer.detect_food_advanced(image)
|
| 753 |
|
| 754 |
+
if not is_food and food_confidence > CONFIG.food_detection_threshold:
|
| 755 |
return JSONResponse(content={
|
| 756 |
"success": False,
|
| 757 |
"error": "Non-food object detected",
|
| 758 |
+
"message": "Image doesn't appear to contain food. Please upload a food image.",
|
| 759 |
+
"confidence": food_confidence,
|
| 760 |
+
"detection_details": detection_details,
|
| 761 |
+
"suggestions": [
|
| 762 |
+
"Ensure the image clearly shows food items",
|
| 763 |
+
"Check that lighting is adequate",
|
| 764 |
+
"Try a different angle or closer shot"
|
| 765 |
+
]
|
| 766 |
})
|
| 767 |
|
| 768 |
+
# Comprehensive food analysis
|
| 769 |
+
logger.info("🍽️ Starting comprehensive food analysis...")
|
| 770 |
+
analysis_result = recognizer.analyze_food(image)
|
| 771 |
|
| 772 |
+
if analysis_result["confidence"] < CONFIG.min_confidence:
|
| 773 |
raise HTTPException(
|
| 774 |
status_code=422,
|
| 775 |
+
detail=f"Low confidence recognition ({analysis_result['confidence']:.1%}). " +
|
| 776 |
+
"Please upload a clearer image with better lighting."
|
| 777 |
)
|
| 778 |
|
| 779 |
except HTTPException:
|
|
|
|
| 782 |
logger.error(f"Classification error: {e}")
|
| 783 |
raise HTTPException(status_code=500, detail=f"Classification error: {e}")
|
| 784 |
|
| 785 |
+
# Comprehensive response
|
| 786 |
+
logger.info(f"✅ Food recognized: {analysis_result['primary_label']} ({analysis_result['confidence']:.1%})")
|
|
|
|
| 787 |
|
|
|
|
| 788 |
response = {
|
| 789 |
"success": True,
|
| 790 |
+
|
| 791 |
+
# Primary results
|
| 792 |
+
"food_item": {
|
| 793 |
+
"name": analysis_result["primary_label"],
|
| 794 |
+
"confidence": analysis_result["confidence"],
|
| 795 |
+
"category": _get_food_category(analysis_result["primary_label"])
|
| 796 |
+
},
|
| 797 |
+
|
| 798 |
+
# Nutrition analysis
|
| 799 |
+
"nutrition": analysis_result["nutrition_analysis"],
|
| 800 |
+
|
| 801 |
+
# Visual analysis
|
| 802 |
+
"image_analysis": {
|
| 803 |
+
"original_size": original_size,
|
| 804 |
+
"visual_features": analysis_result["visual_features"],
|
| 805 |
+
"quality_score": _calculate_image_quality(analysis_result["visual_features"]),
|
| 806 |
+
"is_food_detected": is_food,
|
| 807 |
+
"food_detection_confidence": food_confidence
|
| 808 |
},
|
| 809 |
|
| 810 |
+
# AI model details
|
| 811 |
+
"ai_analysis": {
|
| 812 |
+
"models_used": analysis_result["processing_info"]["models_used"],
|
| 813 |
+
"ensemble_details": analysis_result.get("ensemble_details", []),
|
| 814 |
+
"categories_analyzed": analysis_result["processing_info"]["categories_analyzed"],
|
| 815 |
+
"processing_time_ms": "<100" # Typical processing time
|
| 816 |
+
},
|
| 817 |
+
|
| 818 |
+
# API info
|
| 819 |
+
"api_info": {
|
| 820 |
+
"version": "12.0.0",
|
| 821 |
+
"model_type": "Advanced Multi-Model Ensemble",
|
| 822 |
+
"device": device.upper(),
|
| 823 |
+
"enhanced_features": [
|
| 824 |
+
"Multi-model ensemble",
|
| 825 |
+
"Visual feature analysis",
|
| 826 |
+
"Advanced nutrition lookup",
|
| 827 |
+
"Confidence scoring",
|
| 828 |
+
"Image quality assessment"
|
| 829 |
+
]
|
| 830 |
}
|
| 831 |
}
|
| 832 |
|
|
|
|
| 871 |
raise HTTPException(status_code=500, detail=f"Error reading image: {e}")
|
| 872 |
|
| 873 |
try:
|
| 874 |
+
# Use custom analysis
|
| 875 |
+
result = recognizer.analyze_food(image, custom_categories=custom_categories)
|
| 876 |
+
|
| 877 |
+
# Get top 5 results for custom categories
|
| 878 |
+
if custom_categories:
|
| 879 |
+
# Re-run CLIP with just custom categories for detailed results
|
| 880 |
+
clip_result = recognizer._clip_predict(image, custom_categories)
|
| 881 |
+
|
| 882 |
+
# Get top 5
|
| 883 |
+
sorted_indices = np.argsort(clip_result["all_probs"])[::-1]
|
| 884 |
+
top5_results = []
|
| 885 |
+
for idx in sorted_indices[:5]:
|
| 886 |
+
top5_results.append({
|
| 887 |
+
"label": custom_categories[idx],
|
| 888 |
+
"confidence": float(clip_result["all_probs"][idx])
|
| 889 |
+
})
|
| 890 |
+
else:
|
| 891 |
+
top5_results = [{"label": result["primary_label"], "confidence": result["confidence"]}]
|
| 892 |
|
| 893 |
return JSONResponse(content={
|
| 894 |
"success": True,
|
| 895 |
+
"analysis": {
|
| 896 |
+
"primary_match": {
|
| 897 |
+
"label": result["primary_label"],
|
| 898 |
+
"confidence": result["confidence"],
|
| 899 |
+
"category": _get_food_category(result["primary_label"])
|
| 900 |
+
},
|
| 901 |
+
"top_matches": top5_results,
|
| 902 |
+
"visual_features": result["visual_features"]
|
| 903 |
+
},
|
| 904 |
+
"categories": {
|
| 905 |
+
"total_analyzed": len(custom_categories) if custom_categories else len(FOOD_CATEGORIES),
|
| 906 |
+
"custom_categories": custom_categories,
|
| 907 |
+
"using_defaults": custom_categories is None
|
| 908 |
+
},
|
| 909 |
"model_info": {
|
| 910 |
+
"method": "Zero-shot learning with custom categories",
|
| 911 |
+
"models_used": result["processing_info"]["models_used"],
|
| 912 |
+
"device": device.upper()
|
| 913 |
}
|
| 914 |
})
|
| 915 |
|
|
|
|
| 929 |
"status": "🟢 Online & Ready",
|
| 930 |
"tagline": "Jednostavan i moćan food recognition sa zero-shot learning",
|
| 931 |
"model": {
|
| 932 |
+
"name": recognizer.config.clip_model,
|
| 933 |
"type": "Vision-Language Model (CLIP)",
|
| 934 |
"capabilities": "Zero-shot classification",
|
| 935 |
"device": device.upper(),
|