Skill: aaa2531349/calorie (version 1.0.0)

--- name: calorie-detective-v1-0-2 description: 热量侦探 v1.0.2 - AI 食物卡路里计算器。通过照片识别食物并自动计算卡路里、蛋白质、碳水、脂肪等营养数据。支持 Kimi 视觉识别，内置常见食物营养数据库。用于健康饮食管理、减肥健身追踪。再隐蔽的热量也逃不过我的眼睛！ --- # 🔍 热量侦探 v1.0.0 🕵️ **再隐蔽的热量也逃不过我的眼睛！** 通过 AI 视觉识别技术，像侦探一样找出食物中隐藏的热量，自动计算卡路里和营养成分，帮助你更好地管理饮食健康。 ## ✨ 功能特性 1. **📸 拍照识别** - 上传食物照片，AI 自动识别食物种类 2. **🔥 卡路里计算** - 自动计算总卡路里和宏量营养素 3. **📊 营养报告** - 生成详细的营养分析报告 4. **💡 健康建议** - 提供饮食改进建议 5. **🌐 中文优化** - 专为中餐优化，识别更准确 6. **💾 本地数据库** - 内置常见食物营养数据 ## 🚀 快速开始 ### 方式 1：Kimi Claw 一键部署（推荐） ```bash # 1. 访问 Kimi 控制台 https://platform.moonshot.cn/console/claw # 2. 上传 skill 包 # 选择 calorie-detective-v1.0.2.zip # 3. 使用 config/kimi_claw.yaml 配置 # 4. 部署完成后，在 Kimi 中使用： /卡路里 [上传食物照片] ``` **优点：** - ✅ 一键部署，无需配置环境 - ✅ 自动扩展，无需管理服务器 - ✅ 使用 K2.5 模型（Allegretto 套餐包含） - ✅ 支持自然语言触发 --- ### 方式 2：本地安装 ```bash # 解压 skill unzip calorie-detective-v1.0.2.zip -d calorie-detective cd calorie-detective # 安装依赖 pip install -r requirements.txt # 配置 API Key export KIMI_API_KEY="your_kimi_key" # 运行 ./run.sh data/food.jpg ``` ## ⚙️ 配置 ### 配置 API Key **方式 1：环境变量（推荐）** ```bash export KIMI_API_KEY="your_kimi_key" ``` **方式 2：配置文件** 编辑 `config/config.local.yaml`： ```yaml api_keys: kimi: "your_kimi_key" ``` **获取 Kimi API Key：** 1. 访问 https://platform.moonshot.cn 2. 注册/登录账号 3. 进入控制台 → API Keys 4. 创建新 Key 5. 新用户注册送免费额度 ### config/config.yaml ```yaml # 视觉识别配置 vision: provider: kimi # 推荐使用 Kimi model: moonshot-v1-auto # 使用限制 usage: max_requests_per_day: 10 max_requests_per_user: 5 ``` ## 📤 输出示例 ``` 🕵️ **热量侦探 - 营养分析报告** 📝 一碗牛肉拉面，配有青菜和红油汤底 📊 **营养分析** 🔥 总卡路里：**696 大卡** 💪 蛋白质：26.4g 🍚 碳水化合物：50.9g 🥑 脂肪：43.1g 📋 **详细分解** • **面条** (1 碗) - 卡路里：220 大卡 - 蛋白质：5.0g | 碳水：50g | 脂肪：1.0g • **牛肉** (80 克) - 卡路里：200 大卡 - 蛋白质：20.8g | 碳水：0g | 脂肪：12.0g • **青菜** (30 克) - 卡路里：6 大卡 - 蛋白质：0.6g | 碳水：0.9g | 脂肪：0.1g • **红油汤底** (300ml) - 卡路里：270 大卡 - 蛋白质：0g | 碳水：0g | 脂肪：30.0g ────────────────────────────── 💡 侦探建议： • 红油汤底热量较高，建议少喝汤 • 蛋白质含量充足，适合作为主食 • 可搭配凉拌菜增加膳食纤维 ``` ## 📅 定时任务管理 ```bash # 查看所有定时任务 openclaw cron list # 手动立即运行一次 openclaw cron run <job-id> # 暂停任务 openclaw cron update <job-id> --enabled false # 删除任务 openclaw cron remove <job-id> ``` ## 📁 文件结构 ``` calorie-detective/ ├── SKILL.md # 本文件 ├── config/ │ ├── config.yaml # 配置文件 │ ├── config.local.yaml # 本地配置（含 API Key） │ └── kimi_claw.yaml # Kimi Claw 部署配置 ├── src/ │ └── calorie_calculator.py # 主程序 ├── data/ │ ├── food.jpg # 示例图片 │ └── calorie.log # 运行日志 ├── requirements.txt # 依赖列表 ├── run.sh # 运行脚本 └── test.sh # 测试脚本 ``` ## 🍎 内置食物数据库 已内置 100+ 种常见食物营养数据（每 100 克）： | 类别 | 食物举例 | |------|----------| | 🍚 主食 | 米饭、面条、馒头、面包、土豆 | | 🥚 蛋白质 | 鸡蛋、牛奶、鸡肉、猪肉、牛肉、鱼 | | 🍎 水果 | 苹果、香蕉、橙子、葡萄、草莓 | | 🥬 蔬菜 | 青菜、番茄、黄瓜、胡萝卜、西兰花 | | 🍔 快餐 | 汉堡、薯条、炸鸡、披萨 | ## 🔧 支持的视觉服务 | 服务商 | 模型 | 价格 | 需要 API Key | 推荐度 | |--------|------|------|-------------|--------| | **Kimi** | moonshot-v1-auto | ¥0.008/张 | ✅ | ⭐⭐⭐⭐⭐ | | Kimi | k2.5 | 套餐包含 | ✅ | ⭐⭐⭐⭐⭐ | | OpenAI | GPT-4o / GPT-4V | $0.01/张 | ✅ | ⭐⭐⭐⭐ | | Claude | Claude 3 Vision | $0.003/张 | ✅ | ⭐⭐⭐⭐ | **推荐使用 Kimi：** - ✅ 中文识别最好 - ✅ 价格便宜（约 OpenAI 的 1/10） - ✅ 国内直接访问 - ✅ 注册送免费额度 ## 🛠️ 故障排除 ### 1. 依赖安装失败 ```bash pip install --break-system-packages -r requirements.txt ``` ### 2. API Key 无效 - 检查 API Key 是否正确 - 确认账户有可用额度 - 检查网络连接 ```bash # 测试 API Key curl https://api.moonshot.cn/v1/chat/completions \ -H "Authorization: Bearer $KIMI_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "moonshot-v1-auto", "messages": [{"role": "user", "content": "Hello"}]}' ``` ### 3. 图片识别不准确 - 确保图片清晰、光线充足 - 尽量拍摄食物特写 - 避免过多餐具干扰 ### 4. 营养数据不准确 - 内置数据库为估算值 - 建议接入专业营养 API 获取精确数据 - 可在代码中添加自定义食物 ## 📊 使用统计 在 Kimi 控制台查看： 1. 访问 https://platform.moonshot.cn/console/claw 2. 选择 `calorie-detective` 3. 查看"使用统计"标签页 **统计数据包括：** - 📈 调用次数 - ⏱️ 平均响应时间 - 💰 额度消耗 - 👥 用户数 ## 🔄 扩展开发 ### 添加新食物 编辑 `src/calorie_calculator.py` 中的 `COMMON_FOODS` 字典： ```python COMMON_FOODS = { '你的食物': {'calories': 100, 'protein': 5, 'carbs': 15, 'fat': 3}, ... } ``` ### 添加新的视觉服务 继承 `VisionRecognizer` 类并实现 `_recognize_xxx` 方法。 ## 📝 更新日志 ### v1.0.0 (2026-03-03) - 正式发布版 - ✅ 基础功能实现 - ✅ Kimi 视觉识别支持 - ✅ 本地食物营养数据库（100+ 种食物） - ✅ 营养报告生成 - ✅ 健康饮食建议 - ✅ Kimi Claw 一键部署支持 - ✅ 中文食物识别优化 - ✅ 品牌：热量侦探 ## ⚠️ 免责声明 - 本工具提供的营养数据仅供参考，不构成医疗或营养建议 - 实际食物营养含量可能因烹饪方式、食材来源等因素有所不同 - 如有特殊饮食需求或健康问题，请咨询专业营养师或医生 - 开发者不对使用本工具造成的任何损失承担责任 ## 📄 License MIT ## 🤝 贡献 欢迎提交 Issue 和 Pull Request！ ## 📧 联系方式 如有问题或建议，请提交 Issue 或联系开发者。 --- **🕵️ 热量侦探，再隐蔽的热量也逃不过我的眼睛！** 🍽️

