Spaces:
Running
Running
File size: 5,781 Bytes
081bb6f 89b8989 9684df5 a608ddf 89b8989 9684df5 a608ddf 9684df5 89b8989 a608ddf 9684df5 a608ddf 9684df5 a608ddf 9684df5 a608ddf 9684df5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# 檔案路徑: app/routers/ai_router.py
from fastapi import APIRouter, File, UploadFile, HTTPException
from pydantic import BaseModel
from typing import Dict, Any, List, Optional
import logging
# 導入新的整合服務
from ..services.integrated_food_analysis_service import analyze_food_image_integrated
# 設置日誌
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
router = APIRouter(
prefix="/ai",
tags=["AI"],
)
# 新增 Pydantic 模型定義
class IntegratedAnalysisResponse(BaseModel):
success: bool
analysis_time: float
food_analysis: Dict[str, Any]
reference_analysis: Dict[str, Any]
weight_analysis: Dict[str, Any]
nutrition_analysis: Dict[str, Any]
summary: Dict[str, Any]
architecture: Dict[str, str]
class WeightEstimationResponse(BaseModel):
food_type: str
estimated_weight: float
weight_confidence: float
weight_error_range: List[float]
nutrition: Dict[str, Any]
reference_object: Optional[str] = None
note: str
class FoodAnalysisResponse(BaseModel):
food_name: str
nutrition_info: Dict[str, Any]
@router.post("/analyze-food-image/")
async def analyze_food_image_endpoint(file: UploadFile = File(...)):
"""
這個端點接收使用者上傳的食物圖片,使用 AI 模型進行辨識,
並返回辨識出的食物名稱。
"""
# 檢查上傳的檔案是否為圖片格式
if not file.content_type or not file.content_type.startswith("image/"):
raise HTTPException(status_code=400, detail="上傳的檔案不是圖片格式。")
try:
# 讀取圖片數據
image_bytes = await file.read()
# 使用新的整合服務進行分析
result = analyze_food_image_integrated(image_bytes, debug=False)
if not result.get("success", False):
raise HTTPException(status_code=500, detail=result.get("error_message", "分析失敗"))
# 返回簡化的結果
return {
"food_name": result["food_analysis"]["food_name"],
"nutrition_info": result["nutrition_analysis"]["adjusted_nutrition"]
}
except Exception as e:
logger.error(f"食物分析失敗: {str(e)}")
raise HTTPException(status_code=500, detail=f"分析失敗: {str(e)}")
@router.post("/analyze-food-image-with-weight/", response_model=WeightEstimationResponse)
async def analyze_food_image_with_weight_endpoint(file: UploadFile = File(...)):
"""
整合食物辨識、重量估算與營養分析的端點。
使用新的架構:FOOD101 → YOLO(參考物) → SAM+DPT → USDA API
"""
# 檢查上傳的檔案是否為圖片格式
if not file.content_type or not file.content_type.startswith("image/"):
raise HTTPException(status_code=400, detail="上傳的檔案不是圖片格式。")
try:
# 讀取圖片數據
image_bytes = await file.read()
# 使用新的整合服務進行分析
result = analyze_food_image_integrated(image_bytes, debug=False)
if not result.get("success", False):
raise HTTPException(status_code=500, detail=result.get("error_message", "分析失敗"))
# 轉換為舊格式以保持向後兼容
weight_analysis = result["weight_analysis"]
nutrition_analysis = result["nutrition_analysis"]
return WeightEstimationResponse(
food_type=result["food_analysis"]["food_name"],
estimated_weight=weight_analysis["estimated_weight"],
weight_confidence=weight_analysis["weight_confidence"],
weight_error_range=weight_analysis["weight_error_range"],
nutrition=nutrition_analysis["adjusted_nutrition"],
reference_object=weight_analysis["reference_object"],
note=f"使用新架構分析,耗時 {result['analysis_time']} 秒"
)
except Exception as e:
logger.error(f"重量估算分析失敗: {str(e)}")
raise HTTPException(status_code=500, detail=f"分析失敗: {str(e)}")
@router.post("/analyze-food-image-integrated/")
async def analyze_food_image_integrated_endpoint(file: UploadFile = File(...)):
"""
新的整合分析端點,返回完整的分析結果
架構:FOOD101 → YOLO(參考物) → SAM+DPT → USDA API
"""
# 檢查上傳的檔案是否為圖片格式
if not file.content_type or not file.content_type.startswith("image/"):
raise HTTPException(status_code=400, detail="上傳的檔案不是圖片格式。")
try:
# 讀取圖片數據
image_bytes = await file.read()
# 使用新的整合服務進行分析
result = analyze_food_image_integrated(image_bytes, debug=False)
return result
except Exception as e:
logger.error(f"整合分析失敗: {str(e)}")
raise HTTPException(status_code=500, detail=f"分析失敗: {str(e)}")
@router.get("/health")
async def health_check():
"""
健康檢查端點,確認 AI 服務是否正常運作
"""
return {
"status": "healthy",
"services": {
"food_classification": "available (FOOD101)",
"reference_detection": "available (YOLO)",
"weight_estimation": "available (SAM+DPT)",
"nutrition_api": "available (USDA)",
"integrated_analysis": "available"
},
"architecture": {
"layer_1": "FOOD101 (食物識別)",
"layer_2": "YOLO (參考物偵測)",
"layer_3": "SAM+DPT (重量計算)",
"layer_4": "USDA API (營養查詢)",
"layer_5": "重量調整 (營養計算)"
}
} |