Skill: yibinpro/fitdietkernel (version 1.0.1)

--- name: fitdietkernel description: 健身饮食的个人知识库 - 让AI精准帮你算饮食（碳循环/生酮/增肌/减脂） metadata: openclaw: emoji: "🏋️" category: "productivity" tags: ["diet", "fitness", "carbon-cycling", "macro", "health"] --- # FitDietKernel 🏋️ > 健身饮食的个人知识库，让 AI 成为你的精准饮食教练 ## 功能 - 🔢 精准碳水计算（按体重动态计算） - 🍚 食物注册（10g 碳水等值换算） - 📊 误差追踪（±10g 安全线） - 📋 自动打卡记录 - 📈 周报生成 ## 计算公式 ### 碳循环 ``` 低碳日 = 体重 × 1.0g 中碳日 = 体重 × 1.5g 高碳日 = 体重 × 3.0g 蛋白 = 体重 × 1.5~2.0g 脂肪 = 剩余热量 ``` ### 食物换算 (10g 碳水) | 食材 | 分量 | |------|------| | 燕麦 | 16g (干) | | 意面 | 13g (干) | | 杂粮馒头 | 0.5个 | | 蓝莓 | 72g | | 红薯 | 50g | ## 使用方法 1. 克隆仓库到本地 2. 修改 `profile.json` 配置你的体重、目标 3. 告诉 AI 知识库路径，让它读取数据 ``` 你是一个精准饮食教练，接入了 FitDietKernel。 数据路径：~/fitdietkernel/ ```

path: README.md
content: # FitDietKernel 🏋️

> **健身饮食的个人知识库**  
> 无论你用什么饮食方法，AI 都能精准帮你算