path: _meta.json
content: {
  "ownerId": "kn7et01nz604jx2mtk706y1mrh82075t",
  "slug": "calorie-detective",
  "version": "1.0.0",
  "publishedAt": 1772527200000,
  "tags": ["kimi", "claw", "food", "calorie", "health", "detective", "k2.5"],
  "displayName": "热量侦探",
  "slogan": "再隐蔽的热量也逃不过我的眼睛！"
}


path: requirements.txt
content: # Food Calorie Calculator Dependencies
requests>=2.28.0
pyyaml>=6.0
Pillow>=9.0.0


path: config/config.yaml
content: # Food Calorie Calculator 配置

# 视觉识别配置
vision:
  # 视觉服务提供商：kimi, openai, claude, qwen
  provider: kimi        # 推荐使用 Kimi（中文识别好，便宜）
  model: k2.5           # Allegretto 套餐使用 K2.5 模型
                        # 备选：moonshot-v1-auto, moonshot-v1-8k
  
# 营养数据配置
nutrition:
  # 营养 API 提供商：nutritionix, fatsecret, local
  provider: local       # 使用本地数据库（免费）
  
# API Keys（从环境变量读取或在此配置）
api_keys:
  # Kimi API Key (推荐，用于视觉识别)
  kimi: ""  # 或从环境变量 KIMI_API_KEY 读取
  
  # OpenAI API Key (备选)
  openai: ""  # 或从环境变量 OPENAI_API_KEY 读取
  
  # Nutritionix API Key (用于营养数据，可选)
  nutritionix_app_id: ""  # 或从环境变量 NUTRITIONIX_APP_ID 读取
  nutritionix_api_key: ""  # 或从环境变量 NUTRITIONIX_API_KEY 读取
  
  # 备选：FatSecret API Key
  fatsecret: ""  # 或从环境变量 FATSECRET_KEY 读取

