# backend/app/services/nutrition_api_service.py import os import requests from dotenv import load_dotenv import logging # 設置日誌 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # 載入環境變數 load_dotenv() # 從環境變數中獲取 API 金鑰 USDA_API_KEY = os.getenv("USDA_API_KEY", "4guYMPsU2jSnN6GH6NjexZmSh1VWrgmOIoH6d6ju") USDA_API_URL = "https://api.nal.usda.gov/fdc/v1/foods/search" # 我們關心的主要營養素及其在 USDA API 中的名稱或編號 # 我們可以透過 nutrient.nutrientNumber 或 nutrient.name 來匹配 NUTRIENT_MAP = { 'calories': 'Energy', 'protein': 'Protein', 'fat': 'Total lipid (fat)', 'carbs': 'Carbohydrate, by difference', 'fiber': 'Fiber, total dietary', 'sugar': 'Total sugars', 'sodium': 'Sodium, Na' } def fetch_nutrition_data(food_name: str): """ 從 USDA FoodData Central API 獲取食物的營養資訊。 :param food_name: 要查詢的食物名稱 (例如 "Donuts")。 :return: 包含營養資訊的字典,如果找不到則返回 None。 """ if not USDA_API_KEY: logger.error("USDA_API_KEY 未設定,無法查詢營養資訊。") return None params = { 'query': food_name, 'api_key': USDA_API_KEY, 'dataType': 'Branded', # 優先搜尋品牌食品,結果通常更符合預期 'pageSize': 1 # 我們只需要最相關的一筆結果 } try: logger.info(f"正在向 USDA API 查詢食物:{food_name}") response = requests.get(USDA_API_URL, params=params) response.raise_for_status() # 如果請求失敗 (例如 4xx 或 5xx),則會拋出異常 data = response.json() # 檢查是否有找到食物 if data.get('foods') and len(data['foods']) > 0: food_data = data['foods'][0] # 取第一個最相關的結果 logger.info(f"從 API 成功獲取到食物 '{food_data.get('description')}' 的資料") nutrition_info = { "food_name": food_data.get('description', food_name).capitalize(), "chinese_name": None, # USDA API 不提供中文名 } # 遍歷我們需要的營養素 extracted_nutrients = {key: 0.0 for key in NUTRIENT_MAP.keys()} # 初始化 for nutrient in food_data.get('foodNutrients', []): for key, name in NUTRIENT_MAP.items(): if nutrient.get('nutrientName').strip().lower() == name.strip().lower(): # 將值存入我們的格式 extracted_nutrients[key] = float(nutrient.get('value', 0.0)) break # 找到後就跳出內層迴圈 nutrition_info.update(extracted_nutrients) # 由於 USDA 不直接提供健康建議,我們先回傳原始數據 # 後續可以在 main.py 中根據這些數據生成我們自己的建議 return nutrition_info else: logger.warning(f"在 USDA API 中找不到食物:{food_name}") return None except requests.exceptions.RequestException as e: logger.error(f"請求 USDA API 時發生錯誤: {e}") return None except Exception as e: logger.error(f"處理 API 回應時發生未知錯誤: {e}") return None if __name__ == '__main__': # 測試此模組的功能 test_food = "donuts" nutrition = fetch_nutrition_data(test_food) if nutrition: import json print(f"成功獲取 '{test_food}' 的營養資訊:") print(json.dumps(nutrition, indent=2)) else: print(f"無法獲取 '{test_food}' 的營養資訊。")