J.B-Lin commited on
Commit
33aa89f
·
1 Parent(s): 9046d8e

docs: 添加完整接口说明文档,包含架构图、模块接口表、数据schema、并行协作规范

Browse files
Files changed (1) hide show
  1. README.md +563 -2
README.md CHANGED
@@ -12,7 +12,568 @@ license: mit
12
  short_description: Voice-based Pregnant Meal & Nutrition Tracker
13
  ---
14
 
15
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
16
 
 
 
17
 
18
- Model to be Used: MiniCPM-o 4.5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 团队维护*