# 输出配置
output:
  language: zh  # zh=中文，en=英文
  include_macros: true  # 显示宏量营养素（蛋白质/碳水/脂肪）
  include_micros: false  # 显示微量营养素（维生素/矿物质）
  
# 日志配置
logging:
  level: INFO
  file: data/calorie.log


path: config/kimi_claw.yaml
content: # Kimi Claw 部署配置
# 用于 Allegretto 套餐的一键部署

claw:
  # 部署名称
  name: food-calorie-calculator
  
  # 部署描述
  description: 📸 拍照识食物，一键算卡路里！通过 AI 视觉识别技术，自动分析食物照片并计算卡路里和营养成分。
  
  # 使用模型
  model: k2.5  # Allegretto 套餐包含 K2.5
  
  # 触发方式
  trigger:
    type: command  # 命令触发
    commands:
      - "/卡路里"
      - "/calorie"
      - "算卡路里"
      - "食物热量"
  
  # 输入类型
  input:
    type: image  # 支持图片输入
    accept: ["image/jpeg", "image/png", "image/webp"]
  
  # 输出格式
  output:
    format: markdown
    include_image: false  # 不返回原图
  
  # 环境变量
  env:
    KIMI_MODEL: "k2.5"
    NUTRITION_PROVIDER: "local"
    OUTPUT_LANGUAGE: "zh"
  
  # 资源限制
  resources:
    max_memory: "512MB"
    timeout: 60  # 60 秒超时
  
  # 日志
  logging:
    level: INFO
    retention_days: 7


