Spaces:
Runtime error
Runtime error
J.B-Lin commited on
Commit ·
33aa89f
1
Parent(s): 9046d8e
docs: 添加完整接口说明文档,包含架构图、模块接口表、数据schema、并行协作规范
Browse files
README.md
CHANGED
|
@@ -12,7 +12,568 @@ license: mit
|
|
| 12 |
short_description: Voice-based Pregnant Meal & Nutrition Tracker
|
| 13 |
---
|
| 14 |
|
| 15 |
-
|
| 16 |
|
|
|
|
|
|
|
| 17 |
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
short_description: Voice-based Pregnant Meal & Nutrition Tracker
|
| 13 |
---
|
| 14 |
|
| 15 |
+
# PregoPal — 孕期陪护 AI 助手
|
| 16 |
|
| 17 |
+
> **并行 Cline 协作接口文档**
|
| 18 |
+
> 每个 Cline 在修改模块前,先 `git pull --rebase`;修改完成后立即 `git commit && git push`。
|
| 19 |
|
| 20 |
+
---
|
| 21 |
+
|
| 22 |
+
## 1. 项目概述
|
| 23 |
+
|
| 24 |
+
PregoPal 是一款面向孕期家庭的 AI 陪护工具,支持:
|
| 25 |
+
|
| 26 |
+
| 功能 | 状态 | 负责模块 |
|
| 27 |
+
|------|------|----------|
|
| 28 |
+
| 🎤 声纹识别与家庭成员区分 | 基线可用 | `modules/voiceprint.py` |
|
| 29 |
+
| 🍽️ 今日菜品推荐(营养+家庭能力) | 基线可用 | `modules/meal_recommender.py` |
|
| 30 |
+
| 📝 饮食记录储存(JSON + Markdown) | 已实现 | `modules/diet_logger.py` + `modules/diet_extractor.py` |
|
| 31 |
+
| 📊 营养分析与可视化报告 | 基线可用 | `modules/nutrition_analyzer.py` + `modules/nutrition_standards.py` |
|
| 32 |
+
|
| 33 |
+
**技术栈**: Python 3.13 · Gradio 6.16 · MiniCPM-o 4.5 · Matplotlib · Pandas
|
| 34 |
+
|
| 35 |
+
---
|
| 36 |
+
|
| 37 |
+
## 2. 架构总览
|
| 38 |
+
|
| 39 |
+
```
|
| 40 |
+
app.py ← Gradio 薄入口
|
| 41 |
+
├── ui/app_builder.py ← 前端 Tab 布局(饮食记录/营养分析/家庭管理/声纹/菜品推荐/环境配置)
|
| 42 |
+
├── loop.py ← 每日自动分析循环(状态机)
|
| 43 |
+
│ ├── plugins/base.py ← 插件基类(LoopPlugin, PluginRegistry, LoopContext)
|
| 44 |
+
│ ├── plugins/family_quiz.py ← 家庭问卷插件(菜谱/体重检查)
|
| 45 |
+
│ ├── plugins/diet_summary.py ← 昨日饮食总结
|
| 46 |
+
│ ├── plugins/weight_check.py ← 体重检查插件
|
| 47 |
+
│ ├── plugins/family_memory.py← 家庭记忆处理
|
| 48 |
+
│ ├── plugins/dri_analysis.py ← DRIs 营养对比分析
|
| 49 |
+
│ ├── plugins/briefing_generator.py ← 今日简报生成
|
| 50 |
+
│ ├── plugins/three_day_summary.py ← 每三天综合总结
|
| 51 |
+
│ └── plugins/preset_writer.py ← 预设/缓存写入
|
| 52 |
+
├── modules/ ← 核心业务逻辑(纯函数/无状态)
|
| 53 |
+
│ ├── voiceprint.py ← 声纹识别
|
| 54 |
+
│ ├── meal_recommender.py ← 菜品推荐
|
| 55 |
+
│ ├── diet_extractor.py ← AI 回复数据提取
|
| 56 |
+
│ ├── diet_logger.py ← 饮食记录存储
|
| 57 |
+
│ ├── family_manager.py ← 家庭信息管理
|
| 58 |
+
│ ├── nutrition_standards.py ← 中国官方营养标准
|
| 59 |
+
│ ├── nutrition_analyzer.py ← 营养分析与可视化
|
| 60 |
+
│ └── core/ ← 核心能力层
|
| 61 |
+
│ ├── model_loader.py ← MiniCPM-o 模型加载
|
| 62 |
+
│ ├── voice_processor.py ← 语音处理
|
| 63 |
+
│ ├── vision_processor.py ← 视觉处理
|
| 64 |
+
│ └── conversation_manager.py ← 对话管理
|
| 65 |
+
├── config.py ← 全局配置(路径/常量/数据模板)
|
| 66 |
+
├── utils.py ← 工具函数(中文字体设置等)
|
| 67 |
+
└── data/ ← 持久化存储
|
| 68 |
+
├── diet_logs.json ← 结构化饮食记录 JSON
|
| 69 |
+
├── nutrition_db.json ← 营养数据库 JSON
|
| 70 |
+
├── family.json ← 家庭成员声纹 JSON
|
| 71 |
+
├── family/ ← 家庭信息 Markdown(recipes/preferences/memory)
|
| 72 |
+
├── logs/ ← 每日饮食日志 Markdown
|
| 73 |
+
├── presets/ ← 预设/缓存 + .daily_status.json
|
| 74 |
+
├── reports/ ← 营养报告 Markdown
|
| 75 |
+
├── voices/ ← 声纹音频文件
|
| 76 |
+
└── nutrition/ ← 营养标准原始文档
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
---
|
| 80 |
+
|
| 81 |
+
## 3. 核心模块接口说明
|
| 82 |
+
|
| 83 |
+
> **约定**:模块间通过函数调用传递数据。所有返回 dict 的接口,其 key 约定在下方列出。
|
| 84 |
+
> **修改清单**:改任何模块的输入/输出签名时,必须同步更新本 README 对应条目。
|
| 85 |
+
|
| 86 |
+
### 3.1 声纹识别 — `modules/voiceprint.py`
|
| 87 |
+
|
| 88 |
+
类:`VoiceprintManager`
|
| 89 |
+
|
| 90 |
+
| 方法 | 输入 | 输出 | 说明 |
|
| 91 |
+
|------|------|------|------|
|
| 92 |
+
| `register_member(name, relation, audio_path)` | `name: str`, `relation: str`, `audio_path: str` (Path) | `(member_info: dict\|None, msg: str)` | 注册新成员声纹,返回 `{"id","name","relation","registered_at","audio_path","features"}` |
|
| 93 |
+
| `identify_speaker(audio_path)` | `audio_path: str` (Path) | `(member_info: dict\|None, msg: str)` | 识别说话人,需声纹库非空 |
|
| 94 |
+
| `get_members_list()` | — | `str` (格式化文本) | 获取已注册成员列表 |
|
| 95 |
+
| `delete_member(member_id)` | `member_id: str` | `str` (结果消息) | 删除指定成员 |
|
| 96 |
+
|
| 97 |
+
**依赖**:
|
| 98 |
+
- `VOICE_DIR`(`data/voices/`)从 `config.py` 导入
|
| 99 |
+
- `FAMILY_FILE`(`data/family.json`)— JSON 格式 `{"members": [...], "voiceprints": {...}}`
|
| 100 |
+
- `config.VOICEPRINT_SIMILARITY_THRESHOLD`(默认 0.7)
|
| 101 |
+
|
| 102 |
+
**内部数据结构**(`data/family.json`):
|
| 103 |
+
```json
|
| 104 |
+
{
|
| 105 |
+
"members": [
|
| 106 |
+
{
|
| 107 |
+
"id": "abc12345",
|
| 108 |
+
"name": "小红",
|
| 109 |
+
"relation": "孕妇",
|
| 110 |
+
"registered_at": "2026-06-09T07:00:00",
|
| 111 |
+
"audio_path": "data/voices/abc12345.wav",
|
| 112 |
+
"features": {"mean": 0.01, "std": 0.05, "max": 0.5, "min": -0.5, "zero_crossing_rate": 0.3, "energy": 0.001, "duration": 3.5}
|
| 113 |
+
}
|
| 114 |
+
],
|
| 115 |
+
"voiceprints": {
|
| 116 |
+
"abc12345": {"mean": 0.01, ...}
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
> ⚠️ **风险等级:中** — 当前使用频谱统计特征(baseline),后续升级 Whisper encoder 需保持 `register_member`/`identify_speaker` 签名不变。
|
| 122 |
+
|
| 123 |
+
---
|
| 124 |
+
|
| 125 |
+
### 3.2 菜品推荐 — `modules/meal_recommender.py`
|
| 126 |
+
|
| 127 |
+
类:`MealRecommender`
|
| 128 |
+
|
| 129 |
+
| 方法 | 输入 | 输出 | 说明 |
|
| 130 |
+
|------|------|------|------|
|
| 131 |
+
| `get_recommendation(preference, trimester, restrictions)` | `preference: str=""`, `trimester: str="孕中期"`, `restrictions: str=""` | `dict` | 返回今日推荐食谱 |
|
| 132 |
+
| `format_meal_plan(recommendation)` | `recommendation: dict`(上一个方法的返回值) | `str` | 格式化为可读文本 |
|
| 133 |
+
|
| 134 |
+
**输出 dict schema**(`get_recommendation` 返回):
|
| 135 |
+
```json
|
| 136 |
+
{
|
| 137 |
+
"date": "2026-06-09",
|
| 138 |
+
"trimester": "孕中期",
|
| 139 |
+
"preference": "想吃清淡的",
|
| 140 |
+
"focus": "补充蛋白质、钙、铁",
|
| 141 |
+
"meals": {
|
| 142 |
+
"早餐": "小米粥+包子+煮鸡蛋",
|
| 143 |
+
"午餐": "番茄牛腩+杂粮饭+凉拌黄瓜",
|
| 144 |
+
"晚餐": "蒸蛋羹+小米粥+炒青菜",
|
| 145 |
+
"加餐": "酸奶+坚果"
|
| 146 |
+
},
|
| 147 |
+
"tips": ["🌿 孕中期建议:...", "💡 建议每天饮水..."]
|
| 148 |
+
}
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
**依赖**:
|
| 152 |
+
- `config.MEAL_TEMPLATES`(4 餐次 × 4 选项的食谱模板 dict)
|
| 153 |
+
- `config.TRIMESTER_ADJUSTMENTS`(各孕期阶段的 focus/avoid 建议)
|
| 154 |
+
- `config.TRIMESTER_TIPS`(各孕期阶段的饮食提示字符串)
|
| 155 |
+
|
| 156 |
+
> ⚠️ **风险等级:中** — 当前为随机模板推荐。后续对接 AI 对话推荐时需保持 `get_recommendation` 签名,内部逻辑可任意替换。
|
| 157 |
+
|
| 158 |
+
---
|
| 159 |
+
|
| 160 |
+
### 3.3 AI 对话数据提取 — `modules/diet_extractor.py`
|
| 161 |
+
|
| 162 |
+
类:`DietExtractor`(全静态方法)
|
| 163 |
+
|
| 164 |
+
| 方法 | 输入 | 输出 | 说明 |
|
| 165 |
+
|------|------|------|------|
|
| 166 |
+
| `extract_all(text)` | `text: str` (AI 回复全文) | `dict` | 正则提取所有结构化数据 |
|
| 167 |
+
| `fallback_extract_diet(text)` | `text: str` | `dict\|None` | 关键词 fallback 提取饮食 |
|
| 168 |
+
| `fallback_extract_thinking(text)` | `text: str` | `dict\|None` | 关键词 fallback 提取思考 |
|
| 169 |
+
| `robust_extract(text)` | `text: str` | `dict` | 正则优先 → fallback 兜底 |
|
| 170 |
+
|
| 171 |
+
**`extract_all` 返回 dict schema**:
|
| 172 |
+
```json
|
| 173 |
+
{
|
| 174 |
+
"diets": [
|
| 175 |
+
{
|
| 176 |
+
"meals": {"早餐": "全麦面包+鸡蛋+牛奶", "午餐": "清蒸鱼", "晚餐": "", "加餐": ""},
|
| 177 |
+
"日期": "2026-06-09",
|
| 178 |
+
"记录人": "孕妇",
|
| 179 |
+
"备注": "孕妇吃了"
|
| 180 |
+
}
|
| 181 |
+
],
|
| 182 |
+
"recipes": [{"菜名": "清蒸鱼", "制作人": "丈夫", "难度": "简单", "食材": "鱼、姜", "备注": ""}],
|
| 183 |
+
"preferences": [{"人员": "孕妇", "类型": "偏好", "内容": "爱吃酸"}],
|
| 184 |
+
"weights": [{"日期": "2026-06-09", "体重": "65", "记录人": "孕妇自己"}],
|
| 185 |
+
"memories": [{"类型": "事件", "内容": "婆婆今天来家里"}],
|
| 186 |
+
"thinking": {"当前步骤": "记录饮食", "下一步": "分析营养"} // or None
|
| 187 |
+
}
|
| 188 |
+
```
|
| 189 |
+
|
| 190 |
+
**Markdown 提取标记格式**(AI 回复中需含):
|
| 191 |
+
```
|
| 192 |
+
[EXTRACT_DIET]...[/EXTRACT_DIET]
|
| 193 |
+
[EXTRACT_RECIPE]...[/EXTRACT_RECIPE]
|
| 194 |
+
[EXTRACT_PREFERENCE]...[/EXTRACT_PREFERENCE]
|
| 195 |
+
[EXTRACT_WEIGHT]...[/EXTRACT_WEIGHT]
|
| 196 |
+
[EXTRACT_MEMORY]...[/EXTRACT_MEMORY]
|
| 197 |
+
[THINKING]...[/THINKING]
|
| 198 |
+
```
|
| 199 |
+
|
| 200 |
+
**辅助函数**:
|
| 201 |
+
- `get_extract_prompt(date_str=None) -> str` — 返回含日期占位符的 System Prompt 模板
|
| 202 |
+
|
| 203 |
+
> ✅ **风险等级:低** — 接口稳定,已存在完整测试(`tests/test_diet_extractor.py`)。
|
| 204 |
+
|
| 205 |
+
---
|
| 206 |
+
|
| 207 |
+
### 3.4 饮食记录存储 — `modules/diet_logger.py`
|
| 208 |
+
|
| 209 |
+
类:`DietLogger`
|
| 210 |
+
|
| 211 |
+
| 方法 | 输入 | 输出 | 说明 |
|
| 212 |
+
|------|------|------|------|
|
| 213 |
+
| `add_record(member_name, member_relation, date, meals, mood, notes)` | `member_name: str`, `member_relation: str`, `date: str (ISO)`, `meals: dict`, `mood: str=""`, `notes: str=""` | `(record: dict, md_path: Path)` | 添加记录 → JSON + MD 双写 |
|
| 214 |
+
| `get_recent_records(days=7)` | `days: int` | `list[dict]` | 获取近 N 天记录 |
|
| 215 |
+
| `get_all_markdown_files()` | — | `list[Path]` | 所有 MD 日志文件 |
|
| 216 |
+
| `parse_diet_record(text) — static` | `text: str` | `dict\|None` | [DIET_RECORD] 标记解析(后续 AI 版本用) |
|
| 217 |
+
|
| 218 |
+
**`add_record` 返回的 record dict**:
|
| 219 |
+
```json
|
| 220 |
+
{
|
| 221 |
+
"id": "a1b2c3d4",
|
| 222 |
+
"member_name": "小红",
|
| 223 |
+
"member_relation": "孕妇",
|
| 224 |
+
"date": "2026-06-09",
|
| 225 |
+
"meals": {"早餐": "燕麦粥+坚果", "午餐": "清蒸鱼+米饭"},
|
| 226 |
+
"mood": "挺好",
|
| 227 |
+
"notes": "今天胃口不错",
|
| 228 |
+
"extensions": {},
|
| 229 |
+
"created_at": "2026-06-09T12:00:00"
|
| 230 |
+
}
|
| 231 |
+
```
|
| 232 |
+
|
| 233 |
+
**依赖**:
|
| 234 |
+
- `config.DIET_LOG_FILE`(`data/diet_logs.json`)— JSON 格式
|
| 235 |
+
- `config.LOGS_DIR`(`data/logs/`)— Markdown 日志目录
|
| 236 |
+
- `config.DIET_LOG_SCHEMA_VERSION`(当前 "1.0")
|
| 237 |
+
|
| 238 |
+
**Markdown 日志文��格式**(`data/logs/饮食日志_YYYY-MM-DD.md`):
|
| 239 |
+
```markdown
|
| 240 |
+
# 🥗 孕期饮食日志
|
| 241 |
+
|
| 242 |
+
## 📋 基本信息
|
| 243 |
+
- **日期**: 2026-06-09
|
| 244 |
+
- **记录人**: 孕妇 - 小红
|
| 245 |
+
- **记录时间**: 2026-06-09T12:00:00
|
| 246 |
+
|
| 247 |
+
## 🍽️ 今日饮食记录
|
| 248 |
+
|
| 249 |
+
### 早餐
|
| 250 |
+
- 燕麦粥+坚果
|
| 251 |
+
|
| 252 |
+
### 午餐
|
| 253 |
+
- 清蒸鱼+米饭
|
| 254 |
+
|
| 255 |
+
---
|
| 256 |
+
*由 PregoPal 自动生成*
|
| 257 |
+
```
|
| 258 |
+
|
| 259 |
+
> ✅ **风险等级:低** — schema 已加版本号,`extensions: {}` 字段可向后兼容扩展。
|
| 260 |
+
|
| 261 |
+
---
|
| 262 |
+
|
| 263 |
+
### 3.5 家庭信息管理 — `modules/family_manager.py`
|
| 264 |
+
|
| 265 |
+
三个管理器类,全部使用 `@classmethod`(无需实例化):
|
| 266 |
+
|
| 267 |
+
#### 3.5.1 RecipeManager — 家庭菜谱
|
| 268 |
+
| 方法 | 输入 | 输出 | 说明 |
|
| 269 |
+
|------|------|------|------|
|
| 270 |
+
| `load_all()` | — | `list[dict]` | 读取所有菜谱 |
|
| 271 |
+
| `add_recipe(name, cook, difficulty, ingredients, notes)` | 五个 `str` 参数 | `str` (结果消息) | 添加菜谱 |
|
| 272 |
+
| `get_names()` | — | `list[str]` | 所有菜名 |
|
| 273 |
+
| `format_for_prompt()` | — | `str` | System Prompt 格式 |
|
| 274 |
+
|
| 275 |
+
菜谱 dict: `{"name", "cook", "difficulty", "ingredients", "notes"}`
|
| 276 |
+
|
| 277 |
+
#### 3.5.2 PreferenceManager — 饮食偏好
|
| 278 |
+
| 方法 | 输入 | 输出 | 说明 |
|
| 279 |
+
|------|------|------|------|
|
| 280 |
+
| `load_all()` | — | `list[dict]` | 所有成员偏好 |
|
| 281 |
+
| `add_member(name, role, preferences, avoid, allergies, notes)` | 六个 `str` 参数 | `str` (结果消息) | 添加/更新(覆盖同名) |
|
| 282 |
+
| `format_for_prompt()` | — | `str` | System Prompt 格式 |
|
| 283 |
+
|
| 284 |
+
偏好 dict: `{"name", "role", "preferences", "avoid", "allergies", "notes"}`
|
| 285 |
+
|
| 286 |
+
#### 3.5.3 MemoryManager — 家庭记忆
|
| 287 |
+
| 方法 | 输入 | 输出 | 说明 |
|
| 288 |
+
|------|------|------|------|
|
| 289 |
+
| `load_all()` | — | `dict` (relationships/events/daily) | 所有记忆 |
|
| 290 |
+
| `add_event(description)` | `str` | `str` (结果消息) | 添加重要事件 |
|
| 291 |
+
| `add_daily(content)` | `str` | `str` (结果消息) | 添加日常记录 |
|
| 292 |
+
| `format_for_prompt()` | — | `str` | System Prompt 格式 |
|
| 293 |
+
|
| 294 |
+
**顶层统一接口**:
|
| 295 |
+
- `load_all_family_info() -> dict` — 一次性加载所有家庭信息
|
| 296 |
+
- `format_all_for_prompt() -> str` — 全量 System Prompt 文本
|
| 297 |
+
|
| 298 |
+
**数据文件**(`data/family/`):
|
| 299 |
+
- `recipes.md` — Markdown 格式表
|
| 300 |
+
- `preferences.md` — Markdown 格式表
|
| 301 |
+
- `memory.md` — Markdown 格式表
|
| 302 |
+
|
| 303 |
+
> ✅ **风险等级:低** — 接口稳定,有完整测试(`tests/test_family_manager.py`)。更新 `add_member` 覆盖逻辑时注意保留已有数据。
|
| 304 |
+
|
| 305 |
+
---
|
| 306 |
+
|
| 307 |
+
### 3.6 营养标准 — `modules/nutrition_standards.py`
|
| 308 |
+
|
| 309 |
+
类:`BMIStandards`, `DietaryGuideStandards`, `DRIsParser`(全部只读数据+静态方法)
|
| 310 |
+
|
| 311 |
+
| 类 | 关键方法 | 说明 |
|
| 312 |
+
|----|---------|------|
|
| 313 |
+
| `BMIStandards` | `get_bmi_range(pre_preg_bmi) → dict`, `get_recommended_gain(pre_preg_bmi) → dict`, `calculate_bmi(weight_kg, height_m) → float` | 孕前 BMI 标准(中国标准) |
|
| 314 |
+
| `DietaryGuideStandards` | `get_daily_guideline(trimester) → dict`, `get_food_groups_info() → dict` | 膳食指南推荐 |
|
| 315 |
+
| `DRIsParser` | `get_dri_for_trimester(trimester) → dict`, `get_all_dris() → dict` | DRIs 2023 数据 |
|
| 316 |
+
|
| 317 |
+
**DRIsParser.get_dri_for_trimester 返回示例**:
|
| 318 |
+
```json
|
| 319 |
+
{
|
| 320 |
+
"蛋白质": {"value": 70, "unit": "g", "note": "孕中期+15g"},
|
| 321 |
+
"钙": {"value": 1000, "unit": "mg"},
|
| 322 |
+
"铁": {"value": 27, "unit": "mg"},
|
| 323 |
+
"叶酸": {"value": 600, "unit": "mcg"},
|
| 324 |
+
...
|
| 325 |
+
}
|
| 326 |
+
```
|
| 327 |
+
|
| 328 |
+
> ✅ **风险等级:低** — 只读数据类,有完整测试(`tests/test_nutrition_standards.py`)。
|
| 329 |
+
|
| 330 |
+
---
|
| 331 |
+
|
| 332 |
+
### 3.7 营养分析与可视化 — `modules/nutrition_analyzer.py`
|
| 333 |
+
|
| 334 |
+
类:`NutritionAnalyzer`
|
| 335 |
+
|
| 336 |
+
| 方法 | 输入 | 输出 | 说明 |
|
| 337 |
+
|------|------|------|------|
|
| 338 |
+
| `analyze_diet(records)` | `records: list[dict]` (diet_logger 格式) | `dict` | 营养覆盖分析 |
|
| 339 |
+
| `generate_report_chart(analysis)` | `analysis: dict`(上一个方法返回) | `matplotlib.figure.Figure` | 4 面板可视化图表 |
|
| 340 |
+
| `generate_report_text(analysis)` | `analysis: dict` | `str` | 文本格式报告 |
|
| 341 |
+
| `export_report_markdown(analysis, filename)` | `analysis: dict`, `filename: str\|None` | `Path` | 导出 Markdown 报告 |
|
| 342 |
+
|
| 343 |
+
**`analyze_diet` 返回 dict schema**:
|
| 344 |
+
```json
|
| 345 |
+
{
|
| 346 |
+
"total_days": 7,
|
| 347 |
+
"total_records": 21,
|
| 348 |
+
"meal_counts": {"早餐": 5, "午餐": 6, "晚餐": 6, "加餐": 4},
|
| 349 |
+
"food_items": ["全麦面包", "鸡蛋", "牛奶", "清蒸鱼", ...],
|
| 350 |
+
"nutrition_coverage": {
|
| 351 |
+
"叶酸": {
|
| 352 |
+
"matched_foods": ["菠菜"],
|
| 353 |
+
"covered": true,
|
| 354 |
+
"recommended_foods": ["菠菜", "西兰花", "芦笋"],
|
| 355 |
+
"benefit": "预防胎儿神经管畸形",
|
| 356 |
+
"daily_recommend": "0.4",
|
| 357 |
+
"unit": "mg"
|
| 358 |
+
},
|
| 359 |
+
...
|
| 360 |
+
},
|
| 361 |
+
"diversity_score": {"score": 75, "details": ["✅ 早餐: 6/7天 (86%)", ...]},
|
| 362 |
+
"suggestions": ["⚠️ 以下营养素摄入不足: 铁, 钙", ...]
|
| 363 |
+
}
|
| 364 |
+
```
|
| 365 |
+
|
| 366 |
+
**图表输出**(`generate_report_chart`):
|
| 367 |
+
1. 左上:营养覆盖雷达图(最多 8 种营养素)
|
| 368 |
+
2. 右上:各餐次频率柱状图
|
| 369 |
+
3. 左下:饮食多样性评分环形图
|
| 370 |
+
4. 右下:营养建议文本框
|
| 371 |
+
|
| 372 |
+
**依赖**:
|
| 373 |
+
- `config.NUTRITION_DB_FILE`(`data/nutrition_db.json`)— 可自定义
|
| 374 |
+
- `config.DEFAULT_NUTRITION_DB`(10 种营养素的内置推荐)
|
| 375 |
+
- `config.REPORTS_DIR`(`data/reports/`)
|
| 376 |
+
- `utils.setup_chinese_font()` — matplotlib 中文字体
|
| 377 |
+
|
| 378 |
+
> 🔴 **风险等级:高(待改造)** — 当前使用通用 `DEFAULT_NUTRITION_DB` 做营养覆盖分析,**尚未对接 `modules/nutrition_standards.py` 的 DRIs 数据**。改造时需:
|
| 379 |
+
> 1. 将 `_calculate_nutrition_coverage` 中的 `self.nutrition_db` 替换为 `DRIsParser.get_dri_for_trimester()`
|
| 380 |
+
> 2. 保持 `analyze_diet(records) -> dict` 签名不变
|
| 381 |
+
> 3. 保持 `nutrition_coverage` 的 dict key 不变(nutrient name 为 key)
|
| 382 |
+
|
| 383 |
+
---
|
| 384 |
+
|
| 385 |
+
### 3.8 插件基类 — `plugins/base.py`
|
| 386 |
+
|
| 387 |
+
核心类型(供所有插件和 loop 使用):
|
| 388 |
+
|
| 389 |
+
```python
|
| 390 |
+
# 阶段枚举
|
| 391 |
+
class LoopStage(Enum):
|
| 392 |
+
FAMILY_QUIZ = "family_quiz"
|
| 393 |
+
SUMMARIZE = "summarize"
|
| 394 |
+
ANALYZE = "analyze"
|
| 395 |
+
BRIEF = "brief"
|
| 396 |
+
THREE_DAY = "three_day"
|
| 397 |
+
CONSOLIDATE = "consolidate"
|
| 398 |
+
|
| 399 |
+
# 上下文容器(插件间共享)
|
| 400 |
+
@dataclass
|
| 401 |
+
class LoopContext:
|
| 402 |
+
briefing: dict = {} # 累积的简报数据
|
| 403 |
+
weight_data: dict = {}
|
| 404 |
+
diet_records: list = []
|
| 405 |
+
family_recipes: list = [] # family_manager.RecipeManager.load_all() 格式
|
| 406 |
+
family_memory: dict = {} # family_manager.MemoryManager.load_all() 格式
|
| 407 |
+
analysis_results: dict = {}
|
| 408 |
+
errors: list = []
|
| 409 |
+
|
| 410 |
+
# 插件结果
|
| 411 |
+
@dataclass
|
| 412 |
+
class PluginResult:
|
| 413 |
+
success: bool = True
|
| 414 |
+
data: dict = {}
|
| 415 |
+
message: str = ""
|
| 416 |
+
|
| 417 |
+
# 插件基类
|
| 418 |
+
class LoopPlugin(ABC):
|
| 419 |
+
@abstractmethod
|
| 420 |
+
def stage(self) -> LoopStage: ...
|
| 421 |
+
@abstractmethod
|
| 422 |
+
def name(self) -> str: ...
|
| 423 |
+
@abstractmethod
|
| 424 |
+
async def run(self, ctx: LoopContext) -> PluginResult: ...
|
| 425 |
+
```
|
| 426 |
+
|
| 427 |
+
> ✅ **风险等级:低** — 核心架构稳定。新增插件:实现 `LoopPlugin`,在 `loop.py` 的 `_register_default_plugins` 中注册即可。
|
| 428 |
+
|
| 429 |
+
---
|
| 430 |
+
|
| 431 |
+
## 4. 插件管线一览
|
| 432 |
+
|
| 433 |
+
| 插件名 | 阶段 | 文件 | 职责 |
|
| 434 |
+
|--------|------|------|------|
|
| 435 |
+
| `FamilyRecipeQuizPlugin` | `FAMILY_QUIZ` | `plugins/family_quiz.py` | 检查是否需要询问家庭菜谱 |
|
| 436 |
+
| `WeightQuizPlugin` | `FAMILY_QUIZ` | `plugins/family_quiz.py` | 检查是否需要询问体重 |
|
| 437 |
+
| `DietSummaryPlugin` | `SUMMARIZE` | `plugins/diet_summary.py` | 读取昨日饮食日志 |
|
| 438 |
+
| `WeightCheckPlugin` | `SUMMARIZE` | `plugins/weight_check.py` | 体重变化分析 |
|
| 439 |
+
| `FamilyMemoryPlugin` | `SUMMARIZE` | `plugins/family_memory.py` | 提取家庭记忆 |
|
| 440 |
+
| `DRIAnalysisPlugin` | `ANALYZE` | `plugins/dri_analysis.py` | DRIs 营养对比 |
|
| 441 |
+
| `BriefingGeneratorPlugin` | `BRIEF` | `plugins/briefing_generator.py` | 汇总生成今日简报 |
|
| 442 |
+
| `ThreeDaySummaryPlugin` | `THREE_DAY` | `plugins/three_day_summary.py` | 三天综合总结 |
|
| 443 |
+
| `PresetWriterPlugin` | `CONSOLIDATE` | `plugins/preset_writer.py` | 写入预设/缓存 |
|
| 444 |
+
|
| 445 |
+
**插件向 `ctx.briefing` 写入的 key**(`BriefingGeneratorPlugin` 最终消费):
|
| 446 |
+
```
|
| 447 |
+
ctx.briefing["trimester"] # str
|
| 448 |
+
ctx.briefing["need_ask_weight"] # bool
|
| 449 |
+
ctx.briefing["weight_quiz_message"] # str
|
| 450 |
+
ctx.briefing["weight_evaluation"] # dict
|
| 451 |
+
ctx.briefing["need_ask_recipe"] # bool
|
| 452 |
+
ctx.briefing["recipe_quiz_message"] # str
|
| 453 |
+
ctx.briefing["yesterday_diet"] # dict {"status","summary","meal_count"}
|
| 454 |
+
ctx.briefing["dri_analysis"] # dict {"focus_nutrients","summary"}
|
| 455 |
+
ctx.briefing["recommended_foods"] # list[str]
|
| 456 |
+
ctx.briefing["family_memory"] # dict
|
| 457 |
+
ctx.briefing["thinking_keywords"] # str
|
| 458 |
+
```
|
| 459 |
+
|
| 460 |
+
---
|
| 461 |
+
|
| 462 |
+
## 5. 配置模块 — `config.py`
|
| 463 |
+
|
| 464 |
+
每个 Cline 如需新增全局常量,**追加到同类型区域末尾**,并在 commit message 中注明。
|
| 465 |
+
|
| 466 |
+
| 配置区 | 主要内容 | 修改风险 |
|
| 467 |
+
|--------|---------|----------|
|
| 468 |
+
| 目录路径 | `DATA_DIR`, `VOICE_DIR`, `LOGS_DIR`, `REPORTS_DIR`, `FAMILY_FILE`, `DIET_LOG_FILE`, `NUTRITION_DB_FILE` | ⚠️ 中 |
|
| 469 |
+
| 常量枚举 | `FAMILY_ROLES`, `TRIMESTERS` | ✅ 低 |
|
| 470 |
+
| 数据模板 | `DEFAULT_NUTRITION_DB` (10种营养素), `MEAL_TEMPLATES` (4×4), `TRIMESTER_ADJUSTMENTS`, `TRIMESTER_TIPS` | ⚠️ 中 |
|
| 471 |
+
| Schema 版本 | `DIET_LOG_SCHEMA_VERSION = "1.0"` | ⚠️(改版本号前需评估向后兼容) |
|
| 472 |
+
| 声纹阈值 | `VOICEPRINT_SIMILARITY_THRESHOLD = 0.7` | ✅ 低 |
|
| 473 |
+
|
| 474 |
+
---
|
| 475 |
+
|
| 476 |
+
## 6. 数据文件格式规范
|
| 477 |
+
|
| 478 |
+
| 文件 | 格式 | Schema | 读模块 | 写模块 |
|
| 479 |
+
|------|------|--------|--------|--------|
|
| 480 |
+
| `data/diet_logs.json` | JSON | `{"schema_version": "1.0", "records": [...]}` | `diet_logger`, `nutrition_analyzer` | `diet_logger` |
|
| 481 |
+
| `data/nutrition_db.json` | JSON | `{"营养素名": {"category", "daily_recommend_mg/g/mcg", "foods": [...], "benefit"}}` | `nutrition_analyzer` | `nutrition_analyzer` (首次初始化) |
|
| 482 |
+
| `data/family.json` | JSON | `{"members": [...], "voiceprints": {...}}` | `voiceprint` | `voiceprint` |
|
| 483 |
+
| `data/family/recipes.md` | Markdown | `### 菜名\n- **制作人**: ...` | `family_manager.RecipeManager` | `family_manager.RecipeManager` |
|
| 484 |
+
| `data/family/preferences.md` | Markdown | `### 成员:姓名\n- **偏好**: ...` | `family_manager.PreferenceManager` | `family_manager.PreferenceManager` |
|
| 485 |
+
| `data/family/memory.md` | Markdown | `## 重要事件\n- **日期**: ...` | `family_manager.MemoryManager` | `family_manager.MemoryManager` |
|
| 486 |
+
| `data/logs/饮食日志_*.md` | Markdown | 见 3.4 节 | `plugins/diet_summary` | `diet_logger` |
|
| 487 |
+
| `data/reports/营养报告_*.md` | Markdown | 见 3.7 节 | 用户 | `nutrition_analyzer` |
|
| 488 |
+
| `data/presets/.daily_status.json` | JSON | `{"YYYY-MM-DD": {"summary_done": bool, "day_ended": bool}}` | `loop.DailyStatus` | `loop.DailyStatus` |
|
| 489 |
+
|
| 490 |
+
---
|
| 491 |
+
|
| 492 |
+
## 7. 并行 Cline 协作规范
|
| 493 |
+
|
| 494 |
+
### 7.1 分工建议
|
| 495 |
+
|
| 496 |
+
```
|
| 497 |
+
Cline A: Modules 强化(营养分析对接 DRIs、菜谱推荐 AI 化)
|
| 498 |
+
Cline B: UI 界面优化(Gradio 前端增强、报告模板美化)
|
| 499 |
+
Cline C: 声纹升级(Whisper encoder 替换频谱特征)
|
| 500 |
+
Cline D: 数据处理与插件增强(diet_extractor fallback、新插件)
|
| 501 |
+
```
|
| 502 |
+
|
| 503 |
+
### 7.2 关键约定
|
| 504 |
+
|
| 505 |
+
1. **改接口前先 grep**:用 `search_files` 搜索方法名找到所有调用方
|
| 506 |
+
2. **config.py 修改需沟通**:新增常量追加到同类型区域,不删改已有常量名
|
| 507 |
+
3. **数据文件向后兼容**:新增字段优先用 `extensions: {}` 或新增可选 key,不删除已有 key
|
| 508 |
+
4. **测试保持通过**:`python tests/run_tests.py` 零失败
|
| 509 |
+
5. **README 同步更新**:接口签名变更 → 更新本 README 对应章节
|
| 510 |
+
|
| 511 |
+
### 7.3 Git 工作流(强制执行)
|
| 512 |
+
|
| 513 |
+
```bash
|
| 514 |
+
# 工作前
|
| 515 |
+
git pull --rebase origin main
|
| 516 |
+
|
| 517 |
+
# 开发中:每完成一个独立功能点就提交
|
| 518 |
+
git add -A
|
| 519 |
+
git commit -m "feat: 描述做了什么"
|
| 520 |
+
|
| 521 |
+
# 推送前再次 pull
|
| 522 |
+
git pull --rebase origin main
|
| 523 |
+
|
| 524 |
+
# 测试通过后推送
|
| 525 |
+
python tests/run_tests.py
|
| 526 |
+
git push origin main
|
| 527 |
+
```
|
| 528 |
+
|
| 529 |
+
### 7.4 Commit Message 规范
|
| 530 |
+
|
| 531 |
+
```
|
| 532 |
+
feat: 新功能/新模块/新接口
|
| 533 |
+
fix: 修复 bug
|
| 534 |
+
test: 添加或修改测试
|
| 535 |
+
refactor: 重构(不改功能)
|
| 536 |
+
docs: 文档更新(含本 README)
|
| 537 |
+
chore: 配置/依赖/路径调整
|
| 538 |
+
```
|
| 539 |
+
|
| 540 |
+
### 7.5 冲突处理策略
|
| 541 |
+
|
| 542 |
+
| 冲突类型 | 处理方式 |
|
| 543 |
+
|---------|---------|
|
| 544 |
+
| `config.py` 常量冲突 | 取并集,双方新增常量都保留 |
|
| 545 |
+
| 同函数不同实现 | 保留逻辑更完整的一方,另一方改动如果无冲突则合并到合适位置 |
|
| 546 |
+
| 数据文件(JSON/MD)冲突 | 保留两个版本共有的条目 + 各自独有条目(去重) |
|
| 547 |
+
| 测试文件冲突 | **取并集**:保留所有测试用例 |
|
| 548 |
+
| 本 README 冲突 | **取行数更长的一方**,手动整合 |
|
| 549 |
+
| `.gitignore` 冲突 | 取并集 |
|
| 550 |
+
|
| 551 |
+
---
|
| 552 |
+
|
| 553 |
+
## 8. 测试
|
| 554 |
+
|
| 555 |
+
```bash
|
| 556 |
+
# 运行全部测试
|
| 557 |
+
python tests/run_tests.py
|
| 558 |
+
```
|
| 559 |
+
|
| 560 |
+
当前测试覆盖:
|
| 561 |
+
- `test_diet_extractor.py` — ✅ 通过(正则解析 + fallback 提取)
|
| 562 |
+
- `test_family_manager.py` — ✅ 通过(菜谱/偏好/记忆 CRUD)
|
| 563 |
+
- `test_nutrition_standards.py` — ✅ 通过(BMI/膳食指南/DRIs 数据)
|
| 564 |
+
- `test_loop.py` — 循环执行测试
|
| 565 |
+
- `test_plugins.py` — 插件集成测试
|
| 566 |
+
|
| 567 |
+
---
|
| 568 |
+
|
| 569 |
+
## 9. Model: MiniCPM-o 4.5
|
| 570 |
+
|
| 571 |
+
```
|
| 572 |
+
Model to be Used: MiniCPM-o 4.5
|
| 573 |
+
```
|
| 574 |
+
|
| 575 |
+
核心能力层(`core/` 目录)提供模型加载、语音处理、视觉处理、对话管理的底层能力封装。详见各文件 docstring。
|
| 576 |
+
|
| 577 |
+
---
|
| 578 |
+
|
| 579 |
+
*最后更新: 2026-06-09 | 由 PregoPal Cline 团队维护*
|