[![Stars](https://img.shields.io/github/stars/yibinpro/FitDietKernel?style=flat&color=2ecc71)](https://github.com/yibinpro/FitDietKernel)
[![License](https://img.shields.io/github/license/yibinpro/FitDietKernel)](https://github.com/yibinpro/FitDietKernel)

---

## ⚡ 快速安装 (OpenClaw / Claude Code)

```bash
# 方法1: 通过 ClawHub 安装 (推荐)
npx clawhub@latest install fitdietkernel

# 方法2: 手动安装
git clone https://github.com/yibinpro/FitDietKernel.git ~/fitdietkernel
```

### 配置 AI 助手

安装后告诉 AI：

```
你是一个精准饮食教练，接入了 FitDietKernel 个人知识库。

规则：
1. 优先读取 profile.json 获取我的体重、目标、饮食法
2. 查 knowledge_base/food_registry.json 计算食物数据
3. 查 knowledge_base/rules.md 执行凯圣王算法
4. 每天结束后生成 logs/YYYY-MM-DD.md 打卡记录
5. 碳水误差超过10g要警告我

数据路径：~/fitdietkernel/
```

---

## 🎯 解决什么问题

健身最痛的点：

| 痛点 | 传统 AI | FitDietKernel |
|------|---------|---------------|
| "这个能吃吗" | "馒头碳水高，少吃" | "1个=18.5g碳水，今天MC日能吃2个" |
| "今天吃超了吗" | "大概没超吧" | "实际52g，目标147g，-95g安全" |
| "上次那个食物呢" | "抱歉我忘了" | **永远记得** |

---

## 🏗️ 项目结构

```
FitDietKernel
├── profile.json              # 你是谁：体重、目标、饮食法
├── knowledge_base/
│   ├── food_registry.json    # 你的食物数据库（精准数据）
│   ├── recipes.json         # 验证过的食谱
│   └── rules.md              # 核心规则
└── logs/
    ├── 2026-04-06.md         # 每日打卡
    └── weekly_report/        # AI 周报
```

---

## 🥋 支持的饮食方法

| 饮食法 | 配置示例 |
|--------|----------|
| **碳循环** | 低95g / 中147g / 高315g |
| **生酮** | 碳水<30g，脂肪>70% |
| **增肌** | 碳水400g+，蛋白200g+ |
| **减脂** | 碳水150g，蛋白180g |
| **16:8间歇断食** | 进食窗口 12:00-20:00 |

---

## 🚀 快速开始

### 1. Fork 项目

点击右上角 Fork，修改成你的数据

### 2. 配置你的档案

```json
// profile.json
{
  "name": "你的名字",
  "currentWeight": 80,
  "targetWeight": 75,
  "height": 175,
  "age": 30,
  "activityLevel": "moderate",
  "dietType": "carbon_cycling"
}
```

**碳循环计算公式**（AI 自动帮你算）：

```
基础代谢 (BMR) = 体重(kg) × 23
运动消耗 (TDEE) = BMR × 1.4 ~ 1.6

// 碳水：按体重倍数
低碳日碳水 = 体重 × 1.0g
中碳日碳水 = 体重 × 1.5g  
高碳日碳水 = 体重 × 3.0g

// 蛋白：固定值，增肌/保持 1.5~2g/kg，减脂 2~2.5g/kg
蛋白 = 体重 × 1.5~2.0g

// 脂肪：剩余热量
脂肪 = (TDEE - 碳水×4 - 蛋白×4) / 9
```

比如 80kg 体重：
- **碳水**：低80g / 中120g / 高240g
- **蛋白**：120~160g (固定)
- **脂肪**：低碳日多点，高碳日少点

### 3. 接入 AI（OpenClaw 示例）

```
你是一个精准饮食教练。

规则：
1. 读 profile.json 获取我的饮食目标和预算
2. 查 food_registry.json 计算食物数据
3. 告诉我今天还能吃多少
```

---

## 💡 核心功能

### 🔢 精准计算

```
问：今天能吃几个馒头？
答：
- 你的馒头：1个 = 18.5g 碳水
- 今天是 MC 日，预算 147g
- 已吃：65g燕麦 + 50g蓝莓 = 40g
- 剩余：107g
- 可以吃：5.7个
```

### 📊 误差追踪

| 周 | 平均误差 | 状态 |
|----|----------|------|
| 第1周 | +8g | 🟢 |
| 第2周 | -5g | 🟢 |
| 第3周 | +22g | 🟡 需注意 |

### 🔄 新食物注册

```
"把这个贝果存入，1个=25g碳水，早餐用"
```

AI 自动更新数据库，下次直接查。

---

## 📖 谁适合用

- 🏋️ 任何健身饮食法的人
- 🥗 碳循环 / 生酮 / 增肌 / 减脂 / 间歇断食
- 🤖 用 AI 辅助健身的人

---

## 🔧 技术细节

- 数据存本地/GitHub，隐私安全
- 纯 JSON + Markdown，无数据库
- 配合任意 AI（ChatGPT/OpenClaw/Claude）

---

## 🤝 欢迎贡献

Fork 项目，添加你的饮食法配置，分享给更多人！

---

## 📄 License

MIT - 你自己的数据，存在你自己的仓库。

---

<p align="center">
  <img src="https://komarev.com/ghpvc/?username=yibinpro-FitDietKernel&label=Views&color=2ecc71" alt="Views">
</p>

path: _meta.json
content: {
  "schema": "openclaw@v1",
  "name": "FitDietKernel",
  "version": "1.0.0",
  "description": "健身饮食的个人知识库",
  "author": "YEST1N",
  "tags": ["diet", "fitness", "carbon-cycling", "macro", "health"],
  "category": "productivity"
}

path: desktop-app-gui.py
content: #!/usr/bin/env python3
import PySimpleGUI as sg
import json
import os
from datetime import datetime

# 配置主题
sg.theme("DarkGreen13")

DATA_FILE = "fitdiet_data.json"


class FitDietApp:
    def __init__(self):
        self.load_data()
        self.schedule = ["低", "中", "高", "中", "中", "高", "低"]
        self.macros = {"低": (95, 135, 126), "中": (147, 135, 59), "高": (315, 135, 38)}
        self.meals = {
            "高": [
                ("08:30", "早餐", "130g燕麦+蛋白粉+蓝莓"),
                ("12:00", "午餐", "4个馒头+150g肉"),
                ("17:30", "预充能", "意面+150g肉+玉米"),
                ("21:05", "PWO", "蛋白粉+蓝莓+馒头"),
            ],
            "中": [
                ("08:30", "早餐", "65g燕麦+蛋白粉+蓝莓"),
                ("12:00", "午餐", "2个馒头+150g肉"),
                ("17:30", "预充能", "意面+150g肉"),
                ("21:05", "PWO", "蛋白粉+蓝莓"),
            ],
            "低": [
                ("09:00", "早餐", "2全蛋+蛋白粉+蓝莓"),
                ("13:00", "午餐", "180g肉+牛油果"),
                ("18:00", "晚餐", "180g肉+坚果"),
                ("21:30", "睡前", "蛋白粉"),
            ],
        }

        self.checked_meals = set()
        self.window = None

    def load_data(self):
        if os.path.exists(DATA_FILE):
            with open(DATA_FILE, "r") as f:
                self.data = json.load(f)
        else:
            self.data = {"weight": 89.2, "weight_history": []}

    def save_data(self):
        with open(DATA_FILE, "w") as f:
            json.dump(self.data, f)

    def build_ui(self):
        today_idx = datetime.today().weekday()
        mode = self.schedule[today_idx]
        c, p, f = self.macros[mode]

        layout = [
            [
                sg.Text(
                    "FIT⚡DIET",
                    font=("SF Pro Display", 24, "bold"),
                    text_color="#00ff88",
                    justification="center",
                )
            ],
            [
                sg.Text(
                    "Kernel v1.0",
                    font=("SF Pro", 8),
                    text_color="#666",
                    justification="center",
                )
            ],
            [sg.Text("")],
            # 今日档位
            [
                sg.Text(
                    f"今日档位: {mode}",
                    font=("SF Pro", 14, "bold"),
                    text_color="#ffa502",
                    justification="center",
                )
            ],
            [
                sg.Text(
                    f"碳水 {c}g  |  蛋白 {p}g  |  脂肪 {f}g",
                    font=("SF Pro", 10),
                    text_color="#888",
                    justification="center",
                )
            ],
            [sg.HorizontalSeparator(color="#333")],
            # 打卡
            [sg.Text("今日打卡", font=("SF Pro", 12, "bold"))],
        ]

        for i, (t, n, d) in enumerate(self.meals[mode]):
            checked = i in self.checked_meals
            btn_color = ("#00ff88", "#000") if checked else ("#1a1a25", "#fff")
            layout.append(
                [
                    sg.Button(
                        f"{t} {n}\n{d}",
                        key=f"-MEAL-{i}-",
                        font=("SF Pro", 9),
                        button_color=btn_color,
                        border_width=1,
                        size=(30, 2),
                    )
                ]
            )

        layout.extend(
            [
                [sg.HorizontalSeparator(color="#333")],
                # 体重
                [sg.Text("体重追踪", font=("SF Pro", 12, "bold"))],
                [
                    sg.Text(
                        f"{self.data['weight']} kg",
                        font=("SF Pro", 28, "bold"),
                        text_color="#00ff88",
                        justification="center",
                    )
                ],
                [
                    sg.Input(key="-WEIGHT-", size=(10, 1), font=("SF Pro", 10)),
                    sg.Button("记录", key="-SAVE-", button_color=("#00ff88", "#000")),
                ],
                # 换算表
                [sg.HorizontalSeparator(color="#333")],
                [
                    sg.Text(
                        "10g碳水换算", font=("SF Pro", 10, "bold"), text_color="#666"
                    )
                ],
                [
                    sg.Text(
                        "燕麦16g | 意面13g | 馒头0.5个\n蓝莓72g | 红薯50g | 玉米45g",
                        font=("SF Pro", 8),
                        text_color="#888",
                        justification="center",
                    )
                ],
                [sg.Text("")],
                [
                    sg.Text(
                        datetime.now().strftime("%Y-%m-%d %H:%M"),
                        font=("SF Pro", 8),
                        text_color="#444",
                        justification="center",
                    )
                ],
            ]
        )

        return sg.Window(
            "FitDietKernel", layout, finalize=True, keep_on_top=True, size=(320, 600)
        )

    def run(self):
        self.window = self.build_ui()

        while True:
            event, values = self.window.read(timeout=1000)

            if event in (sg.WIN_CLOSED, "Exit"):
                break

            if event.startswith("-MEAL-"):
                idx = int(event.split("-")[2])
                if idx in self.checked_meals:
                    self.checked_meals.remove(idx)
                else:
                    self.checked_meals.add(idx)
                self.window.close()
                self.window = self.build_ui()

            if event == "-SAVE-":
                w = values["-WEIGHT-"]
                if w:
                    self.data["weight"] = float(w)
                    self.data["weight_history"].append(
                        {"d": datetime.now().strftime("%m-%d"), "w": float(w)}
                    )
                    self.save_data()
                    self.window.close()
                    self.window = self.build_ui()

        self.window.close()


if __name__ == "__main__":
    app = FitDietApp()
    app.run()


path: desktop-app.html
content: <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FitDiet Kernel</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        :root {
            --primary: #00ff88;
            --primary-dim: #00cc6a;
            --bg: #0a0a0f;
            --bg-card: #12121a;
            --bg-card-hover: #1a1a25;
            --text: #ffffff;
            --text-dim: #8888aa;
            --accent-low: #5352ed;
            --accent-mid: #ffa502;
            --accent-high: #ff4757;
            --border: #2a2a3a;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;
            background: var(--bg);
            color: var(--text);
            min-height: 100vh;
            overflow-x: hidden;
        }

        /* 背景效果 */
        .bg-gradient {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: 
                radial-gradient(ellipse at 20% 20%, rgba(0,255,136,0.08) 0%, transparent 50%),
                radial-gradient(ellipse at 80% 80%, rgba(83,82,237,0.06) 0%, transparent 50%),
                radial-gradient(ellipse at 50% 100%, rgba(255,165,2,0.04) 0%, transparent 40%);
            pointer-events: none;
            z-index: 0;
        }

        .container {
            max-width: 480px;
            margin: 0 auto;
            padding: 20px;
            position: relative;
            z-index: 1;
        }

        /* Header */
        .header {
            text-align: center;
            padding: 30px 0 20px;
            position: relative;
        }

        .header::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            width: 80px;
            height: 2px;
            background: linear-gradient(90deg, transparent, var(--primary), transparent);
        }

        .logo {
            font-size: 1.8rem;
            font-weight: 200;
            letter-spacing: 6px;
            color: var(--text);
            margin-bottom: 5px;
        }

        .logo span {
            color: var(--primary);
            font-weight: 600;
        }

        .subtitle {
            font-size: 0.7rem;
            color: var(--text-dim);
            letter-spacing: 3px;
            text-transform: uppercase;
        }

        /* 今日状态 */
        .today-card {
            background: linear-gradient(135deg, var(--bg-card) 0%, #15151f 100%);
            border-radius: 20px;
            padding: 25px;
            margin-bottom: 20px;
            border: 1px solid var(--border);
            box-shadow: 0 10px 40px rgba(0,0,0,0.3);
        }

        .today-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
        }

        .day-label {
            font-size: 0.85rem;
            color: var(--text-dim);
        }

        .mode-badge {
            padding: 6px 14px;
            border-radius: 20px;
            font-size: 0.75rem;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        .mode-badge.low { background: rgba(83,82,237,0.2); color: var(--accent-low); }
        .mode-badge.mid { background: rgba(255,165,2,0.2); color: var(--accent-mid); }
        .mode-badge.high { background: rgba(255,71,87,0.2); color: var(--accent-high); }

        .today-title {
            font-size: 1.5rem;
            font-weight: 700;
            margin-bottom: 5px;
        }

        .today-subtitle {
            font-size: 0.8rem;
            color: var(--text-dim);
        }

        /* 宏量进度条 */
        .macro-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 12px;
            margin-top: 20px;
        }

        .macro-item {
            background: rgba(0,0,0,0.3);
            border-radius: 14px;
            padding: 15px;
            text-align: center;
            position: relative;
            overflow: hidden;
        }

        .macro-item::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 3px;
        }

        .macro-item.carbon::before { background: var(--accent-mid); }
        .macro-item.protein::before { background: var(--primary); }
        .macro-item.fat::before { background: var(--accent-low); }

        .macro-value {
            font-size: 1.4rem;
            font-weight: 800;
            display: block;
        }

        .macro-label {
            font-size: 0.65rem;
            color: var(--text-dim);
            text-transform: uppercase;
            letter-spacing: 1px;
            margin-top: 5px;
            display: block;
        }

        .macro-progress {
            height: 4px;
            background: rgba(255,255,255,0.1);
            border-radius: 2px;
            margin-top: 10px;
            overflow: hidden;
        }

        .macro-progress-fill {
            height: 100%;
            border-radius: 2px;
            transition: width 0.5s ease;
        }

        .carbon .macro-progress-fill { background: var(--accent-mid); }
        .protein .macro-progress-fill { background: var(--primary); }
        .fat .macro-progress-fill { background: var(--accent-low); }

        /* 打卡卡片 */
        .checklist-card {
            background: var(--bg-card);
            border-radius: 20px;
            padding: 20px;
            margin-bottom: 20px;
            border: 1px solid var(--border);
        }

        .card-title {
            font-size: 0.9rem;
            font-weight: 600;
            margin-bottom: 15px;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .card-title::before {
            content: '▸';
            color: var(--primary);
        }

        .meal-item {
            background: rgba(0,0,0,0.2);
            border-radius: 12px;
            padding: 15px;
            margin-bottom: 10px;
            border-left: 3px solid var(--primary);
            cursor: pointer;
            transition: all 0.2s;
        }

        .meal-item:hover {
            background: rgba(0,255,136,0.05);
        }

        .meal-item.checked {
            opacity: 0.5;
            border-left-color: var(--text-dim);
        }

        .meal-item.checked .meal-name {
            text-decoration: line-through;
        }

        .meal-time {
            font-size: 0.7rem;
            color: var(--primary);
            margin-bottom: 5px;
        }

        .meal-name {
            font-size: 0.9rem;
            font-weight: 500;
        }

        .meal-desc {
            font-size: 0.75rem;
            color: var(--text-dim);
            margin-top: 5px;
        }

        /* 食物库 */
        .food-card {
            background: var(--bg-card);
            border-radius: 20px;
            padding: 20px;
            margin-bottom: 20px;
            border: 1px solid var(--border);
        }

        .food-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 10px;
        }

        .food-item {
            background: rgba(0,0,0,0.2);
            border-radius: 10px;
            padding: 12px;
            text-align: center;
            font-size: 0.75rem;
        }

        .food-item b {
            display: block;
            color: var(--primary);
            margin-bottom: 3px;
        }

        /* 体重图表 */
        .weight-card {
            background: var(--bg-card);
            border-radius: 20px;
            padding: 20px;
            margin-bottom: 20px;
            border: 1px solid var(--border);
        }

        .weight-input-group {
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
        }

        .weight-input-group input {
            flex: 1;
            padding: 12px 15px;
            background: rgba(0,0,0,0.3);
            border: 1px solid var(--border);
            border-radius: 10px;
            color: var(--text);
            font-size: 1rem;
        }

        .weight-input-group button {
            padding: 12px 20px;
            background: var(--primary);
            border: none;
            border-radius: 10px;
            color: var(--bg);
            font-weight: 600;
            cursor: pointer;
        }

        .current-weight {
            text-align: center;
            font-size: 2rem;
            font-weight: 800;
            color: var(--primary);
            margin-bottom: 15px;
        }

        .current-weight span {
            font-size: 0.9rem;
            color: var(--text-dim);
            font-weight: 400;
        }

        /* 周进度 */
        .week-card {
            background: var(--bg-card);
            border-radius: 20px;
            padding: 20px;
            border: 1px solid var(--border);
        }

        .week-grid {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 8px;
            margin-top: 15px;
        }

        .week-day {
            text-align: center;
            padding: 10px 5px;
            border-radius: 10px;
            background: rgba(0,0,0,0.2);
            font-size: 0.7rem;
        }

        .week-day.active {
            background: var(--primary);
            color: var(--bg);
        }

        .week-day.low { border: 1px solid var(--accent-low); }
        .week-day.mid { border: 1px solid var(--accent-mid); }
        .week-day.high { border: 1px solid var(--accent-high); }

        /* 时间 */
        .time-display {
            text-align: center;
            font-size: 0.8rem;
            color: var(--text-dim);
            margin-top: 20px;
            padding: 15px;
            background: rgba(0,0,0,0.2);
            border-radius: 10px;
        }
    </style>
</head>
<body>
    <div class="bg-gradient"></div>
    
    <div class="container">
        <header class="header">
            <div class="logo">FIT<span>DIET</span></div>
            <div class="subtitle">Kernel v1.0</div>
        </header>

        <!-- 今日状态 -->
        <div class="today-card">
            <div class="today-header">
                <div class="day-label" id="dayLabel">周三 · 高碳日</div>
                <div class="mode-badge high" id="modeBadge">HIGH</div>
            </div>
            <div class="today-title">碳水目标</div>
            <div class="today-subtitle" id="carbonTarget">315g · 已摄入 0g · 剩余 315g</div>

            <div class="macro-grid">
                <div class="macro-item carbon">
                    <span class="macro-value" id="carbonValue">0 / 315g</span>
                    <span class="macro-label">碳水</span>
                    <div class="macro-progress">
                        <div class="macro-progress-fill" id="carbonProgress" style="width: 0%"></div>
                    </div>
                </div>
                <div class="macro-item protein">
                    <span class="macro-value" id="proteinValue">0 / 135g</span>
                    <span class="macro-label">蛋白</span>
                    <div class="macro-progress">
                        <div class="macro-progress-fill" id="proteinProgress" style="width: 0%"></div>
                    </div>
                </div>
                <div class="macro-item fat">
                    <span class="macro-value" id="fatValue">0 / 38g</span>
                    <span class="macro-label">脂肪</span>
                    <div class="macro-progress">
                        <div class="macro-progress-fill" id="fatProgress" style="width: 0%"></div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 打卡列表 -->
        <div class="checklist-card">
            <div class="card-title">今日打卡</div>
            <div id="mealList"></div>
        </div>

        <!-- 食物库 -->
        <div class="food-card">
            <div class="card-title">10g 碳水换算</div>
            <div class="food-grid">
                <div class="food-item"><b>燕麦</b>16g</div>
                <div class="food-item"><b>意面</b>13g</div>
                <div class="food-item"><b>馒头</b>0.5个</div>
                <div class="food-item"><b>蓝莓</b>72g</div>
                <div class="food-item"><b>红薯</b>50g</div>
                <div class="food-item"><b>玉米</b>45g</div>
            </div>
        </div>

        <!-- 体重 -->
        <div class="weight-card">
            <div class="card-title">体重追踪</div>
            <div class="current-weight" id="currentWeight">89.2 <span>kg</span></div>
            <div class="weight-input-group">
                <input type="number" id="weightInput" step="0.1" placeholder="输入今日体重">
                <button onclick="saveWeight()">记录</button>
            </div>
            <canvas id="weightChart" height="100"></canvas>
        </div>

        <!-- 周进度 -->
        <div class="week-card">
            <div class="card-title">本周档位</div>
            <div class="week-grid">
                <div class="week-day low" id="day0">一<br>LC</div>
                <div class="week-day mid" id="day1">二<br>MC</div>
                <div class="week-day high active" id="day2">三<br>HC</div>
                <div class="week-day mid" id="day3">四<br>MC</div>
                <div class="week-day mid" id="day4">五<br>MC</div>
                <div class="week-day high" id="day5">六<br>HC</div>
                <div class="week-day low" id="day6">日<br>LC</div>
            </div>
        </div>

        <div class="time-display" id="timeDisplay"></div>
    </div>

<script>
    // 数据配置
    const config = {
        weight: 89.2,
        targetWeight: 85,
        schedule: ['low', 'mid', 'high', 'mid', 'mid', 'high', 'low'],
        macros: {
            low: { c: 95, p: 135, f: 126 },
            mid: { c: 147, p: 135, f: 59 },
            high: { c: 315, p: 135, f: 38 }
        },
        meals: {
            high: [
                { time: '08:30', name: '早餐', desc: '130g燕麦 + 蛋白粉 + 蓝莓' },
                { time: '12:00', name: '午餐', desc: '4个杂粮馒头 + 150g肉' },
                { time: '17:30', name: '预充能', desc: '意面 + 150g肉 + 玉米' },
                { time: '21:05', name: 'PWO', desc: '蛋白粉 + 蓝莓 + 馒头' }
            ],
            mid: [
                { time: '08:30', name: '早餐', desc: '65g燕麦 + 蛋白粉 + 蓝莓' },
                { time: '12:00', name: '午餐', desc: '2个杂粮馒头 + 150g肉' },
                { time: '17:30', name: '预充能', desc: '意面 + 150g肉' },
                { time: '21:05', name: 'PWO', desc: '蛋白粉 + 蓝莓' }
            ],
            low: [
                { time: '09:00', name: '早餐', desc: '2全蛋 + 蛋白粉 + 蓝莓' },
                { time: '13:00', name: '午餐', desc: '180g肉 + 牛油果' },
                { time: '18:00', name: '晚餐', desc: '180g肉 + 坚果' },
                { time: '21:30', name: '睡前', desc: '蛋白粉' }
            ]
        }
    };

    // 初始化
    let today = new Date().getDay();
    let currentMode = config.schedule[today === 0 ? 6 : today - 1];
    const modeLabels = { low: '低碳', mid: '中碳', high: '高碳' };
    const modeClasses = { low: 'low', mid: 'mid', high: 'high' };
    const dayLabels = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];

    // 更新界面
    function updateUI() {
        const todayIndex = new Date().getDay();
        const displayIndex = todayIndex === 0 ? 6 : todayIndex - 1;
        const todayMode = config.schedule[displayIndex];
        const macros = config.macros[todayMode];

        // 今日信息
        document.getElementById('dayLabel').innerText = `${dayLabels[displayIndex]} · ${modeLabels[todayMode]}日`;
        document.getElementById('modeBadge').innerText = todayMode.toUpperCase();
        document.getElementById('modeBadge').className = `mode-badge ${modeClasses[todayMode]}`;
        document.getElementById('carbonTarget').innerText = `${macros.c}g · 已摄入 0g · 剩余 ${macros.c}g`;

        // 宏量值
        document.getElementById('carbonValue').innerText = `0 / ${macros.c}g`;
        document.getElementById('proteinValue').innerText = `0 / ${macros.p}g`;
        document.getElementById('fatValue').innerText = `0 / ${macros.f}g`;

        // 渲染打卡
        const meals = config.meals[todayMode];
        const mealHtml = meals.map((m, i) => `
            <div class="meal-item" onclick="toggleMeal(this)">
                <div class="meal-time">${m.time}</div>
                <div class="meal-name">${m.name}</div>
                <div class="meal-desc">${m.desc}</div>
            </div>
        `).join('');
        document.getElementById('mealList').innerHTML = mealHtml;

        // 更新周视图
        document.querySelectorAll('.week-day').forEach((el, i) => {
            el.classList.remove('active');
            if (i === displayIndex) el.classList.add('active');
        });

        // 时间
        updateTime();
    }

    function toggleMeal(el) {
        el.classList.toggle('checked');
    }

    function updateTime() {
        const now = new Date();
        const options = { 
            year: 'numeric', month: 'long', day: 'numeric', 
            weekday: 'long', hour: '2-digit', minute: '2-digit' 
        };
        document.getElementById('timeDisplay').innerText = now.toLocaleString('zh-CN', options);
    }

    // 体重追踪
    function saveWeight() {
        const w = document.getElementById('weightInput').value;
        if (!w) return;
        config.weight = parseFloat(w);
        localStorage.setItem('fdk_weight', JSON.stringify({
            current: config.weight,
            history: JSON.parse(localStorage.getItem('fdk_weight_history') || '[]').concat({
                d: new Date().toLocaleDateString('zh-CN'), w: config.weight
            })
        }));
        document.getElementById('currentWeight').innerHTML = `${config.weight} <span>kg</span>`;
        document.getElementById('weightInput').value = '';
        initChart();
    }

    // 图表
    let chart = null;
    function initChart() {
        const history = JSON.parse(localStorage.getItem('fdk_weight_history') || '[]');
        if (history.length === 0) return;

        document.getElementById('currentWeight').innerHTML = `${history[history.length-1].w} <span>kg</span>`;
        
        const ctx = document.getElementById('weightChart').getContext('2d');
        if (chart) chart.destroy();
        
        chart = new Chart(ctx, {
            type: 'line',
            data: {
                labels: history.map(i => i.d),
                datasets: [{
                    data: history.map(i => i.w),
                    borderColor: '#00ff88',
                    backgroundColor: 'rgba(0,255,136,0.1)',
                    fill: true,
                    tension: 0.4,
                    pointRadius: 3,
                    pointBackgroundColor: '#00ff88'
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                scales: {
                    y: { grid: { color: '#2a2a3a' }, ticks: { color: '#888' } },
                    x: { display: false }
                },
                plugins: { legend: { display: false } }
            }
        });
    }

    // 启动
    updateUI();
    setInterval(updateTime, 1000);
    initChart();
</script>
</body>
</html>

path: desktop-app.py
content: #!/usr/bin/env python3
import customtkinter as ctk
import json
import os
from datetime import datetime
from threading import Thread
import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
from io import BytesIO
import base64

# 配置
ctk.set_appearance_mode("dark")
ctk.set_default_color_theme("green")

DATA_FILE = "fitdiet_data.json"


class FitDietApp(ctk.CTk):
    def __init__(self):
        super().__init__()

        self.title("FitDiet Kernel")
        self.geometry("400x700")
        self.resizable(False, False)

        self.load_data()
        self.setup_ui()
        self.update_time()

    def load_data(self):
        if os.path.exists(DATA_FILE):
            with open(DATA_FILE, "r") as f:
                self.data = json.load(f)
        else:
            self.data = {
                "weight": 89.2,
                "target": 85,
                "weight_history": [],
                "meals": {},
            }

        # 碳循环配置
        self.schedule = ["low", "mid", "high", "mid", "mid", "high", "low"]
        self.macros = {
            "low": {"c": 95, "p": 135, "f": 126},
            "mid": {"c": 147, "p": 135, "f": 59},
            "high": {"c": 315, "p": 135, "f": 38},
        }
        self.meals_config = {
            "high": [
                ("08:30", "早餐", "130g燕麦 + 蛋白粉 + 蓝莓"),
                ("12:00", "午餐", "4个杂粮馒头 + 150g肉"),
                ("17:30", "预充能", "意面 + 150g肉 + 玉米"),
                ("21:05", "PWO", "蛋白粉 + 蓝莓 + 馒头"),
            ],
            "mid": [
                ("08:30", "早餐", "65g燕麦 + 蛋白粉 + 蓝莓"),
                ("12:00", "午餐", "2个杂粮馒头 + 150g肉"),
                ("17:30", "预充能", "意面 + 150g肉"),
                ("21:05", "PWO", "蛋白粉 + 蓝莓"),
            ],
            "low": [
                ("09:00", "早餐", "2全蛋 + 蛋白粉 + 蓝莓"),
                ("13:00", "午餐", "180g肉 + 牛油果"),
                ("18:00", "晚餐", "180g肉 + 坚果"),
                ("21:30", "睡前", "蛋白粉"),
            ],
        }

    def save_data(self):
        with open(DATA_FILE, "w") as f:
            json.dump(self.data, f)

    def setup_ui(self):
        # 标题
        title_frame = ctk.CTkFrame(self, fg_color="transparent")
        title_frame.pack(fill="x", pady=(20, 10))

        title_label = ctk.CTkLabel(
            title_frame,
            text="FIT⚡DIET",
            font=("SF Pro Display", 28, "bold"),
            text_color="#00ff88",
        )
        title_label.pack()

        ctk.CTkLabel(
            title_frame, text="Kernel v1.0", font=("SF Pro", 10), text_color="#666"
        ).pack()

        # 今日状态卡片
        self.today_card = ctk.CTkFrame(self, corner_radius=20)
        self.today_card.pack(fill="x", padx=15, pady=10)

        # 档位标签
        today_idx = datetime.today().weekday()
        today_mode = self.schedule[today_idx]
        mode_colors = {"low": "#5352ed", "mid": "#ffa502", "high": "#ff4757"}

        self.mode_label = ctk.CTkLabel(
            self.today_card,
            text=f"今日: {today_mode.upper()}",
            font=("SF Pro", 12, "bold"),
            text_color=mode_colors[today_mode],
        )
        self.mode_label.pack(pady=(15, 5))

        ctk.CTkLabel(
            self.today_card,
            text=f"碳水目标: {self.macros[today_mode]['c']}g",
            font=("SF Pro", 16, "bold"),
        ).pack(pady=5)

        # 进度条
        self.progress_c = ctk.CTkProgressBar(self.today_card, progress_color="#ffa502")
        self.progress_c.pack(fill="x", padx=20, pady=10)
        self.progress_c.set(0)

        # 宏量数据
        macro_frame = ctk.CTkFrame(self.today_card, fg_color="transparent")
        macro_frame.pack(fill="x", padx=15, pady=(0, 15))

        macros = self.macros[today_mode]
        for name, val in [
            ("碳水", f"{macros['c']}g"),
            ("蛋白", f"{macros['p']}g"),
            ("脂肪", f"{macros['f']}g"),
        ]:
            ctk.CTkLabel(macro_frame, text=val, font=("SF Pro", 14, "bold")).pack(
                side="left", expand=True
            )
            ctk.CTkLabel(
                macro_frame, text=name, font=("SF Pro", 10), text_color="#666"
            ).pack(side="left", padx=(0, 15))

        # 打卡卡片
        check_card = ctk.CTkFrame(self, corner_radius=20)
        check_card.pack(fill="both", expand=True, padx=15, pady=10)

        ctk.CTkLabel(check_card, text="今日打卡", font=("SF Pro", 14, "bold")).pack(
            pady=(15, 10)
        )

        self.meal_buttons = []
        for time, name, desc in self.meals_config[today_mode]:
            btn = ctk.CTkButton(
                check_card,
                text=f"{time} {name}\n{desc}",
                fg_color="#1a1a25",
                hover_color="#00ff88",
                border_width=1,
                border_color="#333",
                text_color="#fff",
                font=("SF Pro", 11),
                height=50,
                command=lambda b=len(self.meal_buttons): self.toggle_meal(b),
            )
            btn.pack(fill="x", padx=15, pady=5)
            self.meal_buttons.append(btn)

        # 体重卡片
        weight_card = ctk.CTkFrame(self, corner_radius=20)
        weight_card.pack(fill="x", padx=15, pady=10)

        ctk.CTkLabel(weight_card, text="体重追踪", font=("SF Pro", 14, "bold")).pack(
            pady=(15, 10)
        )

        self.weight_label = ctk.CTkLabel(
            weight_card,
            text=f"{self.data['weight']} kg",
            font=("SF Pro", 32, "bold"),
            text_color="#00ff88",
        )
        self.weight_label.pack()

        weight_input_frame = ctk.CTkFrame(weight_card, fg_color="transparent")
        weight_input_frame.pack(fill="x", padx=15, pady=10)

        self.weight_input = ctk.CTkEntry(
            weight_input_frame,
            placeholder_text="输入体重",
            fg_color="#1a1a25",
            border_color="#333",
        )
        self.weight_input.pack(side="left", fill="x", expand=True, padx=(0, 10))

        ctk.CTkButton(
            weight_input_frame,
            text="记录",
            fg_color="#00ff88",
            text_color="#000",
            width=60,
            command=self.save_weight,
        ).pack(side="left")

        # 时间显示
        self.time_label = ctk.CTkLabel(
            self, text="", font=("SF Pro", 10), text_color="#444"
        )
        self.time_label.pack(pady=10)

    def toggle_meal(self, idx):
        btn = self.meal_buttons[idx]
        if btn.cget("fg_color") == "#00ff88":
            btn.configure(fg_color="#1a1a25", text_color="#fff")
        else:
            btn.configure(fg_color="#00ff88", text_color="#000")

    def save_weight(self):
        w = self.weight_input.get()
        if not w:
            return
        self.data["weight"] = float(w)
        self.data["weight_history"].append(
            {"d": datetime.now().strftime("%m-%d"), "w": float(w)}
        )
        self.save_data()

        self.weight_label.configure(text=f"{w} kg")
        self.weight_input.delete(0, "end")

    def update_time(self):
        now = datetime.now()
        self.time_label.configure(text=now.strftime("%Y年%m月%d日 %H:%M"))
        self.after(1000, self.update_time)


if __name__ == "__main__":
    app = FitDietApp()
    app.mainloop()


path: desktop-tkinter.py
content: #!/usr/bin/env python3
import tkinter as tk
from tkinter import ttk
import json
import os
from datetime import datetime

# 颜色配置
BG_COLOR = "#0a0a0f"
CARD_COLOR = "#12121a"
TEXT_COLOR = "#ffffff"
DIM_COLOR = "#666666"
ACCENT_COLOR = "#00ff88"
ORANGE_COLOR = "#ffa502"

DATA_FILE = "fitdiet_data.json"


class FitDietApp:
    def __init__(self, root):
        self.root = root
        self.root.title("FitDiet Kernel")
        self.root.geometry("350x650")
        self.root.configure(bg=BG_COLOR)
        self.root.resizable(False, False)

        self.load_data()
        self.schedule = ["低", "中", "高", "中", "中", "高", "低"]
        self.macros = {"低": (95, 135, 126), "中": (147, 135, 59), "高": (315, 135, 38)}
        self.meals = {
            "高": [
                ("08:30", "早餐", "130g燕麦+蛋白粉+蓝莓"),
                ("12:00", "午餐", "4个馒头+150g肉"),
                ("17:30", "预充能", "意面+150g肉+玉米"),
                ("21:05", "PWO", "蛋白粉+蓝莓+馒头"),
            ],
            "中": [
                ("08:30", "早餐", "65g燕麦+蛋白粉+蓝莓"),
                ("12:00", "午餐", "2个馒头+150g肉"),
                ("17:30", "预充能", "意面+150g肉"),
                ("21:05", "PWO", "蛋白粉+蓝莓"),
            ],
            "低": [
                ("09:00", "早餐", "2全蛋+蛋白粉+蓝莓"),
                ("13:00", "午餐", "180g肉+牛油果"),
                ("18:00", "晚餐", "180g肉+坚果"),
                ("21:30", "睡前", "蛋白粉"),
            ],
        }

        self.checked_meals = set()
        self.setup_ui()
        self.update_time()

    def load_data(self):
        if os.path.exists(DATA_FILE):
            with open(DATA_FILE, "r") as f:
                self.data = json.load(f)
        else:
            self.data = {"weight": 89.2, "weight_history": []}

    def save_data(self):
        with open(DATA_FILE, "w") as f:
            json.dump(self.data, f)

    def setup_ui(self):
        # 标题
        title = tk.Label(
            self.root,
            text="FIT⚡DIET",
            font=("SF Pro Display", 24, "bold"),
            bg=BG_COLOR,
            fg=ACCENT_COLOR,
        )
        title.pack(pady=(20, 5))

        tk.Label(
            self.root, text="Kernel v1.0", font=("SF Pro", 8), bg=BG_COLOR, fg=DIM_COLOR
        ).pack()

        # 今日档位
        today_idx = datetime.today().weekday()
        mode = self.schedule[today_idx]
        c, p, f = self.macros[mode]

        mode_card = tk.Frame(self.root, bg=CARD_COLOR, bd=1, relief="flat")
        mode_card.pack(fill="x", padx=15, pady=15)

        tk.Label(
            mode_card,
            text=f"今日档位: {mode}",
            font=("SF Pro", 14, "bold"),
            bg=CARD_COLOR,
            fg=ORANGE_COLOR,
        ).pack(pady=10)
        tk.Label(
            mode_card,
            text=f"碳水 {c}g  |  蛋白 {p}g  |  脂肪 {f}g",
            font=("SF Pro", 10),
            bg=CARD_COLOR,
            fg=DIM_COLOR,
        ).pack(pady=(0, 10))

        # 打卡
        check_card = tk.Frame(self.root, bg=CARD_COLOR, bd=1, relief="flat")
        check_card.pack(fill="both", expand=True, padx=15, pady=5)

        tk.Label(
            check_card,
            text="今日打卡",
            font=("SF Pro", 12, "bold"),
            bg=CARD_COLOR,
            fg=TEXT_COLOR,
        ).pack(pady=10)

        self.meal_buttons = []
        for i, (t, n, d) in enumerate(self.meals[mode]):
            btn = tk.Button(
                check_card,
                text=f"{t} {n}\n{d}",
                font=("SF Pro", 9),
                bg="#1a1a25",
                fg=TEXT_COLOR,
                bd=1,
                relief="flat",
                wraplength=250,
                command=lambda idx=i: self.toggle_meal(idx),
            )
            btn.pack(fill="x", padx=10, pady=3)
            self.meal_buttons.append(btn)

        # 体重
        weight_card = tk.Frame(self.root, bg=CARD_COLOR, bd=1, relief="flat")
        weight_card.pack(fill="x", padx=15, pady=10)

        tk.Label(
            weight_card,
            text="体重追踪",
            font=("SF Pro", 12, "bold"),
            bg=CARD_COLOR,
            fg=TEXT_COLOR,
        ).pack(pady=10)

        self.weight_label = tk.Label(
            weight_card,
            text=f"{self.data['weight']} kg",
            font=("SF Pro", 28, "bold"),
            bg=CARD_COLOR,
            fg=ACCENT_COLOR,
        )
        self.weight_label.pack()

        input_frame = tk.Frame(weight_card, bg=CARD_COLOR)
        input_frame.pack(pady=10)

        self.weight_input = tk.Entry(
            input_frame,
            font=("SF Pro", 10),
            bg="#1a1a25",
            fg=TEXT_COLOR,
            bd=0,
            width=12,
        )
        self.weight_input.pack(side="left", padx=5)

        tk.Button(
            input_frame,
            text="记录",
            font=("SF Pro", 10),
            bg=ACCENT_COLOR,
            fg=BG_COLOR,
            bd=0,
            command=self.save_weight,
        ).pack(side="left")

        # 换算表
        tk.Label(
            self.root,
            text="10g碳水换算: 燕麦16g | 意面13g | 馒头0.5个 | 蓝莓72g | 红薯50g",
            font=("SF Pro", 8),
            bg=BG_COLOR,
            fg=DIM_COLOR,
        ).pack(pady=5)

        # 时间
        self.time_label = tk.Label(
            self.root, text="", font=("SF Pro", 8), bg=BG_COLOR, fg=DIM_COLOR
        )
        self.time_label.pack(pady=10)

    def toggle_meal(self, idx):
        if idx in self.checked_meals:
            self.checked_meals.remove(idx)
            self.meal_buttons[idx].configure(bg="#1a1a25", fg=TEXT_COLOR)
        else:
            self.checked_meals.add(idx)
            self.meal_buttons[idx].configure(bg=ACCENT_COLOR, fg=BG_COLOR)

    def save_weight(self):
        w = self.weight_input.get()
        if w:
            self.data["weight"] = float(w)
            self.data["weight_history"].append(
                {"d": datetime.now().strftime("%m-%d"), "w": float(w)}
            )
            self.save_data()
            self.weight_label.configure(text=f"{w} kg")
            self.weight_input.delete(0, "end")

    def update_time(self):
        now = datetime.now()
        self.time_label.configure(text=now.strftime("%Y-%m-%d %H:%M"))
        self.root.after(1000, self.update_time)


if __name__ == "__main__":
    root = tk.Tk()
    app = FitDietApp(root)
    root.mainloop()


path: knowledge_base/food_registry.json
content: {
  "version": "1.0",
  "description": "个人食物数据库 - 碳水等值换算 (每10g单位为基准)",
  "lastUpdated": "2026-04-06",
  "foods": [
    {
      "id": "mt_001",
      "name": "杂粮馒头",
      "alias": ["馒头", "粗粮馒头"],
      "unit": "个",
      "carbonPerUnit": 18.5,
      "carbonPer10g": 5.4,
      "tags": ["主食", "中高碳日", "便捷"],
      "note": "控制误差关键：不要因为'小'就多吃"
    },
    {
      "id": "oat_001",
      "name": "五黑燕麦",
      "alias": ["燕麦", "干燕麦"],
      "unit": "g (干重)",
      "carbonPerUnit": 10,
      "carbonPer10g": 10,
      "tags": ["主食", "早餐", "高碳日"],
      "note": "干重换算，泡开后约3倍重量"
    },
    {
      "id": "pasta_001",
      "name": "意大利面",
      "alias": ["意面", "意粉"],
      "unit": "g (干重)",
      "carbonPerUnit": 10,
      "carbonPer10g": 10,
      "tags": ["主食", "预充能", "高碳日"],
      "note": "干重计算，煮熟后约2.5倍"
    },
    {
      "id": "berry_001",
      "name": "蓝莓",
      "alias": ["新鲜蓝莓"],
      "unit": "g",
      "carbonPer10g": 1.39,
      "tags": ["碳水来源", "抗氧化", "全天候"],
      "note": "升糖指数低，可用于填充糖原"
    },
    {
      "id": "sweet_potato_001",
      "name": "红薯",
      "alias": ["地瓜", "番薯"],
      "unit": "g",
      "carbonPer10g": 2,
      "tags": ["主食", "中碳日"],
      "note": "需冷藏12小时以上食用"
    },
    {
      "id": "corn_001",
      "name": "水果玉米",
      "alias": ["玉米", "甜玉米"],
      "unit": "根",
      "carbonPerUnit": 22,
      "carbonPer10g": 4.5,
      "tags": ["主食", "高碳日"],
      "note": "1根约45-50g碳水"
    },
    {
      "id": "avocado_001",
      "name": "牛油果",
      "alias": [],
      "unit": "个",
      "carbonPerUnit": 12,
      "tags": ["脂肪", "低碳日"],
      "note": "主要提供健康脂肪"
    },
    {
      "id": "egg_001",
      "name": "全蛋",
      "alias": ["鸡蛋"],
      "unit": "个",
      "carbonPerUnit": 0.6,
      "tags": ["蛋白", "脂肪", "全天候"],
      "note": "低碳日主要蛋白来源"
    },
    {
      "id": "whey_001",
      "name": "WHEY蛋白粉",
      "alias": ["蛋白粉", "Foryes粉"],
      "unit": "份 (30g)",
      "carbonPerUnit": 3,
      "proteinPerUnit": 24,
      "tags": ["蛋白", "练后"],
      "note": "1份约等于1勺"
    },
    {
      "id": "chicken_001",
      "name": "鸡胸肉",
      "alias": ["瘦肉", "熟肉"],
      "unit": "g (熟重)",
      "proteinPer100g": 31,
      "tags": ["蛋白", "主力"],
      "note": "每餐建议150g熟肉"
    },
    {
      "id": "nuts_001",
      "name": "混合坚果",
      "alias": ["坚果"],
      "unit": "g",
      "fatPer10g": 5,
      "tags": ["脂肪", "低碳日"],
      "note": "控制量，20-30g足够"
    }
  ],
  "conversionTable": {
    "description": "10g 碳水等值换算",
    "items": [
      { "food": "燕麦", "amount": "16g (干重)" },
      { "food": "意面", "amount": "13g (干重)" },
      { "food": "杂粮馒头", "amount": "0.5个" },
      { "food": "蓝莓", "amount": "72g" },
      { "food": "红薯", "amount": "50g" },
      { "food": "玉米", "amount": "45g" }
    ]
  }
}

path: knowledge_base/logic_rules.md
content: # BioContext-Kernel 核心逻辑规则

> 本文件定义了 YEST1N 碳循环饮食的核心逻辑，AI 必须严格遵守。

---

## 🔢 碳水误差控制

### 核心原则

- **误差容忍度**: 10g 以内为安全范围
- **超标警示**: 超过 20g 需要记录原因

### 计算公式

```
实际碳水摄入 = 已记录食物碳水总和
碳水误差 = 实际碳水 - 目标碳水
```

---

## 🌡️ 血糖保护协议

### 进食顺序 (必须严格遵守)

1. **蔬菜** → 2. **蛋白质** → 3. **碳水**

### 碳水要求

- 碳水必须是**冷藏过的** (如冷红薯、冷意面)
- 禁止即时升糖的白米、白面

---

## 📅 档位切换逻辑

### 周间档位

| 周一 | 周二 | 周三 | 周四 | 周五 | 周六 | 周日 |
|------|------|------|------|------|------|------|
| LC 低 | MC 中 | HC 高 | MC 中 | MC 中 | HC 高 | LC 低 |

### 特殊情况

- **假期模式**: 自动切换至 LC
- **连练周六**: HC (高碳 + 大量)
- **休息周日**: LC (深度清空)

---

## 🏋️ 训练日匹配

| 档位 | 训练类型 | 碳水用途 |
|------|----------|----------|
| HC 高碳 | 腿部/核心大肌群 | 糖原填充 |
| MC 中碳 | 胸/背/二三头 | 稳定输出 |
| LC 低碳 | 休息/恢复日 | 脂肪供能 |

---

## 📊 睡眠窗口

### 目标

- **关机时间**: 23:00
- **起床时间**: 06:00

### 规则

- 睡前 2 小时禁止碳水
- 蛋白粉可睡前服用 (不加碳水)

---

## 🍚 食物存放规范

### 主食冷藏

- 煮熟后立即放入冰箱
- **冷藏 12 小时以上**才能食用
- 目的：产生抗性淀粉，降低升糖指数

### 蛋白质存放

- 鸡胸肉/瘦肉：150g 一份分装
- 建议冷冻保存，一周内吃完

---

## ⚠️ AI 执行检查清单

当用户询问饮食问题时，必须：

1. ✅ 读取 `profile.json` 获取当前体重和目标
2. ✅ 读取 `food_registry.json` 检索食物碳水
3. ✅ 根据 `schedule` 判断今日档位
4. ✅ 计算碳水误差，给出明确建议
5. ✅ 如有不明食物，提示用户"Commit"新食物

---

## 🔄 Commit 指令格式

用户可通过自然语言添加新食物：

```
"把[食物名]存入注册表，单位[个/g]，每个[数字]g碳水，标记为[标签]"
```

AI 自动更新 `food_registry.json`

---

*最后更新: 2026-04-06 | YEST1N Protocol v8.0*

path: knowledge_base/recipes.json
content: {
  "version": "1.0",
  "lastUpdated": "2026-04-06",
  "recipes": [
    {
      "id": "recipe_001",
      "name": "燕麦蛋白启动",
      "type": "早餐",
      "suitableFor": ["medium", "high"],
      "carbon": 40,
      "protein": 40,
      "steps": [
        "65g 干燕麦沸水冲泡",
        "加入 1.5 份蛋白粉",
        "加入 50g 蓝莓"
      ]
    },
    {
      "id": "recipe_002",
      "name": "馒头午餐",
      "type": "午餐",
      "suitableFor": ["medium"],
      "carbon": 37,
      "protein": 45,
      "steps": [
        "2个杂粮馒头",
        "150g 熟肉",
        "大份蔬菜"
      ]
    },
    {
      "id": "recipe_003",
      "name": "意面预充能",
      "type": "晚餐",
      "suitableFor": ["high", "medium"],
      "carbon": 65,
      "protein": 45,
      "steps": [
        "65g 干意面煮熟",
        "150g 熟肉",
        "100g 蓝莓"
      ]
    },
    {
      "id": "recipe_004",
      "name": "练后修复",
      "type": "PWO",
      "suitableFor": ["all"],
      "carbon": 20,
      "protein": 40,
      "steps": [
        "1.5份蛋白粉",
        "50g 蓝莓 (仅高碳日)",
        "零脂肪"
      ]
    },
    {
      "id": "recipe_005",
      "name": "低碳开启",
      "type": "早餐",
      "suitableFor": ["low"],
      "carbon": 10,
      "protein": 40,
      "steps": [
        "2全蛋",
        "1份蛋白粉",
        "100g 蓝莓",
        "20g 坚果"
      ]
    },
    {
      "id": "recipe_006",
      "name": "低碳正餐",
      "type": "午餐/晚餐",
      "suitableFor": ["low"],
      "carbon": 5,
      "protein": 50,
      "steps": [
        "180g 熟肉",
        "1个牛油果",
        "大量蔬菜"
      ]
    }
  ]
}

path: knowledge_base/rules.md
content: # 凯圣王碳循环算法 | YEST1N 优化版 v8.5

> 核心原理：通过周期性地改变碳水化合物摄入量，欺骗身体代谢，在不降低基础代谢的前提下，强制开启脂肪供能。

---

## 🎯 适用人群

- 大体量（90kg级）
- 高强度力量训练
- 对血糖波动敏感
- 追求精准减脂

---

## ⚠️ 核心约束

| 约束 | 说明 |
|------|------|
| **10g 误差线** | 每日碳水偏离度控制在 ±10g 以内 |
| **蛋白质恒定** | 全天 135g ~ 150g (1.5~1.7g/kg) |
| **全周碳水池** | 1260g (体重 × 2g × 7天) |

---

## 📊 档位配置

| 档位 | 碳水 (C) | 蛋白 (P) | 脂肪 (F) | 适用场景 |
|------|----------|----------|----------|----------|
| **高碳 HC** | 315g | 135g | <40g | 练腿日 / 爆发性训练 |
| **中碳 MC** | 147g | 135g | ~60g | 胸、背训练日 |
| **低碳 LC** | 95g | 135g | >120g | 休息日 / 有氧日 |

---

## 🍚 食物换算存档 (Knowledge Base)

### 主食单位（锁死10g误差）

| 食物 | 碳水含量 | 备注 |
|------|----------|------|
| **杂粮小馒头** | 每个 ≈ 18.5g | 中碳午餐吃2个 |
| **五黑燕麦** | 100g = 61.6g (干重) | 需称量 |
| **蓝莓** | 100g ≈ 14g | 全天候安全水果 |
| **意面** | 100g (干重) ≈ 75g | 必须冷藏过夜 |

---

## 🔒 三大执行协议

### 【11点关机协议】
- 21:00 后的练后餐必须零脂肪
- 严禁蛋黄、坚果、植物油
- 确保深度睡眠质量

### 【进食序列协议】
1. 先吃大量蔬菜
2. 再吃肉（蛋白质）
3. 最后吃主食（馒头/意面）
- 目的：利用物理拦截降低血糖峰值

### 【混合蛋白补丁】
- 早餐推荐"蛋白粉 + 3个纯蛋清"组合
- 兼顾吸收速度与饱腹感

---

## 📅 周间档位排布

| 周一 | 周二 | 周三 | 周四 | 周五 | 周六 | 周日 |
|------|------|------|------|------|------|------|
| LC | MC | HC | MC | MC | HC | LC |

---

## 🧮 计算公式

```
全周碳水池 = 体重 × 2g × 7天 = 90 × 2 × 7 = 1260g

高碳日 (2天): 1260g × 50% ÷ 2 = 315g
中碳日 (3天): 1260g × 35% ÷ 3 = 147g  
低碳日 (2天): 1260g × 15% ÷ 2 = 95g
```

---

## 🤖 AI 调用示例

```
问：今天能吃几个馒头？
答：
- 馒头：1个 = 18.5g 碳水
- 今天是 MC 日，预算 147g
- 已吃：65g燕麦 + 50g蓝莓 = 40g
- 剩余：147 - 40 = 107g
- 可以吃：107 ÷ 18.5 = 5.7个
```

---

*最后更新: 2026-04-06 | YEST1N Protocol v8.5*

path: logs/2026-04-06.md
content: # 2026-04-06 Daily Log

## 📅 日期信息
- **日期**: 2026-04-06
- **星期**: 周一
- **档位**: LC (低碳日)

## 🍽️ 饮食记录

### Meal 1 - 09:00
- [x] 2全蛋
- [x] 1份蛋白粉
- [x] 100g 蓝莓
- [x] 20g 坚果
- **碳水**: ~25g
- **状态**: ✅ 完成

### Meal 2 - 13:00
- [x] 180g 熟肉
- [x] 1个牛油果
- [x] 大份蔬菜
- **碳水**: ~15g
- **状态**: ✅ 完成

### Meal 3 - 18:30
- [x] 180g 熟肉
- [x] 30g 坚果
- [x] 大份蔬菜
- **碳水**: ~10g
- **状态**: ✅ 完成

### 睡前 - 21:30
- [x] 1.5份蛋白粉
- **碳水**: 0g
- **状态**: ✅ 完成

## 🏋️ 训练记录
- **训练**: 休息日
- **状态**: 无

## 💤 睡眠
- **关机时间**: 23:15
- **状态**: ✅ 达成

## 📊 总结
| 项目 | 目标 | 实际 | 状态 |
|------|------|------|------|
| 碳水 | 95g | ~50g | ✅ |
| 蛋白 | 135g | ~150g | ✅ |
| 脂肪 | 126g | ~120g | ✅ |
| 睡眠 | 23:00 | 23:15 | 🟡 |

## 📝 Notes
- 全天低碳运行稳定
- 坚果量稍多，下次注意控制在20g

path: package.json
content: {
  "name": "fitdietkernel",
  "version": "1.0.0",
  "description": "健身饮食的个人知识库 - 让AI精准帮你算饮食",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\""
  },
  "keywords": ["diet", "fitness", "carbon-cycling", "macro", "openclaw", "ai"],
  "author": "YEST1N",
  "license": "MIT"
}

path: profile.json
content: {
  "name": "YEST1N",
  "bio": "健身爱好者",
  "height": 180,
  "currentWeight": 89.2,
  "targetWeight": 85,
  "targetDate": "2026-12-31",
  "age": 30,
  "gender": "male",
  "activityLevel": "moderate",
  "dietType": "carbon_cycling",
  
  "metabolism": {
    "bmr": 1850,
    "tdee": 2800,
    "calculationMethod": "mifflin-st-jeor"
  },
  
  "schedule": {
    "monday": "low",
    "tuesday": "medium",
    "wednesday": "high",
    "thursday": "medium",
    "friday": "medium",
    "saturday": "high",
    "sunday": "low"
  },
  
  "macroCalculator": {
    "protein": {
      "multiplier": 1.5,
      "unit": "g/kg",
      "note": "增肌1.5~2g/kg，减脂2~2.5g/kg"
    },
    "fat": {
      "calculation": "remainder",
      "note": "剩余热量给脂肪"
    },
    "carbon": {
      "low": 1.0,
      "medium": 1.5,
      "high": 3.0,
      "unit": "g/kg",
      "note": "按体重倍数"
    }
  },
  
  "sleep": {
    "window": "23:00 - 06:00",
    "target": "23:00",
    "average": "23:30"
  },
  
  "lastUpdated": "2026-04-06"
}

path: scripts/report_gen.py
content: #!/usr/bin/env python3
"""
BioContext-Kernel Report Generator
自动将日志转换为结构化周报
"""

import json
import os
from datetime import datetime, timedelta
from pathlib import Path


class ReportGenerator:
    def __init__(self, base_path="."):
        self.base_path = Path(base_path)
        self.logs_path = self.base_path / "logs"

    def get_recent_logs(self, days=7):
        """获取最近N天的日志"""
        logs = []
        for i in range(days):
            date = datetime.now() - timedelta(days=i)
            log_file = self.logs_path / f"{date.strftime('%Y-%m-%d')}.md"
            if log_file.exists():
                logs.append(self._parse_log(log_file))
        return logs

    def _parse_log(self, log_file):
        """解析单日日志"""
        with open(log_file, "r", encoding="utf-8") as f:
            content = f.read()

        data = {
            "date": log_file.stem,
            "content": content,
            "meals": [],
            "carbon_actual": 0,
            "sleep_time": None,
        }

        # 简单解析 - 提取碳水数值
        import re

        carbon_matches = re.findall(r"碳水.*?(\d+)g", content)
        if carbon_matches:
            data["carbon_actual"] = sum(int(c) for c in carbon_matches)

        # 提取睡眠时间
        sleep_match = re.search(r"关机时间.*?(\d+:\d+)", content)
        if sleep_match:
            data["sleep_time"] = sleep_match.group(1)

        return data

    def generate_weekly_report(self):
        """生成周报"""
        logs = self.get_recent_logs(7)

        if not logs:
            return "暂无日志数据"

        # 加载 profile 获取目标
        profile_path = self.base_path / "profile.json"
        target_carbon = 147  # 默认MC

        if profile_path.exists():
            with open(profile_path, "r", encoding="utf-8") as f:
                profile = json.load(f)
                target_carbon = (
                    profile.get("carbonCycle", {}).get("medium", {}).get("c", 147)
                )

        # 计算统计数据
        total_carbon = sum(log["carbon_actual"] for log in logs)
        avg_carbon = total_carbon / len(logs) if logs else 0
        carbon_error = avg_carbon - target_carbon

        # 生成报告
        report = f"""# 📊 周报 - {datetime.now().strftime("%Y年%W周")}

## 📈 核心数据

| 维度 | 本周表现 | 状态 |
|------|----------|------|
| 平均碳水 | {avg_carbon:.1f}g | {"🟢" if abs(carbon_error) < 10 else "🟡"} |
| 目标碳水 | {target_carbon}g | - |
| 误差 | {carbon_error:+.1f}g | {"🟢 安全" if abs(carbon_error) < 10 else "🟡 需优化"} |
| 记录天数 | {len(logs)}天 | - |

## 📅 每日详情

"""
        for log in logs:
            status = "✅" if log["carbon_actual"] <= target_carbon + 20 else "⚠️"
            report += f"- {log['date']}: {log['carbon_actual']}g碳水 {status}\n"

        report += f"""
## 💡 建议

{"碳水控制良好，继续保持" if abs(carbon_error) < 10 else "碳水摄入偏高，建议增加低碳日比例"}

---
*由 BioContext-Kernel 自动生成 | {datetime.now().strftime("%Y-%m-%d %H:%M")}*
"""

        return report

    def save_report(self, output_path=None):
        """保存报告"""
        report = self.generate_weekly_report()

        if output_path is None:
            output_path = (
                self.logs_path
                / "weekly_report"
                / f"report_{datetime.now().strftime('%Y-%m-%d')}.md"
            )
        else:
            output_path = Path(output_path)

        output_path.parent.mkdir(parents=True, exist_ok=True)

        with open(output_path, "w", encoding="utf-8") as f:
            f.write(report)

        print(f"✅ 报告已生成: {output_path}")
        return output_path


if __name__ == "__main__":
    import sys

    path = sys.argv[1] if len(sys.argv) > 1 else "."
    gen = ReportGenerator(path)
    gen.save_report()


path: setup.py
content: from setuptools import setup
import py2app

setup(
    app=["desktop-app.py"],
    name="FitDietKernel",
    version="1.0.0",
    description="健身饮食桌面应用",
    app_category="public.app-category.healthcare-fitness",
)


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