path: run.sh
content: #!/bin/bash
# Food Calorie Calculator - 运行脚本

cd "$(dirname "$0")"

# 检查图片参数
if [ -z "$1" ]; then
    echo "用法：./run.sh <图片路径>"
    echo "示例：./run.sh data/food.jpg"
    exit 1
fi

# 运行计算器
python3 src/calorie_calculator.py "$1"


path: DEPLOY.md
content: # Kimi Claw 部署指南

## 📦 前提条件

- ✅ 已订阅 Kimi Allegretto 套餐（¥199/月）
- ✅ 拥有 Kimi API Key
- ✅ 已安装 OpenClaw

---

## 🚀 一键部署

### 方式 1：Kimi Claw 控制台部署（推荐）

1. **访问 Kimi 控制台**
   ```
   https://platform.moonshot.cn/console/claw
   ```

2. **上传 Skill 包**
   - 点击"创建新 Claw"
   - 上传 `food-calorie-calculator-v1.0.1.zip`
   - 选择 `config/kimi_claw.yaml` 作为部署配置

3. **配置环境变量**
   ```
   KIMI_API_KEY=your_api_key
   KIMI_MODEL=k2.5
   ```

4. **部署**
   - 点击"部署"
   - 等待部署完成（约 1-2 分钟）

5. **测试**
   - 在 Kimi 对话框输入 `/卡路里`
   - 上传一张食物照片
   - 查看营养分析报告

---

### 方式 2：命令行部署

```bash
# 1. 安装 Kimi CLI（如果未安装）
pip install kimi-claw

# 2. 登录 Kimi
kimi login

# 3. 部署 Claw
cd food-calorie-release
kimi claw deploy --config config/kimi_claw.yaml

# 4. 查看部署状态
kimi claw status food-calorie-calculator

# 5. 测试
kimi claw test food-calorie-calculator --image food.jpg
```

---

## 📋 触发命令

部署成功后，可以使用以下命令触发：

| 命令 | 说明 | 示例 |
|------|------|------|
| `/卡路里` | 快捷命令 | `/卡路里` + 图片 |
| `/calorie` | 英文命令 | `/calorie` + 图片 |
| `算卡路里` | 自然语言 | "算卡路里" + 图片 |
| `食物热量` | 自然语言 | "食物热量" + 图片 |

---

## 🔧 自定义配置

### 修改触发命令

编辑 `config/kimi_claw.yaml`：

```yaml
trigger:
  commands:
    - "/你的命令"
    - "自定义触发词"
```

### 修改输出格式

编辑 `config/kimi_claw.yaml`：

```yaml
output:
  format: markdown  # 或 text, html
  include_image: true  # 返回原图
```

---

## 📊 使用统计

在 Kimi 控制台查看：

1. 访问 https://platform.moonshot.cn/console/claw
2. 选择 `food-calorie-calculator`
3. 查看"使用统计"标签页

**统计数据包括：**
- 📈 调用次数
- ⏱️ 平均响应时间
- 💰 额度消耗
- 👥 用户数

---

## 💰 额度消耗

**Allegretto 套餐包含：**
- K2.5 模型：4 倍基础额度
- Agent 任务：4 倍基础额度

**每次识别消耗：**
- 图片识别：约 0.1-0.2 倍额度
- 营养计算：约 0.05 倍额度
- **总计：约 0.15-0.25 倍额度/次**

**套餐可用次数估算：**
- 4 倍额度 ≈ 16-26 次识别/月
- 如果不够用，可以切换到按量付费模式

---

## 🛠️ 故障排除

### 1. 部署失败

**错误：** "资源不足"
```bash
# 解决方案：降低资源配置
编辑 config/kimi_claw.yaml:
resources:
  max_memory: "256MB"  # 降低内存
  timeout: 30  # 降低超时时间
```

### 2. 识别失败

**错误：** "模型调用失败"
```bash
# 检查 API Key
kimi auth check

# 重新登录
kimi login
```

### 3. 响应慢

**解决方案：**
- 检查网络连接
- 降低图片分辨率
- 使用 `moonshot-v1-auto` 替代 `k2.5`

---

## 📞 技术支持

- Kimi 文档：https://platform.moonshot.cn/docs
- API 状态：https://status.moonshot.cn
- 社区论坛：https://community.moonshot.cn

---

## 🎉 部署完成！

部署成功后，你可以在 Kimi 中这样使用：

```
用户：[上传食物照片] /卡路里

Kimi: 🍽️ **食物识别结果**

📝 一碗米饭配红烧肉和炒青菜

📊 **营养分析**

🔥 总卡路里：**520 大卡**
💪 蛋白质：28.5g
🍚 碳水化合物：65.2g
🥑 脂肪：18.3g

...
```

享受你的健康饮食管理之旅！🥗💪


path: test.sh
content: #!/bin/bash
# Food Calorie Calculator - 测试脚本

cd "$(dirname "$0")"

echo "=================================="
echo "🍽️  Food Calorie Calculator 测试"
echo "=================================="
echo ""

# 检查图片参数
if [ -z "$1" ]; then
    echo "用法：./test.sh <图片路径>"
    echo ""
    echo "示例："
    echo "  ./test.sh data/food.jpg"
    echo "  ./test.sh ~/Downloads/lunch.jpg"
    echo ""
    echo "请先准备一张食物照片！"
    exit 1
fi

# 检查文件是否存在
if [ ! -f "$1" ]; then
    echo "❌ 错误：图片文件不存在：$1"
    exit 1
fi

echo "📸 测试图片：$1"
echo ""
echo "正在识别食物并计算卡路里..."
echo "──────────────────────────────"
echo ""

# 运行计算器
python3 src/calorie_calculator.py "$1"

echo ""
echo "──────────────────────────────"
echo "✅ 测试完成！"


path: src/calorie_calculator.py
content: #!/usr/bin/env python3
"""
Food Calorie Calculator
通过照片识别食物并计算卡路里
"""
import os
import re
import json
import requests
import yaml
import logging
from typing import Dict, List, Optional, Tuple
from PIL import Image
import base64
from io import BytesIO

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


class VisionRecognizer:
    """视觉识别模块 - 识别食物"""
    
    def __init__(self, provider: str = 'kimi', api_key: str = None, model: str = None):
        self.provider = provider
        self.[REDACTED_SECRET] or os.environ.get('KIMI_API_KEY') or os.environ.get('OPENAI_API_KEY')
        self.model = model or os.environ.get('KIMI_MODEL', 'moonshot-v1-auto')
        
    def recognize(self, image_path: str) -> Dict:
        """
        识别食物图片
        
        Returns:
            {
                'foods': ['米饭', '红烧肉', '青菜'],
                'description': '一碗米饭配红烧肉和炒青菜',
                'confidence': 0.95
            }
        """
        if self.provider == 'kimi':
            return self._recognize_kimi(image_path)
        elif self.provider == 'openai':
            return self._recognize_openai(image_path)
        elif self.provider == 'claude':
            return self._recognize_claude(image_path)
        elif self.provider == 'qwen':
            return self._recognize_qwen(image_path)
        else:
            raise ValueError(f"Unsupported vision provider: {self.provider}")
    
    def _encode_image(self, image_path: str) -> str:
        """将图片编码为 base64"""
        with open(image_path, 'rb') as f:
            return base64.b64encode(f.read()).decode('utf-8')
    
    def _recognize_kimi(self, image_path: str) -> Dict:
        """使用月之暗面 Kimi 识别"""
        import base64
        
        with open(image_path, 'rb') as f:
            base64_image = base64.b64encode(f.read()).decode('utf-8')
        
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        
        payload = {
            "model": self.model,  # 支持 k2.5, moonshot-v1-auto 等
            "messages": [
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "text",
                            "text": """请识别这张图片中的食物，并以 JSON 格式返回：
{
    "foods": ["食物 1", "食物 2", ...],
    "description": "简短描述这顿饭",
    "estimated_servings": {
        "食物 1": "1 碗",
        "食物 2": "100 克"
    }
}
只返回 JSON，不要其他内容。用中文回答。"""
                        },
                        {
                            "type": "image_url",
                            "image_url": {
                                "url": f"data:image/jpeg;base64,{base64_image}"
                            }
                        }
                    ]
                }
            ],
            "max_tokens": 500
        }
        
        response = requests.post(
            "https://api.moonshot.cn/v1/chat/completions",
            headers=headers,
            json=payload,
            timeout=30
        )
        response.raise_for_status()
        
        result = response.json()
        content = result['choices'][0]['message']['content']
        
        # 解析 JSON
        try:
            content = re.sub(r'```json\s*|\s*```', '', content)
            data = json.loads(content)
            return {
                'foods': data.get('foods', []),
                'description': data.get('description', ''),
                'servings': data.get('estimated_servings', {}),
                'confidence': 0.9
            }
        except Exception as e:
            logger.error(f"解析识别结果失败：{e}")
            return {
                'foods': [],
                'description': content,
                'servings': {},
                'confidence': 0.5
            }
    
    def _recognize_openai(self, image_path: str) -> Dict:
        """使用 OpenAI GPT-4V 识别"""
        import base64
        
        with open(image_path, 'rb') as f:
            base64_image = base64.b64encode(f.read()).decode('utf-8')
        
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        
        payload = {
            "model": "gpt-4o-mini",
            "messages": [
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "text",
                            "text": """请识别这张图片中的食物，并以 JSON 格式返回：
{
    "foods": ["食物 1", "食物 2", ...],
    "description": "简短描述这顿饭",
    "estimated_servings": {
        "食物 1": "1 碗",
        "食物 2": "100 克"
    }
}
只返回 JSON，不要其他内容。用中文回答。"""
                        },
                        {
                            "type": "image_url",
                            "image_url": {
                                "url": f"data:image/jpeg;base64,{base64_image}"
                            }
                        }
                    ]
                }
            ],
            "max_tokens": 500
        }
        
        response = requests.post(
            "https://api.openai.com/v1/chat/completions",
            headers=headers,
            json=payload,
            timeout=30
        )
        response.raise_for_status()
        
        result = response.json()
        content = result['choices'][0]['message']['content']
        
        # 解析 JSON
        try:
            # 清理可能的 markdown 标记
            content = re.sub(r'```json\s*|\s*```', '', content)
            data = json.loads(content)
            return {
                'foods': data.get('foods', []),
                'description': data.get('description', ''),
                'servings': data.get('estimated_servings', {}),
                'confidence': 0.9
            }
        except Exception as e:
            logger.error(f"解析识别结果失败：{e}")
            return {
                'foods': [],
                'description': content,
                'servings': {},
                'confidence': 0.5
            }
    
    def _recognize_claude(self, image_path: str) -> Dict:
        """使用 Claude Vision 识别"""
        # TODO: 实现 Claude Vision API
        raise NotImplementedError("Claude Vision 暂未实现")
    
    def _recognize_qwen(self, image_path: str) -> Dict:
        """使用 Qwen-VL 识别"""
        # TODO: 实现 Qwen-VL API
        raise NotImplementedError("Qwen-VL 暂未实现")


class NutritionCalculator:
    """营养计算器 - 查询卡路里"""
    
    # 常见食物卡路里参考数据（每 100 克）
    COMMON_FOODS = {
        '米饭': {'calories': 130, 'protein': 2.7, 'carbs': 28, 'fat': 0.3},
        '面条': {'calories': 110, 'protein': 2.5, 'carbs': 25, 'fat': 0.5},
        '馒头': {'calories': 220, 'protein': 7, 'carbs': 47, 'fat': 1},
        '面包': {'calories': 265, 'protein': 9, 'carbs': 49, 'fat': 3},
        '鸡蛋': {'calories': 155, 'protein': 13, 'carbs': 1.1, 'fat': 11},
        '牛奶': {'calories': 42, 'protein': 3.4, 'carbs': 5, 'fat': 1},
        '苹果': {'calories': 52, 'protein': 0.3, 'carbs': 14, 'fat': 0.2},
        '香蕉': {'calories': 89, 'protein': 1.1, 'carbs': 23, 'fat': 0.3},
        '鸡肉': {'calories': 165, 'protein': 31, 'carbs': 0, 'fat': 3.6},
        '猪肉': {'calories': 242, 'protein': 27, 'carbs': 0, 'fat': 14},
        '牛肉': {'calories': 250, 'protein': 26, 'carbs': 0, 'fat': 15},
        '鱼': {'calories': 206, 'protein': 22, 'carbs': 0, 'fat': 12},
        '青菜': {'calories': 20, 'protein': 2, 'carbs': 3, 'fat': 0.3},
        '土豆': {'calories': 77, 'protein': 2, 'carbs': 17, 'fat': 0.1},
        '番茄': {'calories': 18, 'protein': 0.9, 'carbs': 3.9, 'fat': 0.2},
    }
    
    def __init__(self, provider: str = 'local', app_id: str = None, api_key: str = None):
        self.provider = provider
        self.app_id = app_id or os.environ.get('NUTRITIONIX_APP_ID')
        self.[REDACTED_SECRET] or os.environ.get('NUTRITIONIX_API_KEY')
    
    def calculate(self, foods: List[str], servings: Dict = None) -> Dict:
        """
        计算食物的卡路里和营养
        
        Args:
            foods: 食物列表
            servings: 份量字典，如 {'米饭': '1 碗', '鸡肉': '100 克'}
            
        Returns:
            {
                'total_calories': 500,
                'total_protein': 30,
                'total_carbs': 50,
                'total_fat': 15,
                'items': [
                    {'name': '米饭', 'calories': 200, 'serving': '1 碗'},
                    ...
                ]
            }
        """
        if self.provider == 'nutritionix' and self.app_id:
            return self._calculate_nutritionix(foods, servings)
        else:
            return self._calculate_local(foods, servings)
    
    def _calculate_local(self, foods: List[str], servings: Dict = None) -> Dict:
        """使用本地数据库计算"""
        items = []
        total_calories = 0
        total_protein = 0
        total_carbs = 0
        total_fat = 0
        
        for food in foods:
            # 查找食物（模糊匹配）
            nutrition = self._find_food(food)
            
            if nutrition:
                # 估算份量（简化处理）
                serving = servings.get(food, '100 克') if servings else '100 克'
                multiplier = self._parse_serving(serving)
                
                calories = int(nutrition['calories'] * multiplier)
                protein = round(nutrition['protein'] * multiplier, 1)
                carbs = round(nutrition['carbs'] * multiplier, 1)
                fat = round(nutrition['fat'] * multiplier, 1)
                
                items.append({
                    'name': food,
                    'calories': calories,
                    'protein': protein,
                    'carbs': carbs,
                    'fat': fat,
                    'serving': serving
                })
                
                total_calories += calories
                total_protein += protein
                total_carbs += carbs
                total_fat += fat
        
        return {
            'total_calories': total_calories,
            'total_protein': round(total_protein, 1),
            'total_carbs': round(total_carbs, 1),
            'total_fat': round(total_fat, 1),
            'items': items
        }
    
    def _find_food(self, food_name: str) -> Optional[Dict]:
        """模糊查找食物"""
        food_name = food_name.lower()
        
        # 精确匹配
        if food_name in self.COMMON_FOODS:
            return self.COMMON_FOODS[food_name]
        
        # 模糊匹配
        for name, nutrition in self.COMMON_FOODS.items():
            if name in food_name or food_name in name:
                return nutrition
        
        # 返回默认值（估算）
        return {'calories': 100, 'protein': 5, 'carbs': 15, 'fat': 3}
    
    def _parse_serving(self, serving: str) -> float:
        """解析份量，返回倍数"""
        serving = serving.lower()
        
        # 提取数字
        numbers = re.findall(r'\d+\.?\d*', serving)
        if numbers:
            return float(numbers[0])
        
        # 常见份量估算
        if '碗' in serving:
            return 1.5  # 1 碗约 150 克
        elif '盘' in serving:
            return 2.0
        elif '个' in serving:
            return 1.0
        elif '杯' in serving:
            return 2.4
        elif '片' in serving:
            return 0.3
        else:
            return 1.0  # 默认 100 克
    
    def _calculate_nutritionix(self, foods: List[str], servings: Dict = None) -> Dict:
        """使用 Nutritionix API 计算"""
        # TODO: 实现 Nutritionix API 调用
        logger.info("使用本地数据库计算（Nutritionix API 暂未实现）")
        return self._calculate_local(foods, servings)


class FoodCalorieCalculator:
    """食物卡路里计算器 - 主类"""
    
    def __init__(self, config_path: str = 'config/config.yaml'):
        # 加载配置
        with open(config_path, 'r', encoding='utf-8') as f:
            self.config = yaml.safe_load(f)
        
        # 初始化模块
        vision_config = self.config.get('vision', {})
        api_keys = self.config.get('api_keys', {})
        
        self.recognizer = VisionRecognizer(
            provider=vision_config.get('provider', 'openai'),
            [REDACTED_SECRET]'openai')
        )
        
        nutrition_config = self.config.get('nutrition', {})
        self.calculator = NutritionCalculator(
            provider=nutrition_config.get('provider', 'local'),
            app_id=api_keys.get('nutritionix_app_id'),
            [REDACTED_SECRET]'nutritionix_api_key')
        )
    
    def analyze(self, image_path: str) -> Dict:
        """
        分析食物图片
        
        Returns:
            {
                'foods': [...],
                'description': '...',
                'nutrition': {
                    'total_calories': 500,
                    'total_protein': 30,
                    ...
                },
                'report': '完整的营养报告文本'
            }
        """
        logger.info(f"开始分析图片：{image_path}")
        
        # 1. 识别食物
        recognition = self.recognizer.recognize(image_path)
        logger.info(f"识别结果：{recognition['foods']}")
        
        # 2. 计算营养
        nutrition = self.calculator.calculate(
            recognition['foods'],
            recognition.get('servings')
        )
        
        # 3. 生成报告
        report = self._generate_report(recognition, nutrition)
        
        return {
            'foods': recognition['foods'],
            'description': recognition['description'],
            'nutrition': nutrition,
            'report': report
        }
    
    def _generate_report(self, recognition: Dict, nutrition: Dict) -> str:
        """生成营养报告"""
        lines = [
            "🍽️ **食物识别结果**",
            "",
            f"📝 {recognition['description']}",
            "",
            "📊 **营养分析**",
            "",
            f"🔥 总卡路里：**{nutrition['total_calories']} 大卡**",
            f"💪 蛋白质：{nutrition['total_protein']}g",
            f"🍚 碳水化合物：{nutrition['total_carbs']}g",
            f"🥑 脂肪：{nutrition['total_fat']}g",
            "",
            "📋 **详细分解**",
            ""
        ]
        
        for item in nutrition['items']:
            lines.append(f"• **{item['name']}** ({item['serving']})")
            lines.append(f"  - 卡路里：{item['calories']} 大卡")
            lines.append(f"  - 蛋白质：{item['protein']}g | 碳水：{item['carbs']}g | 脂肪：{item['fat']}g")
            lines.append("")
        
        lines.append("──────────────────────────────")
        lines.append("💡 温馨提示：以上数据为 AI 估算，实际营养含量可能因烹饪方式和食材差异而有所不同。")
        
        return '\n'.join(lines)


def main():
    """主函数 - 测试用"""
    import sys
    
    if len(sys.argv) < 2:
        print("用法：python3 src/calorie_calculator.py <图片路径>")
        print("示例：python3 src/calorie_calculator.py data/food.jpg")
        sys.exit(1)
    
    image_path = sys.argv[1]
    
    if not os.path.exists(image_path):
        print(f"错误：图片文件不存在：{image_path}")
        sys.exit(1)
    
    # 初始化计算器
    calculator = FoodCalorieCalculator()
    
    # 分析图片
    result = calculator.analyze(image_path)
    
    # 输出报告
    print(result['report'])


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)