J.B-Lin commited on
Commit
ec90eae
ยท
1 Parent(s): ca31c30

chore: save current version before UI improvements (i18n + font fix)

Browse files
This view is limited to 50 files because it contains too many changes. ย  See raw diff
Files changed (50) hide show
  1. .gitignore +1 -2
  2. __pycache__/loop.cpython-311.pyc +0 -0
  3. __pycache__/loop.cpython-313.pyc +0 -0
  4. app.py +10 -4
  5. c +502 -0
  6. data/diet_logs.json +53 -0
  7. data/family/memory.md +21 -0
  8. data/family/preferences.md +23 -0
  9. data/family/recipes.md +35 -0
  10. data/nutrition/raw/ไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณ่†ณ้ฃŸๆŒ‡ๅ—2022ๅ›พ็‰‡่ฝฌmd็‰ˆ.md +124 -0
  11. data/nutrition/raw/ๅค‡ๅญ•&ๅญ•ๆ—ฉไธญๆ™šไธ‰ๆœŸๅ’Œๅ“บไนณๆœŸ็š„ๆ‰€ๆœ‰่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡.md +291 -0
  12. data/nutrition/raw/ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผๆ ‡ๅ‡†.md +92 -0
  13. data/presets/.daily_status.json +6 -0
  14. data/presets/ไปŠๆ—ฅ็ฎ€ๆŠฅ_2026-06-10.json +15 -0
  15. debug2.txt +3 -0
  16. debug4.txt +2 -0
  17. debug_out.txt +3 -0
  18. docs/้กน็›ฎ็†่งฃ_ๆŠ€ๆœฏๆžถๆž„.md +578 -222
  19. loop.py +291 -0
  20. modules/__pycache__/__init__.cpython-313.pyc +0 -0
  21. modules/__pycache__/diet_extractor.cpython-311.pyc +0 -0
  22. modules/__pycache__/diet_extractor.cpython-313.pyc +0 -0
  23. modules/__pycache__/family_manager.cpython-311.pyc +0 -0
  24. modules/__pycache__/family_manager.cpython-313.pyc +0 -0
  25. modules/__pycache__/nutrition_standards.cpython-311.pyc +0 -0
  26. modules/__pycache__/nutrition_standards.cpython-313.pyc +0 -0
  27. modules/diet_extractor.py +274 -0
  28. modules/family_manager.py +320 -0
  29. modules/nutrition_standards.py +377 -0
  30. plugins/__init__.py +5 -0
  31. plugins/__pycache__/__init__.cpython-311.pyc +0 -0
  32. plugins/__pycache__/__init__.cpython-313.pyc +0 -0
  33. plugins/__pycache__/base.cpython-311.pyc +0 -0
  34. plugins/__pycache__/base.cpython-313.pyc +0 -0
  35. plugins/__pycache__/briefing_generator.cpython-311.pyc +0 -0
  36. plugins/__pycache__/briefing_generator.cpython-313.pyc +0 -0
  37. plugins/__pycache__/diet_summary.cpython-311.pyc +0 -0
  38. plugins/__pycache__/diet_summary.cpython-313.pyc +0 -0
  39. plugins/__pycache__/dri_analysis.cpython-311.pyc +0 -0
  40. plugins/__pycache__/dri_analysis.cpython-313.pyc +0 -0
  41. plugins/__pycache__/family_memory.cpython-311.pyc +0 -0
  42. plugins/__pycache__/family_memory.cpython-313.pyc +0 -0
  43. plugins/__pycache__/family_quiz.cpython-311.pyc +0 -0
  44. plugins/__pycache__/family_quiz.cpython-313.pyc +0 -0
  45. plugins/__pycache__/preset_writer.cpython-311.pyc +0 -0
  46. plugins/__pycache__/preset_writer.cpython-313.pyc +0 -0
  47. plugins/__pycache__/three_day_summary.cpython-311.pyc +0 -0
  48. plugins/__pycache__/three_day_summary.cpython-313.pyc +0 -0
  49. plugins/__pycache__/weight_check.cpython-311.pyc +0 -0
  50. plugins/__pycache__/weight_check.cpython-313.pyc +0 -0
.gitignore CHANGED
@@ -1,2 +1 @@
1
- .vscode/
2
- data/nutrition/raw/
 
1
+ .vscode/
 
__pycache__/loop.cpython-311.pyc ADDED
Binary file (17.4 kB). View file
 
__pycache__/loop.cpython-313.pyc ADDED
Binary file (16.6 kB). View file
 
app.py CHANGED
@@ -1,12 +1,13 @@
1
  """
2
  PregoPal - ๅญ•ๆœŸ้™ชๆŠคAIๅŠฉๆ‰‹
3
  =========================
4
- ไธปๅ…ฅๅฃ๏ผšๅฏๅŠจ Gradio ๅบ”็”จใ€‚
5
 
6
  ๆžถๆž„๏ผš
7
- app.py โ† ่–„ๅ…ฅๅฃ๏ผˆไป…ๅฏๅŠจ๏ผ‰
8
  config.py โ† ๅ…จๅฑ€้…็ฝฎ
9
- core/ โ† AI ๆ ธๅฟƒๅฑ‚๏ผˆ็ญ‰ๅพ… MiniCPM-o ้ƒจ็ฝฒ๏ผ‰
 
10
  modules/ โ† ไธšๅŠก้€ป่พ‘ๅฑ‚
11
  ui/ โ† ่กจ็Žฐๅฑ‚๏ผˆGradio ็•Œ้ข๏ผ‰
12
  data/ โ† ๆ•ฐๆฎๅญ˜ๅ‚จ
@@ -14,9 +15,14 @@ PregoPal - ๅญ•ๆœŸ้™ชๆŠคAIๅŠฉๆ‰‹
14
 
15
  import gradio as gr
16
  from ui.app_builder import create_app
 
17
 
18
  if __name__ == "__main__":
19
- demo = create_app()
 
 
 
 
20
  demo.launch(
21
  theme=gr.themes.Soft(
22
  primary_hue="pink",
 
1
  """
2
  PregoPal - ๅญ•ๆœŸ้™ชๆŠคAIๅŠฉๆ‰‹
3
  =========================
4
+ ไธปๅ…ฅๅฃ๏ผšๅฏๅŠจ Gradio ๅบ”็”จ + ๆฏๆ—ฅ Loopใ€‚
5
 
6
  ๆžถๆž„๏ผš
7
+ app.py โ† ่–„ๅ…ฅๅฃ๏ผˆๅฏๅŠจ Gradio + Loop๏ผ‰
8
  config.py โ† ๅ…จๅฑ€้…็ฝฎ
9
+ loop.py โ† ๆ ธๅฟƒๅพช็Žฏๅผ•ๆ“Ž๏ผˆ็Šถๆ€ๆœบ้ฉฑๅŠจ๏ผ‰
10
+ plugins/ โ† Loop ๆ’ไปถ
11
  modules/ โ† ไธšๅŠก้€ป่พ‘ๅฑ‚
12
  ui/ โ† ่กจ็Žฐๅฑ‚๏ผˆGradio ็•Œ้ข๏ผ‰
13
  data/ โ† ๆ•ฐๆฎๅญ˜ๅ‚จ
 
15
 
16
  import gradio as gr
17
  from ui.app_builder import create_app
18
+ from loop import check_and_run_loop
19
 
20
  if __name__ == "__main__":
21
+ # ๅฏๅŠจๆ—ถๆฃ€ๆŸฅๅนถ่ฟ่กŒๆฏๆ—ฅ Loop
22
+ loop = check_and_run_loop()
23
+
24
+ # ๅˆ›ๅปบๅนถๅฏๅŠจ Gradio ๅบ”็”จ
25
+ demo = create_app(loop)
26
  demo.launch(
27
  theme=gr.themes.Soft(
28
  primary_hue="pink",
c ADDED
@@ -0,0 +1,502 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ๐ŸŒธ PregoPal ้กน็›ฎ็†่งฃไธŽๆŠ€ๆœฏๆžถๆž„๏ผˆv4 - Loop ้ฉฑๅŠจ + ไธ‰ๆ–‡ๆกฃๆ“ไฝœ๏ผ‰
2
+
3
+ > ๆœฌๆ–‡ๆกฃๅทฒๅฎŒๆˆ้‡ๆž„๏ผŒๆฏไธชๅฐ่Š‚ๆœซๅฐพ้™„ๆœ‰ๆ‰นๆณจๅŒบ๏ผŒไพฟไบŽไฝ ่พน็œ‹่พนๆ ‡ๆณจๆ„่งใ€‚
4
+
5
+ ---
6
+
7
+ ## ไธ€ใ€ไธ€ๅฅ่ฏๅฎšไฝ
8
+
9
+ **ไธ€ไธชๅŸบไบŽๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ Loop ้ฉฑๅŠจ็š„ๅญ•ๆœŸ้™ชๆŠค AI ๅŠฉๆ‰‹**๏ผšๆฏๅคฉ้ฆ–ๆฌกๅฏๅŠจๆ—ถ่‡ชๅŠจๆ€ป็ป“ๆ˜จๆ—ฅ้ฅฎ้ฃŸใ€ๅฏนๆฏ”ๅ›ฝๅฎถ่ฅๅ…ปๆ ‡ๅ‡†๏ผˆDRIs/่†ณ้ฃŸๆŒ‡ๅ—/ไฝ“้‡ๆ ‡ๅ‡†๏ผ‰๏ผŒ็”ŸๆˆไปŠๆ—ฅ็ฎ€ๆŠฅๆณจๅ…ฅๅฏน่ฏไธŠไธ‹ๆ–‡๏ผ›็™ฝๅคฉไธŽๅฎถๅบญๆˆๅ‘˜๏ผˆ้€š่ฟ‡ๅฃฐ็บนๅŒบๅˆ†๏ผ‰่‡ช็„ถไบคไบ’๏ผŒๅฎžๆ—ถ่ฎฐๅฝ•้ฅฎ้ฃŸใ€ๆŽจ่้ฃŸ่ฐฑ๏ผ›ๆฌกๆ—ฅๅพช็Žฏๅพ€ๅคใ€‚
10
+
11
+ > **ๆ‰นๆณจ๏ผš** ________
12
+
13
+ ---
14
+
15
+ ## ไบŒใ€ไธ‰ไธช่ฅๅ…ปๆ–‡ๆกฃ็š„ๆ“ไฝœๆ–นๆณ•
16
+
17
+ ไฝ ๅทฒ็ปไธ‹่ฝฝๅˆฐ `data/nutrition/raw/` ็š„ไธ‰ไธชๆ–‡ไปถ๏ผŒๅ„่‡ชๆ‰ฟๆ‹…ไธๅŒ่ง’่‰ฒ๏ผš
18
+
19
+ | ๆ–‡ๆกฃ | ๆ–‡ไปถ | ็”จ้€” | PregoPal ็š„ๆ“ไฝœๆ–นๅผ |
20
+ |------|------|------|-------------------|
21
+ | **โ‘  ไฝ“้‡ๅขž้•ฟๆ ‡ๅ‡†** | `ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผๆ ‡ๅ‡†.md` | ไฝ“้‡็›‘ๆต‹ๅŸบๅ‡† | **ไธปๅŠจ่ฏข้—ฎไฝ“้‡** โ€” ๆฏๅคฉ Loop ไธญๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ่ฏข้—ฎ๏ผŒๅฏน็…ง BMI ๅˆ†็ฑป็ป™ๅ‡บ่ฏ„ไปท |
22
+ | **โ‘ก ่†ณ้ฃŸๆŒ‡ๅ—** | `ไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณ่†ณ้ฃŸๆŒ‡ๅ—2022ๅ›พ็‰‡่ฝฌmd็‰ˆ.md` | ้ฃŸ่ฐฑๆŽจ่ๅŸบๅ‡† | **ไฝœไธบๆŽจ่้ฃŸ่ฐฑ็š„็บฆๆŸๅŸบ็ก€** โ€” ๆ นๆฎๅญ•ๆœŸ้˜ถๆฎต็”จๅฎๅก”ๆŽจ่้‡็”Ÿๆˆๆจกๆฟ |
23
+ | **โ‘ข DRIs** | `ๅค‡ๅญ•&ๅญ•ๆ—ฉไธญๆ™šไธ‰ๆœŸๅ’Œๅ“บไนณๆœŸ็š„ๆ‰€ๆœ‰่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡.md` | ่ฅๅ…ปๅˆ†ๆžๅŸบๅ‡† | **Agent ๅฎšๆœŸๆ€่€ƒ** โ€” ๆฏๅคฉ่‡ชๅŠจๅฏนๆฏ” RNI๏ผŒๅˆ†ๆžไธ่ถณ๏ผŒๅ†™ๅ…ฅๆฌกๆ—ฅ้ข„่ฎพ |
24
+
25
+ > **ๆ‰นๆณจ๏ผš** ________
26
+
27
+ ### 2.1 ไฝ“้‡ๅขž้•ฟๆ ‡ๅ‡† โ†’ ไธปๅŠจ่ฏข้—ฎไฝ“้‡
28
+
29
+ **ๆ•ฐๆฎๆฅๆบ**๏ผšWS/T 801-2022 ่กจ1
30
+
31
+ ```
32
+ ๆฏๅคฉๆ—ฉไธŠ Loop ็š„ weight_check ๆ’ไปถ๏ผš
33
+ โ”œโ†’ ๆฃ€ๆŸฅ data/logs/ ไธญๆ˜ฏๅฆๆœ‰่ฟ‘ๆœŸ็š„ไฝ“้‡่ฎฐๅฝ•
34
+ โ”œโ†’ ่‹ฅๆ— ่ฎฐๅฝ•ๆˆ–่ฎฐๅฝ•่ถ…่ฟ‡ 7 ๅคฉ
35
+ โ”‚ โ””โ†’ ๅœจไปŠๆ—ฅ็ฎ€ๆŠฅไธญๆ ‡่ฎฐใ€Œ้œ€่ฏข้—ฎไฝ“้‡ใ€
36
+ โ”‚ ๏ผˆUI ๅผนๅ‡บไฝ“้‡ๅก็‰‡๏ผŒๆˆ–่ฏญ้Ÿณ่ฏข้—ฎ๏ผšใ€ŒไปŠๅคฉ็งฐไฝ“้‡ไบ†ๅ—๏ผŸใ€๏ผ‰
37
+ โ””โ†’ ่‹ฅๆœ‰่ฎฐๅฝ•
38
+ โ”œโ†’ ่ฎก็ฎ—ๅฝ“ๅ‰ๅญ•ๅ‘จใ€ๅญ•ๅ‰ BMIใ€ๅฝ“ๅ‰ๆ€ปๅขž้•ฟๅ€ผ
39
+ โ”œโ†’ ๅฏน็…งๆ ‡ๅ‡†่กจ๏ผš
40
+
41
+ | ๅญ•ๅ‰ BMI ๅˆ†็ฑป | ๆ€ปๅขž้•ฟ่Œƒๅ›ด | ๆฏๅ‘จๅขž้•ฟ(ไธญ+ๆ™š) |
42
+ |----------------------|------------|----------------|
43
+ | ไฝŽไฝ“้‡ BMI<18.5 | 11.0~16.0 | 0.46(0.37~0.56) |
44
+ | ๆญฃๅธธ 18.5โ‰คBMI<24.0 | 8.0~14.0 | 0.37(0.26~0.48) |
45
+ | ่ถ…้‡ 24.0โ‰คBMI<28.0 | 7.0~11.0 | 0.30(0.22~0.37) |
46
+ | ่‚ฅ่ƒ– BMIโ‰ฅ28.0 | 5.0~9.0 | 0.22(0.15~0.30) |
47
+
48
+ โ”œโ†’ ๅœจ่Œƒๅ›ดๅ†… โ†’ โœ… ้ผ“ๅŠฑใ€Œไฝ“้‡ๅขž้•ฟๅพˆๅฅฝ๏ผŒ็ปง็ปญไฟๆŒ๏ผใ€
49
+ โ””โ†’ ่ถ…ๅ‡บ่Œƒๅ›ด โ†’ โš ๏ธ ๆ้†’ใ€Œๅขž้•ฟๅๅฟซ/ๅๆ…ข๏ผŒๅปบ่ฎฎ่ฐƒๆ•ด้ฅฎ้ฃŸ/ๅ’จ่ฏขๅŒป็”Ÿใ€
50
+ ```
51
+
52
+ > **ๆ‰นๆณจ๏ผš** ________
53
+
54
+ ### 2.2 ่†ณ้ฃŸๆŒ‡ๅ— โ†’ ้ฃŸ่ฐฑๆŽจ่ๅŸบ็ก€
55
+
56
+ **ๆ•ฐๆฎๆฅๆบ**๏ผšไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณๅนณ่กก่†ณ้ฃŸๅฎๅก”๏ผˆๅค‡ๅญ•/ๅญ•ไธญๆœŸ/ๅญ•ๆ™šๆœŸ/ๅ“บไนณๆœŸ๏ผ‰
57
+
58
+ ```
59
+ ๆŽจ่้ฃŸ่ฐฑๆ—ถ๏ผŒAI ็š„็บฆๆŸๆกไปถ๏ผš
60
+ โ”œโ†’ ๅญ•ไธญๆœŸๅฎๅก”๏ผš
61
+ โ”‚ ๅฅถ็ฑป 300-500g๏ผŒ้ฑผ็ฆฝ่›‹่‚‰็ฑป 150-200g๏ผŒ่ฐท็ฑป 200-250g
62
+ โ”‚ ่”ฌ่œ 400-500g๏ผŒๆฐดๆžœ 200-300g๏ผŒ่–ฏ็ฑป 75g
63
+ โ”‚ ๅคง่ฑ† 20g๏ผŒๅšๆžœ 10g๏ผŒๆฒน 25g๏ผŒ็› 5g
64
+ โ”‚
65
+ โ”œโ†’ ๅญ•ๆ™šๆœŸๅฎๅก”๏ผš
66
+ โ”‚ ๅฅถ็ฑป 300-500g๏ผŒ้ฑผ็ฆฝ่›‹่‚‰็ฑป 175-225g๏ผŒ่ฐท็ฑป 225-275g
67
+ โ”‚ ่”ฌ่œ 400-500g๏ผŒๆฐดๆžœ 200-350g๏ผŒ่–ฏ็ฑป 75g
68
+ โ”‚ ๅคง่ฑ† 20g๏ผŒๅšๆžœ 10g๏ผŒๆฒน 25g๏ผŒ็› 5g
69
+ โ”‚
70
+ โ””โ†’ ่†ณ้ฃŸๆŒ‡ๅ—ๅ…ญๆกๆ ธๅฟƒๅปบ่ฎฎ๏ผˆๅตŒๅ…ฅ็ณป็ปŸๆ็คบ่ฏ๏ผ‰๏ผš
71
+ 1. ่ฐƒๆ•ดๅญ•ๅ‰ไฝ“้‡่‡ณๆญฃๅธธ่Œƒๅ›ด
72
+ 2. ๅธธๅƒๅซ้“้ฃŸ็‰ฉ๏ผŒ้€‰็”จ็ข˜็›๏ผŒ่กฅๅ……ๅถ้…ธๅ’Œ็ปด็”Ÿ็ด D
73
+ 3. ๅญ•ๅไธฅ้‡่€…ๅฐ‘้‡ๅคš้ค
74
+ 4. ๅญ•ไธญๆ™šๆœŸๅขžๅŠ ๅฅถใ€้ฑผใ€็ฆฝใ€่›‹ใ€็˜ฆ่‚‰
75
+ 5. ็ปๅธธๆˆทๅค–ๆดปๅŠจ๏ผŒ็ฆ็ƒŸ้…’
76
+ 6. ๆ„‰ๅฟซๅญ•่‚ฒๆ–ฐ็”Ÿๅ‘ฝ๏ผŒ็งฏๆžๅ‡†ๅค‡ๆฏไนณๅ–‚ๅ…ป
77
+ ```
78
+
79
+ **ๅŽŸๆœ‰ MEAL_TEMPLATES ็š„ๆ”น้€ **๏ผšไธๅ†็กฌ็ผ–็ ๆจกๆฟๅญ—็ฌฆไธฒ๏ผŒ่€Œๆ˜ฏๅฐ†ไธŠ่ฟฐๅฎๅก”็บฆๆŸๆกไฝœไธบ็ป“ๆž„ๅŒ– JSON ไผ ้€’็ป™ AI๏ผˆๆˆ–ไฝœไธบๆœฌๅœฐ fallback ๅ…œๅบ•๏ผ‰๏ผŒ็”ฑ AI ๆ นๆฎๅฎๅก”็บฆๆŸ + ็”จๆˆทๅๅฅฝ็”Ÿๆˆไธชๆ€งๅŒ–้ฃŸ่ฐฑใ€‚
80
+
81
+ > **ๆ‰นๆณจ๏ผš** ________
82
+
83
+ ### 2.3 DRIs โ†’ Agent ๅฎšๆœŸๅˆ†ๆž๏ผˆ่‡ชๅŠจ่ฟ่กŒ โ†’ ๅ†™ๅ…ฅๆฌกๆ—ฅ้ข„่ฎพ๏ผ‰
84
+
85
+ **ๆ•ฐๆฎๆฅๆบ**๏ผš่กจ15๏ผˆๅญ•ๆ—ฉๆœŸ๏ผ‰/ ่กจ16๏ผˆๅญ•ไธญๆœŸ๏ผ‰/ ่กจ17๏ผˆๅญ•ๆ™šๆœŸ๏ผ‰/ ่กจ18๏ผˆๅ“บไนณๆœŸ๏ผ‰
86
+
87
+ ```
88
+ ๆฏๅคฉ Loop ็š„ dri_analysis ๆ’ไปถ๏ผš
89
+ โ”œโ†’ ่ฏปๅ–ๆ˜จๆ—ฅ้ฅฎ้ฃŸ่ฎฐๅฝ•๏ผˆdata/logs/้ฅฎ้ฃŸๆ—ฅๅฟ—_YYYY-MM-DD.md๏ผ‰
90
+ โ”œโ†’ ๆ นๆฎๅฝ“ๅ‰ๅญ•ๆœŸ้˜ถๆฎต้€‰ๆ‹ฉๅฏนๅบ” DRIs ่กจ
91
+ โ”œโ†’ ๅ…ณ้”ฎ่ฅๅ…ป็ด ้€้กนๅฏนๆฏ”๏ผˆ้‡็‚นๆ ‡่ฎฐ RNI ไธŽๆ‘„ๅ…ฅ้‡ๅทฎๅผ‚๏ผ‰๏ผš
92
+
93
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
94
+ โ”‚ ่ฅๅ…ป็ด  RNI(ๅญ•ไธญๆœŸ) ๆ˜จๆ—ฅๆ‘„ๅ…ฅ ๅทฎๅผ‚ โ”‚
95
+ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
96
+ โ”‚ ่ƒฝ้‡(MJ) 9.84(PAL II) 8.2 -17% โ”‚
97
+ โ”‚ ่›‹็™ฝ่ดจ(g) 70 55 -21% โ”‚
98
+ โ”‚ ้’™(mg) 800 420 -48% โ”‚
99
+ โ”‚ ้“(mg) 25 12 -52% โ† ้‡็‚นๅ…ณๆณจ โ”‚
100
+ โ”‚ ๅถ้…ธ(ฮผg DFE) 600 350 -42% โ† ้‡็‚นๅ…ณ๏ฟฝ๏ฟฝ โ”‚
101
+ โ”‚ ็ปด็”Ÿ็ด D(ฮผg) 10 2.1 -79% โ† ้‡็‚นๅ…ณๆณจ โ”‚
102
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
103
+
104
+ โ”œโ†’ ็”Ÿๆˆๅˆ†ๆž็ป“่ฎบ๏ผˆ่‡ช็„ถ่ฏญ่จ€๏ผ‰๏ผš
105
+ โ”‚ ใ€Œๆ˜จๅคฉ้’™ใ€้“ใ€ๅถ้…ธๆ‘„ๅ…ฅๅไฝŽ๏ผŒๅปบ่ฎฎไปŠๅคฉๅคšๅƒ๏ผš
106
+ โ”‚ โœ“ ๆทฑ็ปฟ่‰ฒ่”ฌ่œ๏ผˆ่ ่œใ€่ฅฟๅ…ฐ่Šฑ๏ผ‰
107
+ โ”‚ โœ“ ็˜ฆ่‚‰/ๅŠจ็‰ฉ่‚่„
108
+ โ”‚ โœ“ ่ฑ†ๅˆถๅ“/ๅฅถๅˆถๅ“ใ€
109
+ โ”‚
110
+ โ””โ†’ ๅ†™ๅ…ฅ data/presets/ไปŠๆ—ฅ็ฎ€ๆŠฅ_YYYY-MM-DD.json
111
+ โ”œ ไปŠๆ—ฅ้‡็‚นๅ…ณๆณจ่ฅๅ…ป็ด ๅˆ—่กจ
112
+ โ”œ ไปŠๆ—ฅๆŽจ่้ฃŸ็‰ฉ็ฑปๅˆซไธŽไปฝ้‡
113
+ โ”œ ไฝ“้‡ๆ้†’๏ผˆๅฆ‚้œ€๏ผ‰
114
+ โ”” ไธŽๅญ•ๅฆ‡ๅŠๅฎถไบบไบค่ฐˆ็š„ๅปบ่ฎฎๅผ€ๅœบ่ฏ้ข˜
115
+ ```
116
+
117
+ > **ๆ‰นๆณจ๏ผš** ________
118
+
119
+ ---
120
+
121
+ ## ไธ‰ใ€ๆ ธๅฟƒๆžถๆž„๏ผšLoop ้ฉฑๅŠจ๏ผˆ็Šถๆ€ๆœบ + ๆ’ไปถๆณจๅ†Œ๏ผ‰
122
+
123
+ ### 3.1 ่ฎพ่ฎก็†ๅฟต
124
+
125
+ PregoPal ไธๆ˜ฏไธ€ไธชใ€Œ็”จๆˆท็‚นๆŒ‰้’ฎ โ†’ ๅ‡บ็ป“ๆžœใ€็š„่ขซๅŠจๅบ”็”จ๏ผŒ่€Œๆ˜ฏ**ๆœ‰ๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ็š„ไธปๅŠจไผดไพฃ**ใ€‚
126
+
127
+ ๅ‚่€ƒไฝ ๆไพ›็š„ `nanobot_core/agent/loop.py` ไธญ็š„**็Šถๆ€ๆœบไบ‹ไปถ้ฉฑๅŠจๆจกๅผ**๏ผŒPregoPal ็š„ Loop ๆๅ–ไธคไธชๆ ธๅฟƒ่ฎพ่ฎก๏ผš
128
+
129
+ 1. **TurnState ็Šถๆ€ๆœบ**๏ผˆ็ฑปๆฏ” `_process_message` ็š„ `_state_*` ็Šถๆ€้“พ๏ผ‰โ€” ็ฎก็†ๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ็š„้˜ถๆฎตๆต่ฝฌ
130
+ 2. **ๅฏๆณจๅ†Œ็š„ๆ‰ฉๅฑ•่ƒฝๅŠ›**๏ผˆ็ฑปๆฏ” ToolRegistry๏ผ‰โ€” ๆฏไธช้˜ถๆฎต็š„ๅ…ทไฝ“้€ป่พ‘็”ฑ Plugin ๅฎž็Žฐ
131
+
132
+ > **ๆ‰นๆณจ๏ผš** ________
133
+
134
+ ### 3.2 ๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ
135
+
136
+ ```
137
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
138
+ โ”‚ LAUNCH โ”‚ โ† ้ฆ–ๆฌกๅฏๅŠจๆฃ€ๆŸฅ
139
+ โ”‚ (ๅฏๅŠจ) โ”‚
140
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜
141
+ โ”‚
142
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
143
+ โ”‚ โ”‚
144
+ ้ฆ–ๆฌก่ฟ่กŒไปŠๆ—ฅ ๅทฒ่ฟ่กŒ่ฟ‡ไปŠๆ—ฅ
145
+ โ”‚ โ”‚
146
+ โ–ผ โ–ผ
147
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
148
+ โ”‚ SUMMARIZE โ”‚ โ”‚ โ”‚
149
+ โ”‚ (ๆ˜จๆ—ฅๆ€ป็ป“) โ”‚ โ”‚ โ”‚
150
+ โ”‚ โ”œ ่ฏปๅ–้ฅฎ้ฃŸๆ—ฅๅฟ— โ”‚ โ”‚ โ”‚
151
+ โ”‚ โ”” ๆฃ€ๆŸฅไฝ“้‡ โ”‚ โ”‚ โ”‚
152
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
153
+ โ”‚ โ”‚ โ”‚
154
+ โ–ผ โ”‚ โ”‚
155
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
156
+ โ”‚ ANALYZE โ”‚ โ”‚ โ”‚
157
+ โ”‚ (่ฅๅ…ปๅˆ†ๆž) โ”‚ โ”‚ โ”‚
158
+ โ”‚ โ”” ๅฏนๆฏ”DRIs โ”‚ โ”‚ โ”‚
159
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
160
+ โ”‚ โ”‚ โ”‚
161
+ โ–ผ โ”‚ โ”‚
162
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
163
+ โ”‚ BRIEF โ”‚ โ”‚ โ”‚
164
+ โ”‚ (็”Ÿๆˆ็ฎ€ๆŠฅ) โ”‚ โ”‚ โ”‚
165
+ โ”‚ โ”” ๅ†™JSON โ”‚ โ”‚ โ”‚
166
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
167
+ โ”‚ โ”‚ โ”‚
168
+ โ–ผ โ–ผ โ”‚
169
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
170
+ โ”‚ INTERACT โ”‚โ—„โ”€โ”˜
171
+ โ”‚ (็™ฝๅคฉไบคไบ’ๆจกๅผ) โ”‚
172
+ โ”‚ โ”œ ๅฃฐ็บน่ฏ†ๅˆซ โ†’ ๅŒบๅˆ†่ฏด่ฏไบบ โ”‚
173
+ โ”‚ โ”œ ๅฏน่ฏ็†่งฃ โ†’ ่ฎฐๅฝ•้ฅฎ้ฃŸ/ๆŽจ่/้—ฒ่Š โ”‚
174
+ โ”‚ โ”” ็ฎ€ๆŠฅๆณจๅ…ฅ โ†’ AI ็Ÿฅ้“ไปŠๆ—ฅๅ…ณๆณจ็‚น โ”‚
175
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
176
+ โ”‚
177
+ ็”จๆˆท็ป“ๆŸไปŠๆ—ฅ
178
+ โ”‚
179
+ โ–ผ
180
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
181
+ โ”‚ CONSOLIDATE โ”‚
182
+ โ”‚ (ๆ™š้—ดๆ•ด็†) โ”‚ โ† ๅฏ้€‰๏ผˆๅ…ณ้—ญ้กต้ขๆ—ถ่งฆๅ‘๏ผ‰
183
+ โ”‚ โ”œ ๆฑ‡ๆ€ปไปŠๆ—ฅ โ”‚
184
+ โ”‚ โ”” ๅ†™ๆ˜Žๆ—ฅ้ข„่ฎพ โ”‚
185
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
186
+ โ”‚
187
+ โ–ผ
188
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
189
+ โ”‚ DONE โ”‚
190
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
191
+ ```
192
+
193
+ > **ๆ‰นๆณจ๏ผš** ________
194
+
195
+ ### 3.3 ็Šถๆ€ๆœบๅฎšไน‰
196
+
197
+ ```python
198
+ # ็Šถๆ€ๆžšไธพ
199
+ class LoopState(Enum):
200
+ LAUNCH = "launch" # ๅฏๅŠจๆฃ€ๆŸฅ๏ผšๆ˜ฏๅฆๆ˜ฏไปŠๆ—ฅ้ฆ–ๆฌก่ฟ่กŒ
201
+ SUMMARIZE = "summarize" # ๆ˜จๆ—ฅๆ€ป็ป“๏ผš๏ฟฝ๏ฟฝๆžๆ˜จๆ—ฅ้ฅฎ้ฃŸ/ไฝ“้‡
202
+ ANALYZE = "analyze" # ่ฅๅ…ปๅˆ†ๆž๏ผšๅฏนๆฏ” DRIs
203
+ BRIEF = "brief" # ็”ŸๆˆไปŠๆ—ฅ็ฎ€ๆŠฅ
204
+ INTERACT = "interact" # ็™ฝๅคฉไบคไบ’ๆจกๅผ๏ผˆ็ญ‰ๅพ…็”จๆˆทๆ“ไฝœ๏ผ‰
205
+ CONSOLIDATE = "consolidate" # ๆ™š้—ดๆ•ด็†
206
+ DONE = "done"
207
+
208
+ # ็Šถๆ€่ฝฌ็งป่กจ๏ผˆ็ฑปๆฏ” nanobot_core ็š„ _TRANSITIONS๏ผ‰
209
+ _TRANSITIONS = {
210
+ (LoopState.LAUNCH, "first_run_today"): LoopState.SUMMARIZE,
211
+ (LoopState.LAUNCH, "already_run"): LoopState.INTERACT,
212
+ (LoopState.SUMMARIZE, "ok"): LoopState.ANALYZE,
213
+ (LoopState.ANALYZE, "ok"): LoopState.BRIEF,
214
+ (LoopState.BRIEF, "ok"): LoopState.INTERACT,
215
+ (LoopState.INTERACT, "day_ended"): LoopState.CONSOLIDATE,
216
+ (LoopState.CONSOLIDATE, "ok"): LoopState.DONE,
217
+ }
218
+ ```
219
+
220
+ > **ๆ‰นๆณจ๏ผš** ________
221
+
222
+ ### 3.4 ็Šถๆ€ๅค„็†ๅ™จ
223
+
224
+ ๆฏไธช็Šถๆ€ๅฏนๅบ”ไธ€ไธช handler๏ผˆ็ฑปๆฏ” `_state_restore`, `_state_compact`, `_state_run` ็ญ‰๏ผ‰๏ผš
225
+
226
+ | ็Šถๆ€ | Handler | ๅŠŸ่ƒฝ |
227
+ |------|---------|------|
228
+ | `LAUNCH` | `_state_launch()` | ๆฃ€ๆŸฅ `data/presets/` ไธญๆ˜ฏๅฆๆœ‰ไปŠๆ—ฅ็ฎ€ๆŠฅ โ†’ ๅ†ณๅฎš้ฆ–ๆฌก/ๅทฒ่ฟ่กŒ |
229
+ | `SUMMARIZE` | `_state_summarize()` | ้ๅކๆ‰ง่กŒๆ‰€ๆœ‰ๆณจๅ†Œๅœจ SUMMARIZE ้˜ถๆฎต็š„ Plugin |
230
+ | `ANALYZE` | `_state_analyze()` | ้ๅކๆ‰ง่กŒๆ‰€ๆœ‰ๆณจๅ†Œๅœจ ANALYZE ้˜ถๆฎต็š„ Plugin |
231
+ | `BRIEF` | `_state_brief()` | ้ๅކๆ‰ง่กŒๆ‰€ๆœ‰ๆณจๅ†Œๅœจ BRIEF ้˜ถๆฎต็š„ Plugin |
232
+ | `INTERACT` | `_state_interact()` | ็ญ‰ๅพ…็”จๆˆทไบคไบ’๏ผˆไปŽ Gradio event queue ๆถˆ่ดนๆถˆๆฏ๏ผ‰ |
233
+ | `CONSOLIDATE` | `_state_consolidate()` | ้ๅކๆ‰ง่กŒๆ‰€ๆœ‰ๆณจๅ†Œๅœจ CONSOLIDATE ้˜ถๆฎต็š„ Plugin |
234
+ | `DONE` | `_state_done()` | ๆธ…็†่ต„ๆบ๏ผŒๆ ‡่ฎฐไปŠๆ—ฅๅฎŒๆˆ |
235
+
236
+ > **ๆ‰นๆณจ๏ผš** ________
237
+
238
+ ### 3.5 ไธปๅพช็Žฏๅ…ฅๅฃ
239
+
240
+ ```python
241
+ # loop.py ๆ ธๅฟƒ้€ป่พ‘
242
+ class PregoPalLoop:
243
+ def __init__(self):
244
+ self.plugins = PluginRegistry()
245
+ self.state = LoopState.LAUNCH
246
+ self._register_default_plugins()
247
+
248
+ async def run(self) -> None:
249
+ """ไธปๅพช็Žฏๅ…ฅๅฃ"""
250
+ while self.state is not LoopState.DONE:
251
+ handler_name = f"_state_{self.state.value}"
252
+ handler = getattr(self, handler_name)
253
+ event = await handler()
254
+ next_state = _TRANSITIONS.get((self.state, event))
255
+ if next_state is None:
256
+ raise RuntimeError(f"No transition from {self.state} on {event}")
257
+ self.state = next_state
258
+
259
+ async def _state_summarize(self) -> str:
260
+ """SUMMARIZE ้˜ถๆฎต๏ผšๆ‰ง่กŒๆ‰€ๆœ‰็›ธๅ…ณๆ’ไปถ"""
261
+ for plugin in self.plugins.get_plugins(LoopStage.SUMMARIZE):
262
+ await plugin.run(self.context)
263
+ return "ok"
264
+ ```
265
+
266
+ > **ๆ‰นๆณจ๏ผš** ________
267
+
268
+ ---
269
+
270
+ ## ๅ››ใ€ๆ’ไปถ็ณป็ปŸ่ฎพ่ฎก๏ผˆๅฏๆ‰ฉๅฑ•ๆ€ง๏ผ‰
271
+
272
+ ### 4.1 ๆ’ไปถๅŸบ็ฑป
273
+
274
+ ```python
275
+ # plugins/base.py
276
+ from abc import ABC, abstractmethod
277
+ from dataclasses import dataclass, field
278
+ from enum import Enum
279
+
280
+ class LoopStage(Enum):
281
+ """ๆ’ไปถๅฏๆณจๅ†Œ็š„้˜ถๆฎต"""
282
+ SUMMARIZE = "summarize"
283
+ ANALYZE = "analyze"
284
+ BRIEF = "brief"
285
+ CONSOLIDATE = "consolidate"
286
+
287
+ @dataclass
288
+ class LoopContext:
289
+ """ๆ’ไปถไธŠไธ‹ๆ–‡๏ผšๅ…ฑไบซๆ•ฐๆฎๅฎนๅ™จ"""
290
+ briefing: dict = field(default_factory=dict) # ไปŠๆ—ฅ็ฎ€ๆŠฅๆ•ฐๆฎ
291
+ weight_data: dict = field(default_factory=dict) # ไฝ“้‡่ฎฐๅฝ•
292
+ diet_records: list = field(default_factory=list) # ้ฅฎ้ฃŸ่ฎฐๅฝ•
293
+ analysis_results: dict = field(default_factory=dict) # ๅˆ†ๆž็ป“ๆžœ
294
+ errors: list = field(default_factory=list) # ้”™่ฏฏๆ”ถ้›†
295
+
296
+ @dataclass
297
+ class PluginResult:
298
+ """ๆ’ไปถๆ‰ง่กŒ็ป“ๆžœ"""
299
+ success: bool
300
+ data: dict = field(default_factory=dict)
301
+ message: str = ""
302
+
303
+ class LoopPlugin(ABC):
304
+ """Loop ๆ‰ฉๅฑ•ๆ’ไปถๅŸบ็ฑป โ€” ๆ‰€ๆœ‰ๆ’ไปถ็ปงๆ‰ฟๆญค็ฑป"""
305
+
306
+ @abstractmethod
307
+ def stage(self) -> LoopStage:
308
+ """ๆญคๆ’ไปถๆณจๅ†Œๅˆฐๅ“ชไธช้˜ถๆฎต"""
309
+
310
+ @abstractmethod
311
+ def name(self) -> str:
312
+ """ๆ’ไปถๅ”ฏไธ€ๅ็งฐ"""
313
+
314
+ @abstractmethod
315
+ async def run(self, ctx: LoopContext) -> PluginResult:
316
+ """ๆ‰ง่กŒๆ’ไปถ้€ป่พ‘"""
317
+ ```
318
+
319
+ > **ๆ‰นๆณจ๏ผš** ________
320
+
321
+ ### 4.2 ๅ†…็ฝฎๆ’ไปถๆธ…ๅ•
322
+
323
+ | ๆ’ไปถ | ็ฑปๅ | ๆณจๅ†Œ้˜ถๆฎต | ๅŠŸ่ƒฝ | ๆ•ฐๆฎๆบ |
324
+ |------|------|---------|------|--------|
325
+ | ๆ˜จๆ—ฅ้ฅฎ้ฃŸๆ€ป็ป“ | `DietSummaryPlugin` | SUMMARIZE | ่ฏปๅ–ๆ˜จๆ—ฅ้ฅฎ้ฃŸๆ—ฅๅฟ—๏ผŒๆฑ‡ๆ€ปไธ‰้ค | `data/logs/*.md` |
326
+ | ไฝ“้‡ๆฃ€ๆŸฅ | `WeightCheckPlugin` | SUMMARIZE | ๆฃ€ๆŸฅไฝ“้‡่ฎฐๅฝ•๏ผŒๅฏนๆฏ” WS/T 801 | `data/logs/*.md` + ็”จๆˆท่พ“ๅ…ฅ |
327
+ | DRIs ๅˆ†ๆž | `DRIAnalysisPlugin` | ANALYZE | ๅฏนๆฏ”่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡ | DRIs ่กจ + ๆ˜จๆ—ฅ้ฅฎ้ฃŸ |
328
+ | ็ฎ€ๆŠฅ็”Ÿๆˆ | `BriefingGeneratorPlugin` | BRIEF | ๆฑ‡ๆ€ปๅˆ†ๆžไธบ็ป“ๆž„ๅŒ– JSON | `LoopContext` |
329
+ | ้ข„่ฎพๅ†™ๅ…ฅ | `PresetWriterPlugin` | CONSOLIDATE | ็”Ÿๆˆๆ˜Žๆ—ฅ้ข„่ฎพๆ–‡ไปถ | `data/presets/` |
330
+
331
+ > **ๆ‰นๆณจ๏ผš** ________
332
+
333
+ ### 4.3 ๆ‰ฉๅฑ•ๆ–นๅผ
334
+
335
+ ```python
336
+ # ๅŽ็ปญๆ–ฐๅขžๅŠŸ่ƒฝ๏ผˆๅฆ‚่ก€็ณ–็›‘ๆต‹๏ผ‰ๅช้œ€ไธคๆญฅ๏ผš
337
+
338
+ # 1. ๅ†™ไธ€ไธชๆ–ฐๆ’ไปถ
339
+ class BloodSugarPlugin(LoopPlugin):
340
+ def stage(self) -> LoopStage: return LoopStage.SUMMARIZE
341
+ def name(self) -> str: return "blood_sugar"
342
+ async def run(self, ctx: LoopContext) -> PluginResult:
343
+ # ่ฏปๅ–่ก€็ณ–่ฎฐๅฝ• โ†’ ๅˆ†ๆž่ถ‹ๅŠฟ โ†’ ๅ†™ๅ…ฅ ctx
344
+ ...
345
+
346
+ # 2. ๆณจๅ†Œๅˆฐ loop
347
+ loop.plugins.register(BloodSugarPlugin())
348
+
349
+ # ไธ้œ€่ฆไฟฎๆ”น loop.py ็š„ไปปไฝ•็Šถๆ€ๆœบไปฃ็ 
350
+ ```
351
+
352
+ > **ๆ‰นๆณจ๏ผš** ________
353
+
354
+ ---
355
+
356
+ ## ไบ”ใ€ๆ•ดไฝ“ๆ–‡ไปถ็ป“ๆž„
357
+
358
+ ```
359
+ PregoPal/
360
+ โ”œโ”€โ”€ app.py # ไธปๅ…ฅๅฃ๏ผšๅฏๅŠจ Gradio + Loop
361
+ โ”œโ”€โ”€ config.py # ๅ…จๅฑ€้…็ฝฎ๏ผˆ่ทฏๅพ„/ๆžšไธพ/็ณป็ปŸๆ็คบ่ฏๆจกๆฟ๏ผ‰
362
+ โ”œโ”€โ”€ utils.py # ๅทฅๅ…ทๅ‡ฝๆ•ฐ
363
+ โ”œโ”€โ”€ loop.py โ† ๐Ÿ†• ๆ–ฐๅขž # ๆ ธๅฟƒๅพช็Žฏๅผ•ๆ“Ž๏ผˆ็Šถๆ€ๆœบ้ฉฑๅŠจ๏ผ‰
364
+ โ”‚
365
+ โ”œโ”€โ”€ plugins/ โ† ๐Ÿ†• ๆ–ฐๅขž # Loop ๆ’ไปถ
366
+ โ”‚ โ”œโ”€โ”€ __init__.py
367
+ โ”‚ โ”œโ”€โ”€ base.py # LoopPlugin ๅŸบ็ฑป + PluginRegistry
368
+ โ”‚ โ”œโ”€โ”€ diet_summary.py # ๆ˜จๆ—ฅ้ฅฎ้ฃŸๆ€ป็ป“
369
+ โ”‚ โ”œโ”€โ”€ weight_check.py # ไฝ“้‡ๆฃ€ๆŸฅ๏ผˆWS/T 801๏ผ‰
370
+ โ”‚ โ”œโ”€โ”€ dri_analysis.py # DRIs ่ฅๅ…ป็ด ๅฏนๆฏ”ๅˆ†ๆž
371
+ โ”‚ โ”œโ”€โ”€ briefing_generator.py # ไปŠๆ—ฅ็ฎ€ๆŠฅ็”Ÿๆˆๅ™จ
372
+ โ”‚ โ””โ”€โ”€ preset_writer.py # ้ข„่ฎพๆ–‡ไปถๅ†™ๅ…ฅ
373
+ โ”‚
374
+ โ”œโ”€โ”€ core/ # AI ๆ ธๅฟƒๅฑ‚๏ผˆ็ญ‰ๅพ… MiniCPM-o ้ƒจ็ฝฒ๏ผ‰
375
+ โ”‚ โ”œโ”€โ”€ __init__.py
376
+ โ”‚ โ”œโ”€โ”€ model_loader.py # ๆจกๅž‹ๅŠ ่ฝฝๅ™จ๏ผˆ็ฉบๆŽฅๅฃ๏ผ‰
377
+ โ”‚ โ”œโ”€โ”€ voice_processor.py # ่ฏญ้Ÿณๅค„็†ๅ™จ๏ผˆ็ฉบๆŽฅๅฃ๏ผ‰
378
+ โ”‚ โ”œโ”€โ”€ vision_processor.py # ่ง†่ง‰ๅค„็†ๅ™จ๏ผˆ็ฉบๆŽฅๅฃ๏ผ‰
379
+ โ”‚ โ””โ”€โ”€ conversation_manager.py # ๅฏน่ฏ็ฎก็†ๅ™จ๏ผˆ็ฉบๆŽฅๅฃ๏ผ‰
380
+ โ”‚
381
+ โ”œโ”€โ”€ modules/ # ไธšๅŠก้€ป่พ‘ๅฑ‚
382
+ โ”‚ โ”œโ”€โ”€ __init__.py
383
+ โ”‚ โ”œโ”€โ”€ voiceprint.py # ๅฃฐ็บน่ฏ†ๅˆซ
384
+ โ”‚ โ”œโ”€โ”€ meal_recommender.py # ่œๅ“ๆŽจ่
385
+ โ”‚ โ”œโ”€โ”€ diet_logger.py # ้ฅฎ้ฃŸ่ฎฐๅฝ• + Markdown ็”Ÿๆˆ
386
+ โ”‚ โ””โ”€โ”€ nutrition_analyzer.py # ่ฅๅ…ปๅˆ†ๆž + ๅฏ่ง†ๅŒ–
387
+ โ”‚
388
+ โ”œโ”€โ”€ ui/ # ่กจ็Žฐๅฑ‚
389
+ โ”‚ โ”œโ”€โ”€ __init__.py
390
+ โ”‚ โ””โ”€โ”€ app_builder.py # Gradio ็•Œ้ข + ไบ‹ไปถ็ป‘ๅฎš
391
+ โ”‚
392
+ โ”œโ”€โ”€ data/ # ๆ•ฐๆฎๅญ˜ๅ‚จ
393
+ โ”‚ โ”œโ”€โ”€ nutrition/
394
+ โ”‚ โ”‚ โ””โ”€โ”€ raw/ # โ† ไฝ ๅทฒไธ‹่ฝฝ็š„ไธ‰ไธช MD ๆ–‡ไปถ
395
+ โ”‚ โ”‚ โ”œโ”€โ”€ ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผๆ ‡ๅ‡†.md
396
+ โ”‚ โ”‚ โ”œโ”€โ”€ ไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณ่†ณ้ฃŸๆŒ‡ๅ—2022ๅ›พ็‰‡่ฝฌmd็‰ˆ.md
397
+ โ”‚ โ”‚ โ””โ”€โ”€ ๅค‡ๅญ•&ๅญ•ๆ—ฉไธญๆ™šไธ‰ๆœŸๅ’Œๅ“บไนณๆœŸ็š„ๆ‰€ๆœ‰่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡.md
398
+ โ”‚ โ”œโ”€โ”€ presets/ โ† ๐Ÿ†• ๆ–ฐๅขž # ๆฏๆ—ฅ็ฎ€ๆŠฅ / ้ข„่ฎพๆ–‡ไปถ
399
+ โ”‚ โ”œโ”€โ”€ voices/ # ๅฃฐ็บนๆ•ฐๆฎ
400
+ โ”‚ โ”œโ”€โ”€ logs/ # Markdown ้ฅฎ้ฃŸๆ—ฅๅฟ—
401
+ โ”‚ โ””โ”€โ”€ reports/ # ๅฏผๅ‡บๆŠฅๅ‘Š
402
+ โ”‚
403
+ โ”œโ”€โ”€ docs/
404
+ โ”‚ โ”œโ”€โ”€ ้กน็›ฎ็†่งฃ_ๆŠ€ๆœฏๆžถๆž„.md # โ† ๆœฌๆ–‡ๆกฃ
405
+ โ”‚ โ””โ”€โ”€ ๅผ€ๅ‘ๆ—ฅๅฟ—.md
406
+ โ”‚
407
+ โ”œโ”€โ”€ requirements.txt # ไพ่ต–ๆธ…ๅ•
408
+ โ””โ”€โ”€ README.md
409
+ ```
410
+
411
+ > **ๆ‰นๆณจ๏ผš** ________
412
+
413
+ ---
414
+
415
+ ## ๅ…ญใ€ๆ•ฐๆฎๆตๅ…จๆ™ฏ
416
+
417
+ ```
418
+ data/nutrition/raw/
419
+ โ”œโ”€โ”€ ไฝ“้‡ๆ ‡ๅ‡†.md โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
420
+ โ”œโ”€โ”€ ่†ณ้ฃŸๆŒ‡ๅ—.md โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
421
+ โ””โ”€โ”€ DRIs.md โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
422
+ โ”‚
423
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
424
+ โ”‚ data/presets/ โ”‚
425
+ โ”‚ (็ผ“ๅญ˜็ผ–่ฏ‘ๅŽ็š„็ป“ๆž„ๅŒ–ๆ•ฐๆฎ) โ”‚
426
+ โ”‚ ไฝ“้‡ๆ ‡ๅ‡†.json ่†ณ้ฃŸๆŒ‡ๅ—.json DRIs.json โ”‚
427
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
428
+ โ”‚
429
+ โ–ผ
430
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
431
+ โ”‚ loop.py โ”‚
432
+ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
433
+ โ”‚ โ”‚ ็Šถๆ€ๆœบ้ฉฑๅŠจ (LAUNCHโ†’SUMMARIZEโ†’ANALYZEโ†’BRIEF) โ”‚ โ”‚
434
+ โ”‚ โ”‚ โ†“ ไพๆฌก่ฐƒ็”จ Plugin โ”‚ โ”‚
435
+ โ”‚ โ”‚ diet_summary โ†’ weight_check โ†’ dri_analysis โ”‚ โ”‚
436
+ โ”‚ โ”‚ โ†“ โ”‚ โ”‚
437
+ โ”‚ โ”‚ briefing_generator โ”‚ โ”‚
438
+ โ”‚ โ”‚ โ†“ โ”‚ โ”‚
439
+ โ”‚ โ”‚ data/presets/ไปŠๆ—ฅ็ฎ€ๆŠฅ.json โ”‚ โ”‚
440
+ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
441
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
442
+ โ”‚
443
+ โ–ผ
444
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
445
+ โ”‚ ui/app_builder.py (Gradio ็•Œ้ข) โ”‚
446
+ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
447
+ โ”‚ โ”‚ Tab1 ๅฃฐ็บน่ฏ†ๅˆซ โ”‚ Tab2 ่œๅ“ๆŽจ่ โ”‚ Tab3 ้ฅฎ้ฃŸ่ฎฐๅฝ• โ”‚ โ”‚
448
+ โ”‚ โ”‚ Tab4 ่ฅๅ…ปๆŠฅๅ‘Š โ”‚ Tab5 ๅ…ณไบŽ โ”‚ โ”‚
449
+ โ”‚ โ”‚ โ”‚ โ”‚
450
+ โ”‚ โ”‚ ไปŠๆ—ฅ็ฎ€ๆŠฅๆณจๅ…ฅๅฏน่ฏไธŠไธ‹ๆ–‡ โ”‚ โ”‚
451
+ โ”‚ โ”‚ AI ็Ÿฅ้“๏ผšไปŠๅคฉ่ฏฅๅ…ณๆณจไป€ไนˆ่ฅๅ…ป็ด  โ”‚ โ”‚
452
+ โ”‚ โ”‚ ่ฏฅ้—ฎ่ฐไฝ“้‡๏ผŸ่ฏฅ่Šไป€ไนˆ่ฏ้ข˜๏ผŸ โ”‚ โ”‚
453
+ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
454
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
455
+ โ”‚
456
+ โ–ผ
457
+ modules/diet_logger.py (่ฎฐๅฝ•ๆ–ฐๆ•ฐๆฎ)
458
+ modules/meal_recommender.py (่†ณ้ฃŸๆŒ‡ๅ—็บฆๆŸ)
459
+ modules/nutrition_analyzer.py (DRIs ๅฏนๆฏ”)
460
+ โ”‚
461
+ โ–ผ
462
+ ๆฌกๆ—ฅ loop.py ๅ†ๆฌกๅฏๅŠจ โ†’ ๅพช็Žฏ
463
+ ```
464
+
465
+ > **ๆ‰นๆณจ๏ผš** ________
466
+
467
+ ---
468
+
469
+ ## ไธƒใ€ๆŠ€ๆœฏๆ ˆไธ€่งˆ
470
+
471
+ | ๅฑ‚็บง | ๆŠ€ๆœฏ | ็”จ้€” |
472
+ |------|------|------|
473
+ | ๆ ธๅฟƒๆจกๅž‹ | **MiniCPM-o 4.5**๏ผˆ็ปŸไธ€ๅคšๆจกๆ€ๆจกๅž‹๏ผ‰ | ๅ…จๅŒๅทฅๆŽจ็†๏ผš่ง†่ง‰+่ฏญ้Ÿณ+ๆ–‡ๆœฌ+่ฏญ้Ÿณ่พ“ๅ‡บ |
474
+ | ๅ‰็ซฏๆก†ๆžถ | **Gradio 6.x** | Web ็•Œ้ข๏ผŒๅฎžๆ—ถๅฏน่ฏไบคไบ’ |
475
+ | ๅฃฐ็บน่ฏ†ๅˆซ | Whisper-medium encoder embedding๏ผˆไผ˜ๅ…ˆ๏ผ‰| ่ฏด่ฏไบบ่บซไปฝ่ฏ†ๅˆซ |
476
+ | ้ข‘่ฐฑๆ–นๆกˆ | NumPy + SoundFile๏ผˆๅค‡้€‰ fallback๏ผ‰ | ๅฃฐ็บน่ฏ†ๅˆซๅ…œๅบ• |
477
+ | ๆ•ฐๆฎๅญ˜ๅ‚จ | JSON + Markdown | ้ฅฎ้ฃŸ่ฎฐๅฝ• + ๆŠฅๅ‘Šๅญ˜ๆกฃ + ๆฏๆ—ฅ็ฎ€ๆŠฅ |
478
+ | ่ฅๅ…ปๆ ‡ๅ‡† | ไธ‰ไธช MD ๆ–‡ไปถ๏ผˆๅทฒไธ‹่ฝฝ๏ผ‰ | ไฝ“้‡ๆ ‡ๅ‡†/่†ณ้ฃŸๆŒ‡ๅ—/DRIs |
479
+ | ๅพช็Žฏๅผ•ๆ“Ž | ่‡ช็ ”็Šถๆ€ๆœบ + ๆ’ไปถๆณจๅ†Œ | ๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ็ฎก็† |
480
+ | ้ƒจ็ฝฒๅนณๅฐ | HuggingFace Spaces๏ผˆ็›ฎๅ‰๏ผ‰+ Modal๏ผˆๅŽ็ปญ๏ผ‰ | ไบ‘็ซฏ้ƒจ็ฝฒ |
481
+
482
+ > **ๆ‰นๆณจ๏ผš** ________
483
+
484
+ ---
485
+
486
+ ## ๅ…ซใ€ๅพ…่ฎจ่ฎบ้—ฎ้ข˜ๆธ…ๅ•
487
+
488
+ > ๐Ÿ“ ไธ‹่กจๆฑ‡ๆ€ปไบ†ๆœฌๆ–‡ๆกฃไธญ้œ€่ฆไฝ ๅ†ณ็ญ–็š„้—ฎ้ข˜ใ€‚่ฏทๅœจ `____` ๅค„ๆ ‡ๆณจไฝ ็š„ๆ„่ง๏ผˆๅฆ‚้œ€ๆ›ดๅคš่ฎจ่ฎบ๏ผŒๅœจๅฏนๅบ”ๅฐ่Š‚ๆ‰นๆณจๅŒบ่กฅๅ……๏ผ‰ใ€‚
489
+
490
+ | # | ้—ฎ้ข˜ | ไฝ ็š„้€‰ๆ‹ฉ / ๆ„่ง |
491
+ |---|------|----------------|
492
+ | 1 | **Loop ๅฏๅŠจๆ—ถๆœบ**๏ผšGradio ๅฏๅŠจๆ—ถๅ…ˆ่ท‘ๅฎŒ Loop ๆ€ป็ป“้˜ถๆฎตๅ†ๅผ€ๆœๅŠก๏ผˆA๏ผ‰/ ็”จๆˆทๆ‰“ๅผ€้กต้ขๆ—ถๆ‰่งฆๅ‘๏ผˆB๏ผ‰ | ________ |
493
+ | 2 | **็ฎ€ๆŠฅๆ‰ฟ่ฝฝๅฝขๅผ**๏ผšJSON ๆ–‡ไปถ่ฝ็›˜ไฝœไธบไธญไป‹๏ผˆA๏ผ‰/ ไป…ๅ†…ๅญ˜ๅ˜้‡ไธ่ฝ็›˜๏ผˆB๏ผ‰ | ________ |
494
+ | 3 | **Loop ๅคๆ‚ๅบฆ่พน็•Œ**๏ผšๅช้œ€็ฎกๅฅฝๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ 3~5 ไธช้˜ถๆฎต๏ผŒ็บฆ 200~300 ่กŒ๏ผˆๅŒๆ„๏ผ‰/ ้œ€่ฆๆ›ดๅคๆ‚๏ผˆ่ฏท่ฏดๆ˜Ž๏ผ‰ | ________ |
495
+ | 4 | **ๆ’ไปถไผ˜ๅ…ˆ็บง**๏ผšDietSummary P0 / WeightCheck P0 / DRIAnalysis P0 / BriefingGenerator P0 / PresetWriter P1๏ผˆ้œ€่ฆ่ฐƒๆ•ด๏ผŸ๏ผ‰ | ________ |
496
+ | 5 | **ไฝ“้‡ๆ•ฐๆฎๆฅๆบ**๏ผš็”จๆˆทๆ‰‹ๅŠจ่พ“ๅ…ฅ๏ผˆA๏ผ‰/ ่ฏญ้Ÿณๅฏน่ฏ AI ่ฏข้—ฎ่ฎฐๅฝ•๏ผˆB๏ผ‰/ ่“็‰™ๅŒๆญฅๆœชๆฅๆ‰ฉๅฑ•๏ผˆC๏ผ‰ | ________ |
497
+ | 6 | **core/ ๅฑ‚ๅค„็†**๏ผš็Žฐ้˜ถๆฎต Loop ็›ดๆŽฅ่ฐƒ็”จ modules/ ่ง„ๅˆ™ๅผ•ๆ“Ž๏ผŒcore/ ไฟๆŒ็ฉบๆŽฅๅฃ็ญ‰ MiniCPM-o๏ผˆๅŒๆ„๏ผŸ๏ผ‰ | ________ |
498
+ | 7 | **่ฟ˜ๆœ‰ไป€ไนˆๆˆ‘ๆฒก่€ƒ่™‘ๅˆฐ็š„้—ฎ้ข˜๏ผŸ** | ________ |
499
+
500
+ ---
501
+
502
+ *ๆ–‡ๆกฃ็”Ÿๆˆๆ—ถ้—ด๏ผš2026-06-08 | v4 - ๅผ•ๅ…ฅ Loop ้ฉฑๅŠจๆžถๆž„ + ไธ‰ๆ–‡ๆกฃๆ“ไฝœๆ–นๆกˆ*
data/diet_logs.json ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema_version": "1.0",
3
+ "records": [
4
+ {
5
+ "id": "rec001",
6
+ "member_name": "ๅฐ็บข",
7
+ "member_relation": "ๅญ•ๅฆ‡",
8
+ "date": "2026-06-07",
9
+ "meals": {
10
+ "ๆ—ฉ้ค": "ๅ…จ้บฆ้ขๅŒ…+้ธก่›‹+็‰›ๅฅถ",
11
+ "ๅˆ้ค": "็•ช่Œ„็‰›่…ฉ+็ฑณ้ฅญ",
12
+ "ๆ™š้ค": "้ฒซ้ฑผ่ฑ†่…ๆฑค+ๅฐ้ฆ’ๅคด",
13
+ "ๅŠ ้ค": "่‹นๆžœ+้…ธๅฅถ"
14
+ },
15
+ "mood": "ๅฟƒๆƒ…ไธ้”™",
16
+ "notes": "ไปŠๅคฉ่ƒƒๅฃๅพˆๅฅฝ",
17
+ "extensions": {},
18
+ "created_at": "2026-06-07T20:00:00"
19
+ },
20
+ {
21
+ "id": "rec002",
22
+ "member_name": "ๅฐ็บข",
23
+ "member_relation": "ๅญ•ๅฆ‡",
24
+ "date": "2026-06-08",
25
+ "meals": {
26
+ "ๆ—ฉ้ค": "ๅฐ็ฑณ็ฒฅ+ๅŒ…ๅญ",
27
+ "ๅˆ้ค": "ๆธ…็‚’่ฅฟๅ…ฐ่Šฑ+็ณ™็ฑณ้ฅญ",
28
+ "ๆ™š้ค": "็•ช่Œ„็‚’่›‹+็ฑณ้ฅญ",
29
+ "ๅŠ ้ค": "ๅšๆžœ+ๆฉ™ๅญ"
30
+ },
31
+ "mood": "ๆœ‰็‚นๅญ•ๅ",
32
+ "notes": "ๆ™šไธŠๆœ‰็‚นไธ่ˆ’ๆœ",
33
+ "extensions": {},
34
+ "created_at": "2026-06-08T20:00:00"
35
+ },
36
+ {
37
+ "id": "rec003",
38
+ "member_name": "ๅฐ็บข",
39
+ "member_relation": "ๅญ•ๅฆ‡",
40
+ "date": "2026-06-09",
41
+ "meals": {
42
+ "ๆ—ฉ้ค": "็‡•้บฆ็ฒฅ+้ธก่›‹",
43
+ "ๅˆ้ค": "ๆธ…่’ธ้ฒˆ้ฑผ+ๆ‚็ฒฎ้ฅญ",
44
+ "ๆ™š้ค": "็บขๆžฃๆžธๆž้ธกๆฑค",
45
+ "ๅŠ ้ค": "็Œ•็Œดๆกƒ+็‰›ๅฅถ"
46
+ },
47
+ "mood": "ๆŒบๅฅฝ",
48
+ "notes": "ๆƒณๅƒ้…ธ็š„",
49
+ "extensions": {},
50
+ "created_at": "2026-06-09T12:00:00"
51
+ }
52
+ ]
53
+ }
data/family/memory.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ๅฎถๅบญ่ฎฐๅฟ†
2
+
3
+ > ่ฎฐๅฝ•ๅฎถๅบญๅ…ณ็ณปใ€้‡่ฆไบ‹ไปถใ€ๆ—ฅๅธธ็‚นๆปดใ€‚
4
+
5
+ ## ๅฎถๅบญๅ…ณ็ณป
6
+
7
+ - **ๅฐ็บข**: ๅญ•ๅฆ‡๏ผŒๅญ•ไธญๆœŸ
8
+ - **ๅฐๆ˜Ž**: ไธˆๅคซ๏ผŒ่ดŸ่ดฃๅš้ฅญ
9
+ - **ๅผ ้˜ฟๅงจ**: ๅฉ†ๅฉ†๏ผŒๅธฎๅฟ™็…ง้กพ
10
+
11
+ ## ้‡่ฆไบ‹ไปถ
12
+
13
+ - **2026-06-07**: ไธˆๅคซๅšไบ†็•ช่Œ„็‰›่…ฉ๏ผŒๅญ•ๅฆ‡่ฏดๅพˆๅฅฝๅƒ
14
+ - **2026-06-08**: ๅฉ†ๅฉ†็…ฒไบ†้ฒซ้ฑผ่ฑ†่…ๆฑค๏ผŒๅญ•ๅฆ‡ๅ–ไบ†ไธค็ข—
15
+ - **2026-06-09**: ๅญ•ๅฆ‡่ฏดๆƒณๅƒๆธ…่’ธ้ฒˆ้ฑผ
16
+
17
+ ## ๆ—ฅๅธธ่ฎฐๅฝ•
18
+
19
+ - **2026-06-07**: ๅญ•ๅฆ‡ไปŠๅคฉๅฟƒๆƒ…ไธ้”™๏ผŒๅƒไบ†ๅพˆๅคšๆฐดๆžœ
20
+ - **2026-06-08**: ๅญ•ๅฆ‡ๆœ‰็‚นๅญ•ๅ๏ผŒไฝ†ๅšๆŒๅƒไบ†ๆ™š้ฅญ
21
+ - **2026-06-09**: ๅญ•ๅฆ‡่ฏดๆœ€่ฟ‘ๆƒณๅƒ้…ธ็š„
data/family/preferences.md ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ๅฎถๅบญๆˆๅ‘˜้ฅฎ้ฃŸๅๅฅฝ
2
+
3
+ > ่ฎฐๅฝ•ๆ‰€ๆœ‰ๅฎถไบบ็š„้ฅฎ้ฃŸๅๅฅฝใ€ๅฟŒๅฃใ€่ฟ‡ๆ•ไฟกๆฏใ€‚
4
+
5
+ ## ๆˆๅ‘˜ๅˆ—่กจ
6
+
7
+ ### ๆˆๅ‘˜๏ผšๅฐ็บข๏ผˆๅญ•ๅฆ‡๏ผ‰
8
+ - **ๅๅฅฝ**: ็ˆฑๅƒๆฐดๆžœใ€็ˆฑๅƒ้ฑผใ€็ˆฑๅƒๆธ…ๆทก
9
+ - **ๅฟŒๅฃ**: ไธๅƒ่พฃใ€ไธๅƒๆฒน่…ป
10
+ - **่ฟ‡ๆ•**: ่Š’ๆžœ
11
+ - **ๅค‡ๆณจ**: ๅญ•ไธญๆœŸ๏ผŒ้œ€่ฆ่กฅ้’™
12
+
13
+ ### ๆˆๅ‘˜๏ผšๅฐๆ˜Ž๏ผˆไธˆๅคซ๏ผ‰
14
+ - **ๅๅฅฝ**: ็ˆฑๅƒ่‚‰ใ€็ˆฑๅƒ้ข้ฃŸ
15
+ - **ๅฟŒๅฃ**: ไธๅƒ้ฆ™่œ
16
+ - **่ฟ‡ๆ•**:
17
+ - **ๅค‡ๆณจ**:
18
+
19
+ ### ๆˆๅ‘˜๏ผšๅผ ้˜ฟๅงจ๏ผˆๅฉ†ๅฉ†๏ผ‰
20
+ - **ๅๅฅฝ**: ไผšๅšๅ„็งๆฑค
21
+ - **ๅฟŒๅฃ**:
22
+ - **่ฟ‡ๆ•**:
23
+ - **ๅค‡ๆณจ**: ๆ“…้•ฟ็…ฒๆฑค
data/family/recipes.md ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ๅฎถๅบญ่œ่ฐฑ
2
+
3
+ > ่ฎฐๅฝ•ๅฎถไบบไผšๅš็š„่œใ€‚
4
+
5
+ ## ่œ่ฐฑๅˆ—่กจ
6
+
7
+ ### ็•ช่Œ„็‰›่…ฉ
8
+ - **ๅˆถไฝœไบบ**: ไธˆๅคซ
9
+ - **้šพๅบฆ**: ไธญ็ญ‰
10
+ - **้ฃŸๆ**: ็•ช่Œ„, ็‰›่…ฉ, ๅœŸ่ฑ†, ่ƒก่ๅœ
11
+ - **ๅค‡ๆณจ**: ๅญ•ๅฆ‡็ˆฑๅƒ
12
+
13
+ ### ๆธ…่’ธ้ฒˆ้ฑผ
14
+ - **ๅˆถไฝœไบบ**: ไธˆๅคซ
15
+ - **้šพๅบฆ**: ็ฎ€ๅ•
16
+ - **้ฃŸๆ**: ้ฒˆ้ฑผ, ่‘ฑ, ๅงœ, ่’ธ้ฑผ่ฑ‰ๆฒน
17
+ - **ๅค‡ๆณจ**: ๆธ…ๆทกๅฅๅบท
18
+
19
+ ### ้ฒซ้ฑผ่ฑ†่…ๆฑค
20
+ - **ๅˆถไฝœไบบ**: ๅฉ†ๅฉ†
21
+ - **้šพๅบฆ**: ็ฎ€ๅ•
22
+ - **้ฃŸๆ**: ้ฒซ้ฑผ, ่ฑ†่…, ๅงœ, ่‘ฑ
23
+ - **ๅค‡ๆณจ**: ไธ‹ๅฅถ
24
+
25
+ ### ็•ช่Œ„็‚’่›‹
26
+ - **ๅˆถไฝœไบบ**: ไธˆๅคซ
27
+ - **้šพๅบฆ**: ็ฎ€ๅ•
28
+ - **้ฃŸๆ**: ็•ช่Œ„, ้ธก่›‹, ่‘ฑ
29
+ - **ๅค‡ๆณจ**:
30
+
31
+ ### ็บขๆžฃๆžธๆž้ธกๆฑค
32
+ - **ๅˆถไฝœไบบ**: ๅฆˆๅฆˆ
33
+ - **้šพๅบฆ**: ไธญ็ญ‰
34
+ - **้ฃŸๆ**: ้ธก, ็บขๆžฃ, ๆžธๆž, ๅงœ
35
+ - **ๅค‡ๆณจ**: ่กฅๆฐ”่ก€
data/nutrition/raw/ไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณ่†ณ้ฃŸๆŒ‡ๅ—2022ๅ›พ็‰‡่ฝฌmd็‰ˆ.md CHANGED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ไธญๅ›ฝๅค‡ๅญ•ๅฆ‡ๅฅณๅนณ่กก่†ณ้ฃŸๅฎๅก”
2
+
3
+ ## ๅค‡ๅญ•ๆ ธๅฟƒๅปบ่ฎฎ
4
+ - ๅถ้…ธ่กฅๅ……ๅ‰‚0.4ๆฏซๅ…‹/ๅคฉ
5
+ - ่ดซ่ก€่€…ๅœจๅŒป็”ŸๆŒ‡ๅฏผไธ‹่กฅๅ……้“ๅ‰‚
6
+ - ๆฏๅคฉ30ๅˆ†้’ŸไปฅไธŠไธญ็ญ‰ๅผบๅบฆ่ฟๅŠจ
7
+ - ็›‘ๆต‹ไฝ“้‡๏ผŒ่ฐƒๆ•ดไฝ“้‡่‡ณ้€‚ๅฎœ่Œƒๅ›ด
8
+ - ๆ„‰ๆ‚ฆๅฟƒๆƒ…๏ผŒๅ……่ถณ็ก็œ 
9
+ - ้ฅฎๆดๅ‡€ๆฐด๏ผŒๅฐ‘ๅ–ๅซ็ณ–้ฅฎๆ–™
10
+ - ไธๅธ็ƒŸ๏ผŒ่ฟœ็ฆปไบŒๆ‰‹็ƒŸ
11
+ - ไธ้ฅฎ้…’
12
+
13
+ ---
14
+
15
+ ## ้ฃŸ็‰ฉๆŽจ่้‡
16
+ 1. **ๅŠ ็ข˜้ฃŸ็›**๏ผš5ๅ…‹
17
+ 2. **ๆฒน**๏ผš25ๅ…‹
18
+ 3. **ๅฅถ็ฑป**๏ผš300ๅ…‹
19
+ 4. **ๅคง่ฑ†/ๅšๆžœ**๏ผš15ๅ…‹ / 10ๅ…‹
20
+ 5. **่‚‰้ฃŸ่›‹้ฑผ็ฑป**๏ผš130-180ๅ…‹
21
+ - ็•œ็ฆฝ่‚‰๏ผš40-65ๅ…‹
22
+ - ้ฑผ่™พ็ฑป๏ผš40-65ๅ…‹
23
+ - ่›‹็ฑป๏ผš50ๅ…‹๏ผˆๆฏๅคฉไธ€ๆฌก๏ผŒ็บฆ1ไธช้ธก่›‹๏ผ‰
24
+ 6. **่”ฌ่œ็ฑป**๏ผš300-500ๅ…‹๏ผˆๅฏๆฏๅคฉ่‡ณๅฐ‘ไธ€ๆฌกๆทฑ็ปฟ่‰ฒ่”ฌ่œ๏ผ‰
25
+ 7. **ๆฐดๆžœ็ฑป**๏ผš200-300ๅ…‹
26
+ 8. **่ฐท็ฑป**๏ผš200-250ๅ…‹
27
+ - โ€”โ€”ๅ…จ่ฐท็‰ฉๅ’Œๆ‚่ฑ†๏ผš75-130ๅ…‹
28
+ 9. **่–ฏ็ฑป**๏ผš50ๅ…‹
29
+ 10. **ๆฐด**๏ผš1500-1700ๆฏซๅ‡
30
+
31
+
32
+ ---
33
+
34
+
35
+ # ไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณๅนณ่กก่†ณ้ฃŸๅฎๅก”
36
+
37
+ ## ๅทฆไพง้€š็”จๅปบ่ฎฎ
38
+ - ๅถ้…ธ่กฅๅ……ๅ‰‚0.4ๆฏซๅ…‹/ๅคฉ
39
+ - ่ดซ่ก€ไธฅ้‡่€…ๅœจๅŒป็”ŸๆŒ‡ๅฏผไธ‹่กฅๅ……้“ๅ‰‚
40
+ - ้€‚ๅบฆ่ฟๅŠจ๏ผŒ็ปๅธธๆˆทๅค–ๆดปๅŠจ
41
+ - ๆฏๅ‘จๆต‹้‡ไฝ“้‡๏ผŒ็ปดๆŒๅญ•ๆœŸ้€‚ๅฎœๅขž้‡
42
+ - ๆ„‰ๆ‚ฆๅฟƒๆƒ…๏ผŒๅ……่ถณ็ก็œ 
43
+ - ้ฅฎๆดๅ‡€ๆฐด๏ผŒๅฐ‘ๅ–ๅซ็ณ–้ฅฎๆ–™
44
+ - ๅ‡†ๅค‡ๆฏไนณๅ–‚ๅ…ป
45
+ - ไธๅธ็ƒŸ๏ผŒ่ฟœ็ฆปไบŒๆ‰‹็ƒŸ
46
+ - ไธ้ฅฎ้…’
47
+
48
+ ---
49
+
50
+ ## ๅณไพง้ฃŸ็‰ฉๆŽจ่้‡
51
+ | ้ฃŸ็‰ฉ็ฑปๅˆซ | ๅญ•ไธญๆœŸ | ๅญ•ๆ™šๆœŸ |
52
+ | :--- | :--- | :--- |
53
+ | ๅŠ ็ข˜้ฃŸ็› | 5ๅ…‹ | 5ๅ…‹ |
54
+ | ๆฒน | 25ๅ…‹ | 25ๅ…‹ |
55
+ | ๅฅถ็ฑป | 300-500ๅ…‹ | 300-500ๅ…‹ |
56
+ | ๅคง่ฑ†/ๅšๆžœ | 20ๅ…‹/10ๅ…‹ | 20ๅ…‹/10ๅ…‹ |
57
+ | ้ฑผ็ฆฝ่›‹่‚‰็ฑป | 150-200ๅ…‹ | 175-225ๅ…‹ |
58
+ | - ็•œ็ฆฝ่‚‰็ฑป | 50-75ๅ…‹ | 50-75ๅ…‹ |
59
+ | - ้ฑผ่™พ็ฑป | 50-75ๅ…‹๏ผˆๆฏๅ‘จ2-3ๆฌก๏ผŒๅ…ถไธญ1ๆฌกไธบๆทฑๆตท้ฑผ๏ผ‰ | 75-100ๅ…‹ |
60
+ | - ่›‹็ฑป | 50ๅ…‹ | 50ๅ…‹ |
61
+ | ่”ฌ่œ็ฑป | 400-500ๅ…‹๏ผˆๆฏๅคฉ่‡ณๅฐ‘ไธ€ๆฌกๆทฑ็ปฟ่‰ฒ่”ฌ่œ๏ผ‰ | 400-500ๅ…‹ |
62
+ | ๆฐดๆžœ็ฑป | 200-300ๅ…‹ | 200-350ๅ…‹ |
63
+ | ่ฐท็ฑป | 200-250ๅ…‹ | 225-275ๅ…‹ |
64
+ | - ๅ…จ่ฐท็‰ฉๅ’Œๆ‚่ฑ† | 75-100ๅ…‹ | 75-125ๅ…‹ |
65
+ | ่–ฏ็ฑป | 75ๅ…‹ | 75ๅ…‹ |
66
+ | ๆฐด | 1700ๆฏซๅ‡ | 1700ๆฏซๅ‡ |
67
+
68
+
69
+ 1. **่ฐƒๆ•ดๅญ•ๅ‰ไฝ“้‡่‡ณๆญฃๅธธ่Œƒๅ›ด๏ผŒไฟ่ฏๅญ•ๆœŸไฝ“้‡้€‚ๅฎœๅขž้•ฟ**
70
+ 2. **ๅธธๅƒๅซ้“ไธฐๅฏŒ็š„้ฃŸ็‰ฉ๏ผŒ้€‰็”จ็ข˜็›๏ผŒๅˆ็†่กฅๅ……ๅถ้…ธๅ’Œ็ปด็”Ÿ็ด D**
71
+ 3. **ๅญ•ๅไธฅ้‡่€…๏ผŒๅฏๅฐ‘้‡ๅคš้ค๏ผŒไฟ่ฏๆ‘„ๅ…ฅๅซๅฟ…้œ€้‡็ขณๆฐดๅŒ–ๅˆ็‰ฉ็š„้ฃŸ็‰ฉ**
72
+ 4. **ๅญ•ไธญๆ™šๆœŸ้€‚้‡ๅขžๅŠ ๅฅถใ€้ฑผใ€็ฆฝใ€่›‹ใ€็˜ฆ่‚‰็š„ๆ‘„ๅ…ฅ**
73
+ 5. **็ปๅธธๆˆทๅค–ๆดปๅŠจ๏ผŒ็ฆ็ƒŸ้…’๏ผŒไฟๆŒๅฅๅบท็”Ÿๆดปๆ–นๅผ**
74
+ 6. **ๆ„‰ๅฟซๅญ•่‚ฒๆ–ฐ็”Ÿๅ‘ฝ๏ผŒ็งฏๆžๅ‡†ๅค‡ๆฏไนณๅ–‚ๅ…ป**
75
+
76
+ ---
77
+
78
+
79
+
80
+ # ไธญๅ›ฝๅ“บไนณๆœŸๅฆ‡ๅฅณๅนณ่กก่†ณ้ฃŸๅฎๅก”
81
+
82
+ ---
83
+
84
+ ## ๅทฆไพง็”Ÿๆดปๅปบ่ฎฎ
85
+ - ๅšๆŒๅ“บไนณ
86
+ - ้€‚ๅฝ“ๅขžๅŠ ้ฑผ็ฆฝ่‚‰่›‹ๅ’Œๆตทไบงๅ“
87
+ - ๆ„‰ๆ‚ฆๅฟƒๆƒ…๏ผŒๅ……่ถณ็ก็œ 
88
+ - ่ถณ้‡้ฅฎๆฐด๏ผŒ้€‚ๅฝ“ๅคšๅ–็ฒฅใ€ๆฑค
89
+ - ้€‚ๅบฆ่ฟๅŠจ
90
+ - ๆฏๅ‘จๆต‹้‡ไฝ“้‡๏ผŒ้€ๆญฅๆขๅค้€‚ๅฎœไฝ“้‡
91
+ - ไธๅธ็ƒŸ๏ผŒ่ฟœ็ฆปไบŒๆ‰‹็ƒŸ
92
+ - ไธ้ฅฎ้…’
93
+
94
+ ---
95
+
96
+ ## ๅณไพง้ฃŸ็‰ฉๆŽจ่้‡
97
+ | ้ฃŸ็‰ฉ็ฑปๅˆซ | ๆฏๆ—ฅๆŽจ่ๆ‘„ๅ…ฅ้‡ | ่กฅๅ……่ฏดๆ˜Ž |
98
+ | :--- | :--- | :--- |
99
+ | ๅŠ ็ข˜้ฃŸ็› | 5ๅ…‹ | - |
100
+ | ๆฒน | 25ๅ…‹ | - |
101
+ | ๅฅถ็ฑป | 300-500ๅ…‹ | - |
102
+ | ๅคง่ฑ†/ๅšๆžœ | 25ๅ…‹/10ๅ…‹ | - |
103
+ | ้ฑผ็ฆฝ่›‹่‚‰็ฑป | 175-225ๅ…‹ | - |
104
+ | - ็•œ็ฆฝ่‚‰็ฑป | 50-75ๅ…‹ | - |
105
+ | - ้ฑผ่™พ็ฑป | 75-100ๅ…‹ | ๆฏๅ‘จ1-2ๆฌก้ฃŸ็‰ฉไธญๅŒ…ๅซ50gไปฅไธŠ็š„้ฑผ็ฑปๆˆ–่ด็ฑป |
106
+ | - ่›‹็ฑป | 50ๅ…‹ | - |
107
+ | ่”ฌ่œ็ฑป | 400-500ๅ…‹ | ๆฏๅคฉ่‡ณๅฐ‘ไธ€ๆฌกๆทฑ็ปฟ่‰ฒ่”ฌ่œ |
108
+ | ๆฐดๆžœ็ฑป | 200-350ๅ…‹ | - |
109
+ | ่ฐท็ฑป | 225-275ๅ…‹ | - |
110
+ | - ๅ…จ่ฐท็‰ฉๅ’Œๆ‚่ฑ† | 75-125ๅ…‹ | - |
111
+ | ่–ฏ็ฑป | 75ๅ…‹ | - |
112
+ | ๆฐด | 2100ๆฏซๅ‡ | - |
113
+
114
+ - ๆณจ๏ผšๆœˆๅญ่†ณ้ฃŸไบฆ้€‚็”จ
115
+
116
+
117
+ 1. **ไบง่คฅๆœŸ้ฃŸ็‰ฉๅคšๆ ทไธ่ฟ‡้‡๏ผŒๅšๆŒๆ•ดไธชๅ“บไนณๆœŸ่ฅๅ…ปๅ‡่กก**
118
+ 2. **้€‚้‡ๅขžๅŠ ๅฏŒๅซไผ˜่ดจ่›‹็™ฝ่ดจๅŠ็ปด็”Ÿ็ด A็š„ๅŠจ็‰ฉๆ€ง้ฃŸ็‰ฉๅ’Œๆตทไบงๅ“๏ผŒ้€‰็”จ็ข˜็›๏ผŒๅˆ็†่กฅๅ……็ปด็”Ÿ็ด D**
119
+ 3. **ๅฎถๅบญๆ”ฏๆŒ๏ผŒๆ„‰ๆ‚ฆๅฟƒๆƒ…๏ผŒๅ……่ถณ็ก็œ ๏ผŒๅšๆŒๆฏไนณๅ–‚ๅ…ป**
120
+ 4. **ๅขžๅŠ ่บซไฝ“ๆดปๅŠจ๏ผŒไฟƒ่ฟ›ไบงๅŽๆขๅคๅฅๅบทไฝ“้‡**
121
+ 5. **ๅคšๅ–ๆฑคๅ’Œๆฐด๏ผŒ้™ๅˆถๆต“่Œถๅ’Œๅ’–ๅ•ก๏ผŒๅฟŒ็ƒŸ้…’**
122
+
123
+ ---
124
+
data/nutrition/raw/ๅค‡ๅญ•&ๅญ•ๆ—ฉไธญๆ™šไธ‰ๆœŸๅ’Œๅ“บไนณๆœŸ็š„ๆ‰€ๆœ‰่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡.md ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ไธ‹้ขๅฐ†**ๅ››ๅผ ่กจๆ ผๅ…จ้ƒจๆ‹†ๅˆ†ไธบใ€Œ่ƒฝ้‡ไธŽๅฎ้‡่ฅๅ…ป็ด ใ€็Ÿฟ็‰ฉ่ดจใ€็ปด็”Ÿ็ด ใ€ไธ‰ๅผ ็‹ฌ็ซ‹ๆ ‡ๅ‡† Markdown ่กจ**๏ผŒ่ฏญๆณ•้€š็”จใ€ๆ— ่ถ…ๅฎฝๅˆๅนถๅˆ—๏ผŒไธปๆต็ผ–่พ‘ๅ™จ/ๆ–‡ๆกฃๅทฅๅ…ทๅ‡ๅฏๆญฃๅธธๆธฒๆŸ“๏ผŒๅฏ็›ดๆŽฅๅ…จ้€‰ๅคๅˆถไฝฟ็”จใ€‚
2
+
3
+ # ่กจ15 ไธญๅ›ฝ18-49ๅฒๅญ•ๆœŸๅฅณๆ€ง๏ผˆๅญ•ๆ—ฉๆœŸ๏ผ‰่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡
4
+ ### ็ผฉ็•ฅ่ฏ่ฏดๆ˜Ž
5
+ - EAR๏ผšๅนณๅ‡้œ€่ฆ้‡
6
+ - RNI๏ผšๆŽจ่ๆ‘„ๅ…ฅ้‡
7
+ - AI๏ผš้€‚ๅฎœๆ‘„ๅ…ฅ้‡
8
+ - PI๏ผš้ข„้˜ฒ้žไผ ๆŸ“ๆ€งๆ…ขๆ€ง็—…ๅปบ่ฎฎๆ‘„ๅ…ฅ้‡
9
+ - UL๏ผšๅฏ่€ๅ—ๆœ€้ซ˜ๆ‘„ๅ…ฅ้‡
10
+ - AMDR๏ผšๅฎ้‡่ฅๅ…ป็ด ๅฏๆŽฅๅ—่Œƒๅ›ด
11
+ - PAL๏ผš่บซไฝ“ๆดปๅŠจๆฐดๅนณ
12
+
13
+ ### ไธ€ใ€่ƒฝ้‡ไธŽๅฎ้‡่ฅๅ…ป็ด 
14
+ | ่ƒฝ้‡/่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | AMDR | PI | UL |
15
+ | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
16
+ | ่ƒฝ้‡ PAL(I) | MJ/d | - | 7.11 | - | - | - |
17
+ | ่ƒฝ้‡ PAL(II) | MJ/d | - | 8.79 | - | - | - |
18
+ | ่ƒฝ้‡ PAL(III) | MJ/d | - | 10.25 | - | - | - |
19
+ | ่›‹็™ฝ่ดจ | g/d | 55 | - | 10~20% | - | - |
20
+ | ๆ€ป็ขณๆฐดๅŒ–ๅˆ็‰ฉ | %E | 130# | - | 50~65% | - | - |
21
+ | โ€” ๆทปๅŠ ็ณ– | %E | - | - | <10 | - | - |
22
+ | ่†ณ้ฃŸ็บค็ปด | g/d | - | - | 25~30(AI) | - | - |
23
+ | ๆ€ป่„‚่‚ช | %E | - | - | 20~30 | - | - |
24
+ | โ€” ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | <10 | - | - |
25
+ | โ€” n-6ๅคšไธ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | 2.5~9 | - | - |
26
+ | โ€” ไบšๆฒน้…ธ | %E | - | - | 4.0(AI) | - | - |
27
+ | โ€” n-3ๅคšไธ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | 0.5~2.0 | - | - |
28
+ | โ€” ฮฑ-ไบš้บป้…ธ | %E | - | - | 0.60(AI) | - | - |
29
+ | โ€” DHA | %E | - | - | 0.25(0.2%E)(AI) | - | - |
30
+ | ๆฐด | mL/d | - | 1500/2700 | - | - | - |
31
+
32
+ ### ไบŒใ€็Ÿฟ็‰ฉ่ดจ
33
+ | ่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | PI | UL |
34
+ | ---- | ---- | ---- | ---- | ---- | ---- |
35
+ | ้’™ | mg/d | 650 | 800 | - | 2000 |
36
+ | ็ฃท | mg/d | 600 | 720 | - | 3500 |
37
+ | ้’พ | mg/d | - | 2000(AI) | 3600 | - |
38
+ | ้’  | mg/d | - | 1500(AI) | โ‰ค2000 | - |
39
+ | ้• | mg/d | 300 | 370 | - | - |
40
+ | ๆฐฏ | mg/d | - | 2300(AI) | - | - |
41
+ | ้“ | mg/d | 12 | 18 | - | 42 |
42
+ | ็ข˜ | ฮผg/d | 120 | 230 | - | 500 |
43
+ | ้”Œ | mg/d | 8.6 | 10.5 | - | 40 |
44
+ | ็ก’ | ฮผg/d | 54 | 65 | - | 400 |
45
+ | ้“œ | mg/d | 0.72 | 0.91 | - | 8.0 |
46
+ | ๆฐŸ | mg/d | - | 1.5(AI) | - | 3.5 |
47
+ | ้“ฌ | ฮผg/d | - | 30(AI) | - | - |
48
+ | ้”ฐ | mg/d | - | 4.0(AI) | - | 11 |
49
+ | ้’ผ | ฮผg/d | 20 | 25 | - | 900 |
50
+
51
+ ### ไธ‰ใ€็ปด็”Ÿ็ด 
52
+ | ่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | PI | UL |
53
+ | ---- | ---- | ---- | ---- | ---- | ---- |
54
+ | ็ปด็”Ÿ็ด A | ฮผgRAE/d | 470 | 660 | - | 3000 |
55
+ | ็ปด็”Ÿ็ด D | ฮผg/d | 8 | 10 | - | 50 |
56
+ | ็ปด็”Ÿ็ด E | mgฮฑ-TE/d | - | 14(AI) | - | 700 |
57
+ | ็ปด็”Ÿ็ด K | ฮผg/d | - | 80(AI) | - | - |
58
+ | ็ปด็”Ÿ็ด Bโ‚ | mg/d | 1.0 | 1.2 | - | - |
59
+ | ็ปด็”Ÿ็ด Bโ‚‚ | mg/d | 1.0 | 1.2 | - | - |
60
+ | ็ƒŸ้…ธ | mg NE/d | 10 | 12 | - | 35/310# |
61
+ | ็ปด็”Ÿ็ด Bโ‚† | mg/d | 1.9 | 2.2 | - | 60 |
62
+ | ๅถ้…ธ | ฮผg DFE/d | 520 | 600 | - | 1000# |
63
+ | ็ปด็”Ÿ็ด Bโ‚โ‚‚ | ฮผg/d | 2.4 | 2.9 | - | - |
64
+ | ๆณ›้…ธ | mg/d | - | 6.0(AI) | - | - |
65
+ | ็”Ÿ็‰ฉ็ด  | ฮผg/d | - | 50(AI) | - | - |
66
+ | ่ƒ†็ขฑ | mg/d | - | 460(AI) | - | 3000 |
67
+ | ็ปด็”Ÿ็ด C | mg/d | 85 | 100 | 200 | 2000 |
68
+
69
+ ### ๅค‡ๆณจ
70
+ - PAL๏ผš่บซไฝ“ๆดปๅŠจๆฐดๅนณ๏ผˆI๏ผšไฝŽๅผบๅบฆ๏ผ›II๏ผšไธญ็ญ‰ๅผบๅบฆ๏ผ›III๏ผš้ซ˜ๅผบๅบฆ๏ผ‰
71
+ - ๆœชๅˆถๅฎšๅ‚่€ƒๅ€ผ็”จโ€œโ€”โ€่กจ็คบ๏ผ›#ๆ ‡ๆณจ้กนไธบ็‰นๆฎŠ้™ๅฎšๆ•ฐๅ€ผ
72
+ - ๆฐดๆ€ปๆ‘„ๅ…ฅ้‡ๅŒ…ๅซ้ฅฎ็”จๆฐดๅŠ้ฃŸ็‰ฉไธญ็š„ๆฐดๅˆ†
73
+
74
+ ---
75
+
76
+ # ่กจ16 ไธญๅ›ฝ18-49ๅฒๅญ•ๆœŸๅฅณๆ€ง๏ผˆๅญ•ไธญๆœŸ๏ผ‰่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡
77
+ ### ็ผฉ็•ฅ่ฏ่ฏดๆ˜Ž
78
+ - EAR๏ผšๅนณๅ‡้œ€่ฆ้‡
79
+ - RNI๏ผšๆŽจ่ๆ‘„ๅ…ฅ้‡
80
+ - AI๏ผš้€‚ๅฎœๆ‘„ๅ…ฅ้‡
81
+ - PI๏ผš้ข„้˜ฒ้žไผ ๆŸ“ๆ€งๆ…ขๆ€ง็—…ๅปบ่ฎฎๆ‘„ๅ…ฅ้‡
82
+ - UL๏ผšๅฏ่€ๅ—ๆœ€้ซ˜ๆ‘„ๅ…ฅ้‡
83
+ - AMDR๏ผšๅฎ้‡่ฅๅ…ป็ด ๅฏๆŽฅๅ—่Œƒๅ›ด
84
+ - PAL๏ผš่บซไฝ“ๆดปๅŠจๆฐดๅนณ
85
+
86
+ ### ไธ€ใ€่ƒฝ้‡ไธŽๅฎ้‡่ฅๅ…ป็ด 
87
+ | ่ƒฝ้‡/่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | AMDR | PI | UL |
88
+ | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
89
+ | ่ƒฝ้‡ PAL(I) | MJ/d | - | 8.16 | - | - | - |
90
+ | ่ƒฝ้‡ PAL(II) | MJ/d | - | 9.84 | - | - | - |
91
+ | ่ƒฝ้‡ PAL(III) | MJ/d | - | 11.30 | - | - | - |
92
+ | ่›‹็™ฝ่ดจ | g/d | 60 | 70 | 10~20% | - | - |
93
+ | ๆ€ป็ขณๆฐดๅŒ–ๅˆ็‰ฉ | %E | 140 | - | 50~65% | - | - |
94
+ | โ€” ๆทปๅŠ ็ณ– | %E | - | - | <10 | - | - |
95
+ | ่†ณ้ฃŸ็บค็ปด | g/d | - | - | 29~34(AI) | - | - |
96
+ | ๆ€ป่„‚่‚ช | %E | - | - | 20~30 | - | - |
97
+ | โ€” ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | <10 | - | - |
98
+ | โ€” n-6ๅคšไธ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | 2.5~9 | - | - |
99
+ | โ€” ไบšๆฒน้…ธ | %E | - | - | 4.0(AI) | - | - |
100
+ | โ€” n-3ๅคšไธ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | 0.5~2.0 | - | - |
101
+ | โ€” ฮฑ-ไบš้บป้…ธ | %E | - | - | 0.60(AI) | - | - |
102
+ | โ€” DHA+EPA | g/d | - | - | 0.25(0.2%E)(AI) | - | - |
103
+ | ๆฐด | mL/d | - | 1700/3000 | - | - | - |
104
+
105
+ ### ไบŒใ€็Ÿฟ็‰ฉ่ดจ
106
+ | ่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | PI | UL |
107
+ | ---- | ---- | ---- | ---- | ---- | ---- |
108
+ | ้’™ | mg/d | 650 | 800 | - | 2000 |
109
+ | ็ฃท | mg/d | 600 | 720 | - | 3500 |
110
+ | ้’พ | mg/d | - | 2000(AI) | 3600 | - |
111
+ | ้’  | mg/d | - | 1500(AI) | โ‰ค2000 | - |
112
+ | ้• | mg/d | 300 | 370 | - | - |
113
+ | ๆฐฏ | mg/d | - | 2300(AI) | - | - |
114
+ | ้“ | mg/d | 19 | 25 | - | 42 |
115
+ | ็ข˜ | ฮผg/d | 160 | 230 | - | 500 |
116
+ | ้”Œ | mg/d | 8.6 | 10.5 | - | 40 |
117
+ | ็ก’ | ฮผg/d | 54 | 65 | - | 400 |
118
+ | ้“œ | mg/d | 0.72 | 0.9 | - | 8.0 |
119
+ | ๆฐŸ | mg/d | - | 1.5(AI) | - | 3.5 |
120
+ | ้“ฌ | ฮผg/d | - | 33(AI) | - | - |
121
+ | ้”ฐ | mg/d | - | 4.0(AI) | - | 11 |
122
+ | ้’ผ | ฮผg/d | 20 | 25 | - | 900 |
123
+
124
+ ### ไธ‰ใ€็ปด็”Ÿ็ด 
125
+ | ่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | PI | UL |
126
+ | ---- | ---- | ---- | ---- | ---- | ---- |
127
+ | ็ปด็”Ÿ็ด A | ฮผgRAE/d | 520 | 730 | - | 3000 |
128
+ | ็ปด็”Ÿ็ด D | ฮผg/d | 8 | 10 | - | 50 |
129
+ | ็ปด็”Ÿ็ด E | mgฮฑ-TE/d | - | 14(AI) | - | 700 |
130
+ | ็ปด็”Ÿ็ด K | ฮผg/d | - | 80(AI) | - | - |
131
+ | ็ปด็”Ÿ็ด Bโ‚ | mg/d | 1.1 | 1.4 | - | - |
132
+ | ็ปด็”Ÿ็ด Bโ‚‚ | mg/d | 1.1 | 1.3 | - | - |
133
+ | ็ƒŸ้…ธ | mg NE/d | 10 | 12 | - | 35/310# |
134
+ | ็ปด็”Ÿ็ด Bโ‚† | mg/d | 1.7 | 2.2 | - | 60 |
135
+ | ๅถ้…ธ | ฮผg DFE/d | 520 | 600 | - | 1000# |
136
+ | ็ปด็”Ÿ็ด Bโ‚โ‚‚ | ฮผg/d | 2.4 | 2.9 | - | - |
137
+ | ๆณ›้…ธ | mg/d | - | 6.0(AI) | - | - |
138
+ | ็”Ÿ็‰ฉ็ด  | ฮผg/d | - | 50(AI) | - | - |
139
+ | ่ƒ†็ขฑ | mg/d | - | 460(AI) | - | 3000 |
140
+ | ็ปด็”Ÿ็ด C | mg/d | 95 | 115 | 200 | 2000 |
141
+
142
+ ### ๅค‡ๆณจ
143
+ - PAL๏ผš่บซไฝ“ๆดปๅŠจๆฐดๅนณ๏ผˆI๏ผšไฝŽๅผบๅบฆ๏ผ›II๏ผšไธญ็ญ‰ๅผบๅบฆ๏ผ›III๏ผš้ซ˜ๅผบๅบฆ๏ผ‰
144
+ - ๆœชๅˆถๅฎšๅ‚่€ƒๅ€ผ็”จโ€œโ€”โ€่กจ็คบ๏ผ›#ๆ ‡ๆณจ้กนไธบ็‰นๆฎŠ้™ๅฎšๆ•ฐๅ€ผ
145
+ - ๆฐดๆ€ปๆ‘„ๅ…ฅ้‡ๅŒ…ๅซ้ฅฎ็”จๆฐดๅŠ้ฃŸ็‰ฉไธญ็š„ๆฐดๅˆ†
146
+
147
+ ---
148
+
149
+ # ่กจ17 ไธญๅ›ฝ18-49ๅฒๅญ•ๆœŸๅฅณๆ€ง๏ผˆๅญ•ๆ™šๆœŸ๏ผ‰่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡
150
+ ### ็ผฉ็•ฅ่ฏ่ฏดๆ˜Ž
151
+ - EAR๏ผšๅนณๅ‡้œ€่ฆ้‡
152
+ - RNI๏ผšๆŽจ่ๆ‘„ๅ…ฅ้‡
153
+ - AI๏ผš้€‚ๅฎœๆ‘„ๅ…ฅ้‡
154
+ - PI๏ผš้ข„้˜ฒ้žไผ ๆŸ“ๆ€งๆ…ขๆ€ง็—…ๅปบ่ฎฎๆ‘„ๅ…ฅ้‡
155
+ - UL๏ผšๅฏ่€ๅ—ๆœ€้ซ˜ๆ‘„ๅ…ฅ้‡
156
+ - AMDR๏ผšๅฎ้‡่ฅๅ…ป็ด ๅฏๆŽฅๅ—่Œƒๅ›ด
157
+ - PAL๏ผš่บซไฝ“ๆดปๅŠจๆฐดๅนณ
158
+
159
+ ### ไธ€ใ€่ƒฝ้‡ไธŽๅฎ้‡่ฅๅ…ป็ด 
160
+ | ่ƒฝ้‡/่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | AMDR | PI | UL |
161
+ | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
162
+ | ่ƒฝ้‡ PAL(I) | MJ/d | - | 8.78 | - | - | - |
163
+ | ่ƒฝ้‡ PAL(II) | MJ/d | - | 10.46 | - | - | - |
164
+ | ่ƒฝ้‡ PAL(III) | MJ/d | - | 11.92 | - | - | - |
165
+ | ่›‹็™ฝ่ดจ | g/d | 75 | 85 | 10~20% | - | - |
166
+ | ๆ€ป็ขณๆฐดๅŒ–ๅˆ็‰ฉ | %E | 155 | - | 50~65% | - | - |
167
+ | โ€” ๆทปๅŠ ็ณ– | %E | - | - | <10 | - | - |
168
+ | ่†ณ้ฃŸ็บค็ปด | g/d | - | - | 29~34(AI) | - | - |
169
+ | ๆ€ป่„‚่‚ช | %E | - | - | 20~30 | - | - |
170
+ | โ€” ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | <10 | - | - |
171
+ | โ€” n-6ๅคšไธ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | 2.5~9 | - | - |
172
+ | โ€” ไบšๆฒน้…ธ | %E | - | - | 4.0(AI) | - | - |
173
+ | โ€” n-3ๅคšไธ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | 0.5~2.0 | - | - |
174
+ | โ€” ฮฑ-ไบš้บป้…ธ | %E | - | - | 0.60(AI) | - | - |
175
+ | โ€” DHA+EPA | g/d | - | - | 0.25(0.2%E)(AI) | - | - |
176
+ | ๆฐด | mL/d | - | 1700/3000 | - | - | - |
177
+
178
+ ### ไบŒใ€็Ÿฟ็‰ฉ่ดจ
179
+ | ่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | PI | UL |
180
+ | ---- | ---- | ---- | ---- | ---- | ---- |
181
+ | ้’™ | mg/d | 650 | 800 | - | 2000 |
182
+ | ็ฃท | mg/d | 600 | 720 | - | 3500 |
183
+ | ้’พ | mg/d | - | 2000(AI) | 3600 | - |
184
+ | ้’  | mg/d | - | 1500(AI) | โ‰ค2000 | - |
185
+ | ้• | mg/d | 300 | 370 | - | - |
186
+ | ๆฐฏ | mg/d | - | 2300(AI) | - | - |
187
+ | ้“ | mg/d | 22 | 29 | - | 42 |
188
+ | ็ข˜ | ฮผg/d | 160 | 230 | - | 500 |
189
+ | ้”Œ | mg/d | 8.6 | 10.5 | - | 40 |
190
+ | ็ก’ | ฮผg/d | 54 | 65 | - | 400 |
191
+ | ้“œ | mg/d | 0.72 | 0.9 | - | 8.0 |
192
+ | ๆฐŸ | mg/d | - | 1.5(AI) | - | 3.5 |
193
+ | ้“ฌ | ฮผg/d | - | 35(AI) | - | - |
194
+ | ้”ฐ | mg/d | - | 4.0(AI) | - | 11 |
195
+ | ้’ผ | ฮผg/d | 20 | 25 | - | 900 |
196
+
197
+ ### ไธ‰ใ€็ปด็”Ÿ็ด 
198
+ | ่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | PI | UL |
199
+ | ---- | ---- | ---- | ---- | ---- | ---- |
200
+ | ็ปด็”Ÿ็ด A | ฮผgRAE/d | 520 | 730 | - | 3000 |
201
+ | ็ปด็”Ÿ็ด D | ฮผg/d | 8 | 10 | - | 50 |
202
+ | ็ปด็”Ÿ็ด E | mgฮฑ-TE/d | - | 14(AI) | - | 700 |
203
+ | ็ปด็”Ÿ็ด K | ฮผg/d | - | 80(AI) | - | - |
204
+ | ็ปด็”Ÿ็ด Bโ‚ | mg/d | 1.2 | 1.4 | - | - |
205
+ | ็ปด็”Ÿ็ด Bโ‚‚ | mg/d | 1.2 | 1.5 | - | - |
206
+ | ็ƒŸ้…ธ | mg NE/d | 10 | 12 | - | 35/310# |
207
+ | ็ปด็”Ÿ็ด Bโ‚† | mg/d | 1.9 | 2.2 | - | 60 |
208
+ | ๅถ้…ธ | ฮผg DFE/d | 520 | 600 | - | 1000# |
209
+ | ็ปด็”Ÿ็ด Bโ‚โ‚‚ | ฮผg/d | 2.4 | 2.9 | - | - |
210
+ | ๆณ›้…ธ | mg/d | - | 6.0(AI) | - | - |
211
+ | ็”Ÿ็‰ฉ็ด  | ฮผg/d | - | 50(AI) | - | - |
212
+ | ่ƒ†็ขฑ | mg/d | - | 460(AI) | - | 3000 |
213
+ | ็ปด็”Ÿ็ด C | mg/d | 95 | 115 | 200 | 2000 |
214
+
215
+ ### ๅค‡ๆณจ
216
+ - PAL๏ผš่บซไฝ“ๆดปๅŠจๆฐดๅนณ๏ผˆI๏ผšไฝŽๅผบๅบฆ๏ผ›II๏ผšไธญ็ญ‰ๅผบๅบฆ๏ผ›III๏ผš้ซ˜ๅผบๅบฆ๏ผ‰
217
+ - ๆœชๅˆถๅฎšๅ‚่€ƒๅ€ผ็”จโ€œโ€”โ€่กจ็คบ๏ผ›#ๆ ‡ๆณจ้กนไธบ็‰นๆฎŠ้™ๅฎšๆ•ฐๅ€ผ
218
+ - ๆฐดๆ€ปๆ‘„ๅ…ฅ้‡ๅŒ…ๅซ้ฅฎ็”จๆฐดๅŠ้ฃŸ็‰ฉไธญ็š„ๆฐดๅˆ†
219
+
220
+ ---
221
+
222
+ # ่กจ18 ไธญๅ›ฝ18-49ๅฒๅ“บไนณๆœŸๅฅณๆ€ง่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡
223
+ ### ็ผฉ็•ฅ่ฏ่ฏดๆ˜Ž
224
+ - EAR๏ผšๅนณๅ‡้œ€่ฆ้‡
225
+ - RNI๏ผšๆŽจ่ๆ‘„ๅ…ฅ้‡
226
+ - AI๏ผš้€‚ๅฎœๆ‘„ๅ…ฅ้‡
227
+ - PI๏ผš้ข„้˜ฒ้žไผ ๆŸ“ๆ€งๆ…ขๆ€ง็—…ๅปบ่ฎฎๆ‘„ๅ…ฅ้‡
228
+ - UL๏ผšๅฏ่€ๅ—ๆœ€้ซ˜ๆ‘„ๅ…ฅ้‡
229
+ - AMDR๏ผšๅฎ้‡่ฅๅ…ป็ด ๅฏๆŽฅๅ—่Œƒๅ›ด
230
+ - PAL๏ผš่บซไฝ“ๆดปๅŠจๆฐดๅนณ
231
+
232
+ ### ไธ€ใ€่ƒฝ้‡ไธŽๅฎ้‡่ฅๅ…ป็ด 
233
+ | ่ƒฝ้‡/่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | AMDR | PI | UL |
234
+ | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
235
+ | ่ƒฝ้‡ PAL(I) | MJ/d | - | 8.78 | - | - | - |
236
+ | ่ƒฝ้‡ PAL(II) | MJ/d | - | 10.46 | - | - | - |
237
+ | ่ƒฝ้‡ PAL(III) | MJ/d | - | 11.92 | - | - | - |
238
+ | ่›‹็™ฝ่ดจ | g/d | 70 | 80 | 10~20% | - | - |
239
+ | ๆ€ป็ขณๆฐดๅŒ–ๅˆ็‰ฉ | %E | 170 | - | 50~65% | - | - |
240
+ | โ€” ๆทปๅŠ ็ณ– | %E | - | - | <10 | - | - |
241
+ | ่†ณ้ฃŸ็บค็ปด | g/d | - | - | 29~34(AI) | - | - |
242
+ | ๆ€ป่„‚่‚ช | %E | - | - | 20~30 | - | - |
243
+ | โ€” ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | <10 | - | - |
244
+ | โ€” n-6ๅคšไธ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | 2.5~9 | - | - |
245
+ | โ€” ไบšๆฒน้…ธ | %E | - | - | 4.0(AI) | - | - |
246
+ | โ€” n-3ๅคšไธ้ฅฑๅ’Œ่„‚่‚ช้…ธ | %E | - | - | 0.5~2.0 | - | - |
247
+ | โ€” ฮฑ-ไบš้บป๏ฟฝ๏ฟฝ | %E | - | - | 0.60(AI) | - | - |
248
+ | โ€” DHA+EPA | g/d | - | - | 250(200)(AI) | - | - |
249
+ | ๆฐด | mL/d | - | 2100/3800 | - | - | - |
250
+
251
+ ### ไบŒใ€็Ÿฟ็‰ฉ่ดจ
252
+ | ่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | PI | UL |
253
+ | ---- | ---- | ---- | ---- | ---- | ---- |
254
+ | ้’™ | mg/d | 650 | 800 | - | 2000 |
255
+ | ็ฃท | mg/d | 600 | 720 | - | 3500 |
256
+ | ้’พ | mg/d | - | 2400(AI) | 3600 | - |
257
+ | ้’  | mg/d | - | 1500(AI) | โ‰ค2000 | - |
258
+ | ้• | mg/d | 270 | 330 | - | - |
259
+ | ๆฐฏ | mg/d | - | 2300(AI) | - | - |
260
+ | ้“ | mg/d | 18 | 24 | - | 42 |
261
+ | ็ข˜ | ฮผg/d | 170 | 240 | - | 500 |
262
+ | ้”Œ | mg/d | 11 | 13.0 | - | 40 |
263
+ | ็ก’ | ฮผg/d | 65 | 78 | - | 400 |
264
+ | ้“œ | mg/d | 1.12 | 1.5 | - | 8.0 |
265
+ | ๆฐŸ | mg/d | - | 1.5(AI) | - | 3.5 |
266
+ | ้“ฌ | ฮผg/d | - | 35(AI) | - | - |
267
+ | ้”ฐ | mg/d | - | 4.2(AI) | - | 11 |
268
+ | ้’ผ | ฮผg/d | 24 | 30 | - | 900 |
269
+
270
+ ### ไธ‰ใ€็ปด็”Ÿ็ด 
271
+ | ่ฅๅ…ป็ด  | ๅ•ไฝ | EAR | RNI | PI | UL |
272
+ | ---- | ---- | ---- | ---- | ---- | ---- |
273
+ | ็ปด็”Ÿ็ด A | ฮผgRAE/d | 870 | 1260 | - | 3000 |
274
+ | ็ปด็”Ÿ็ด D | ฮผg/d | 8 | 10 | - | 50 |
275
+ | ็ปด็”Ÿ็ด E | mgฮฑ-TE/d | - | 14(AI) | - | 700 |
276
+ | ็ปด็”Ÿ็ด K | ฮผg/d | - | 85(AI) | - | - |
277
+ | ็ปด็”Ÿ็ด Bโ‚ | mg/d | 1.2 | 1.5 | - | - |
278
+ | ็ปด็”Ÿ็ด Bโ‚‚ | mg/d | 1.4 | 1.7 | - | - |
279
+ | ็ƒŸ้…ธ | mg NE/d | 13 | 16 | - | 35/310# |
280
+ | ็ปด็”Ÿ็ด Bโ‚† | mg/d | 1.4 | 1.7 | - | 60 |
281
+ | ๅถ้…ธ | ฮผg DFE/d | 450 | 550 | - | 1000# |
282
+ | ็ปด็”Ÿ็ด Bโ‚โ‚‚ | ฮผg/d | 2.6 | 3.2 | - | - |
283
+ | ๆณ›้…ธ | mg/d | - | 7.0(AI) | - | - |
284
+ | ็”Ÿ็‰ฉ็ด  | ฮผg/d | - | 50(AI) | - | - |
285
+ | ่ƒ†็ขฑ | mg/d | - | 500(AI) | - | 3000 |
286
+ | ็ปด็”Ÿ็ด C | mg/d | 125 | 150 | 200 | 2000 |
287
+
288
+ ### ๅค‡ๆณจ
289
+ - PAL๏ผš่บซไฝ“ๆดปๅŠจๆฐดๅนณ๏ผˆI๏ผšไฝŽๅผบๅบฆ๏ผ›II๏ผšไธญ็ญ‰ๅผบๅบฆ๏ผ›III๏ผš้ซ˜ๅผบๅบฆ๏ผ‰
290
+ - ๆœชๅˆถๅฎšๅ‚่€ƒๅ€ผ็”จโ€œโ€”โ€่กจ็คบ๏ผ›#ๆ ‡ๆณจ้กนไธบ็‰นๆฎŠ้™ๅฎšๆ•ฐๅ€ผ
291
+ - ๆฐดๆ€ปๆ‘„ๅ…ฅ้‡ๅŒ…ๅซ้ฅฎ็”จๆฐดๅŠ้ฃŸ็‰ฉไธญ็š„ๆฐดๅˆ†
data/nutrition/raw/ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผๆ ‡ๅ‡†.md ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # WS/T 801-2022 ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผๆ ‡ๅ‡†
2
+ *Standard of recommendation for weight gain during pregnancy period*
3
+
4
+ ---
5
+
6
+ ## 1 ่Œƒๅ›ด
7
+ ๆœฌๆ ‡ๅ‡†่ง„ๅฎšไบ†ๆˆ‘ๅ›ฝๅฆ‡ๅฅณๅ•่ƒŽ่‡ช็„ถๅฆŠๅจ ไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผใ€‚
8
+ ๆœฌๆ ‡ๅ‡†้€‚็”จไบŽๅฏนๆˆ‘ๅ›ฝๅฆ‡ๅฅณๅ•่ƒŽ่‡ช็„ถๅฆŠๅจ ไฝ“้‡ๅขž้•ฟ็š„ๆŒ‡ๅฏผใ€‚
9
+ ๆœฌๆ ‡ๅ‡†ไธ้€‚็”จไบŽ่บซ้ซ˜ไฝŽไบŽ140cm๏ผŒๆˆ–ๅฆŠๅจ ๅ‰ไฝ“้‡้ซ˜ไบŽ125kg็š„ๅฆ‡ๅฅณใ€‚ๅฆŠๅจ ๆœŸๅˆๅนถ็—‡ๅ’Œๅนถๅ‘็—‡ๆ‚ฃ่€…ๅบ”็ป“ๅˆไธดๅบŠๆ„่ง่ฟ›่กŒไธชไฝ“ๅŒ–่ฏ„ไปทใ€‚
10
+
11
+ ## 2 ่ง„่Œƒๆ€งๅผ•็”จๆ–‡ไปถ
12
+ ๆœฌๆ ‡ๅ‡†ๆฒกๆœ‰่ง„่Œƒๆ€งๅผ•็”จๆ–‡ไปถใ€‚
13
+
14
+ ## 3 ๆœฏ่ฏญๅ’Œๅฎšไน‰
15
+ ไธ‹ๅˆ—ๆœฏ่ฏญๅ’Œๅฎšไน‰้€‚็”จไบŽๆœฌๆ ‡ๅ‡†ใ€‚
16
+
17
+ ### 3.1 ๅฆŠๅจ ๆœŸ pregnancy period
18
+ ไปŽๆœซๆฌกๆœˆ็ป็š„็ฌฌไธ€ๆ—ฅๅผ€ๅง‹่ฎก็ฎ—๏ผŒ็บฆไธบ280ๆ—ฅ๏ผˆ40ๅ‘จ๏ผ‰ใ€‚
19
+ ๆณจ๏ผšไธดๅบŠไธŠๅฐ†ๅฆŠๅจ ๅ…จ็จ‹ๅˆ†ไธบๅฆŠๅจ ๆ—ฉๆœŸใ€ๅฆŠๅจ ไธญๆœŸใ€ๅฆŠๅจ ๆ™šๆœŸ3ไธชๆ—ถๆœŸใ€‚
20
+
21
+ ### 3.2 ๅฆŠๅจ ๆ—ฉๆœŸ first trimester
22
+ ๅฆŠๅจ ๆœช่พพ14ๅ‘จใ€‚
23
+
24
+ ### 3.3 ๅฆŠๅจ ไธญๆœŸ second trimester
25
+ ๅฆŠๅจ ็ฌฌ14ๅ‘จ๏ฝž27+6ๅ‘จใ€‚
26
+
27
+ ### 3.4 ๅฆŠๅจ ๆ™šๆœŸ third trimester
28
+ ๅฆŠๅจ ็ฌฌ28ๅ‘จๅŠๅ…ถๅŽใ€‚
29
+
30
+ ### 3.5 ไฝ“่ดจๆŒ‡ๆ•ฐ body mass index; BMI
31
+ ไธ€็ง่ฎก็ฎ—่บซ้ซ˜ๅˆซไฝ“้‡็š„ๆŒ‡ๆ•ฐ๏ผŒ่ฎก็ฎ—ๆ–นๆณ•ๆ˜ฏไฝ“้‡(kg)ไธŽ่บซ้ซ˜(m)็š„ๅนณๆ–น็š„ๆฏ”ๅ€ผใ€‚
32
+
33
+ ### 3.6 ๅฆŠๅจ ๅ‰ไฝ“้‡ pre-pregnancy weight
34
+ ๅฆŠๅจ ไน‹ๅ‰ไธ‰ไธชๆœˆๅ†…็š„ๅนณๅ‡ไฝ“้‡ใ€‚
35
+
36
+ ### 3.7 ๅˆ†ๅจฉๅ‰ไฝ“้‡ pre-delivery weight
37
+ ๅˆ†ๅจฉๅ‰ไธ€ๅ‘จๅ†…ๆœ€ๅŽไธ€ๆฌก็งฐ้‡็š„ไฝ“้‡ใ€‚
38
+
39
+ ### 3.8 ๅฆŠๅจ ๆœŸไฝ“้‡ๆ€ปๅขž้•ฟๅ€ผ gestational weight gain; GWG
40
+ ๅˆ†ๅจฉๅ‰ไฝ“้‡(kg)ๅ‡ๅŽปๅฆŠๅจ ๅ‰ไฝ“้‡(kg)ๆ‰€ๅพ—ๆ•ฐๅ€ผใ€‚
41
+
42
+ ### 3.9 ๅฆŠๅจ ๆ—ฉๆœŸไฝ“้‡ๅขž้•ฟๅ€ผ gestational weight gain in first trimester
43
+ ๅฆŠๅจ 13ๅ‘จๆœซไฝ“้‡(kg)ๅ‡ๅŽปๅฆŠๅจ ๅ‰ไฝ“้‡(kg)ๆ‰€ๅพ—ๆ•ฐๅ€ผใ€‚
44
+
45
+ ### 3.10 ๅฆŠๅจ ไธญๆœŸไฝ“้‡ๅขž้•ฟๅ€ผ gestational weight gain in second trimester
46
+ ๅฆŠๅจ 27ๅ‘จๆœซไฝ“้‡(kg)ๅ‡ๅŽปๅฆŠๅจ 13ๅ‘จๆœซไฝ“้‡(kg)ๆ‰€ๅพ—ๆ•ฐๅ€ผใ€‚
47
+
48
+ ### 3.11 ๅฆŠๅจ ๆ™šๆœŸไฝ“้‡ๅขž้•ฟๅ€ผ gestational weight gain in third trimester
49
+ ๅˆ†ๅจฉๅ‰ไฝ“้‡(kg)ๅ‡ๅŽปๅฆŠๅจ 27ๅ‘จๆœซไฝ“้‡(kg)ๆ‰€ๅพ—ๆ•ฐๅ€ผใ€‚
50
+
51
+ ## 4 ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟ่Œƒๅ›ดๅŠๅฆŠๅจ ไธญๆœŸๅ’ŒๅฆŠๅจ ๆ™šๆœŸๆฏๅ‘จไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผ
52
+ ๆŒ‰ไธญๅ›ฝๆˆไบบไฝ“่ดจๆŒ‡ๆ•ฐๅˆ‡็‚น๏ผŒๅˆ†ๅˆซ็ป™ไบˆๅœจไธๅŒๅฆŠๅจ ๅ‰ไฝ“่ดจๆŒ‡ๆ•ฐๆƒ…ๅ†ตไธ‹๏ผŒๅ•่ƒŽๅฆŠๅจ ๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟ่Œƒๅ›ดๅŠๅฆŠๅจ ไธญๆœŸๅ’ŒๅฆŠๅจ ๆ™šๆœŸๆฏๅ‘จไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผ๏ผŒ่ง่กจ1ใ€‚
53
+
54
+ **่กจ1 ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟ่Œƒๅ›ดๅŠๅฆŠๅจ ไธญๆœŸๅ’ŒๅฆŠๅจ ๆ™šๆœŸๆฏๅ‘จไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผ**
55
+ | ๅฆŠๅจ ๅ‰ไฝ“่ดจๆŒ‡ๆ•ฐๅˆ†็ฑป | ๆ€ปๅขž้•ฟๅ€ผ่Œƒๅ›ด(kg) | ๅฆŠๅจ ๆ—ฉๆœŸๅขž้•ฟๅ€ผ่Œƒๅ›ด(kg) | ๅฆŠๅจ ไธญๆœŸๅ’ŒๅฆŠๅจ ๆ™šๆœŸๆฏๅ‘จไฝ“้‡ๅขž้•ฟๅ€ผๅŠ่Œƒๅ›ด(kg/week) |
56
+ | ---- | ---- | ---- | ---- |
57
+ | ไฝŽไฝ“้‡๏ผˆBMI ๏ผœ 18.5 kg/mยฒ๏ผ‰ | 11.0 ~ 16.0 | 0 ~ 2.0 | 0.46๏ผˆ0.37 ~ 0.56๏ผ‰ |
58
+ | ๆญฃๅธธไฝ“้‡๏ผˆ18.5 kg/mยฒ โ‰ค BMI ๏ผœ 24.0 kg/mยฒ๏ผ‰ | 8.0 ~ 14.0 | 0 ~ 2.0 | 0.37๏ผˆ0.26 ~ 0.48๏ผ‰ |
59
+ | ่ถ…้‡๏ผˆ24.0 kg/mยฒ โ‰ค BMI ๏ผœ 28.0 kg/mยฒ๏ผ‰ | 7.0 ~ 11.0 | 0 ~ 2.0 | 0.30๏ผˆ0.22 ~ 0.37๏ผ‰ |
60
+ | ่‚ฅ่ƒ–๏ผˆBMI โ‰ฅ 28.0 kg/mยฒ๏ผ‰ | 5.0 ~ 9.0 | 0 ~ 2.0 | 0.22๏ผˆ0.15 ~ 0.30๏ผ‰ |
61
+
62
+ ## 5 ๆต‹้‡ๆ–นๆณ•
63
+ ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณ่บซ้ซ˜ใ€ไฝ“้‡็š„ๆต‹้‡ๆ–นๆณ•ๅ‚่ง้™„ๅฝ•Aใ€‚
64
+
65
+ ---
66
+
67
+ ## ้™„ๅฝ•A๏ผˆ่ต„ๆ–™ๆ€ง๏ผ‰ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณ่บซ้ซ˜ใ€ไฝ“้‡็š„ๆต‹้‡ๆ–นๆณ•
68
+ ### A.1 ่บซ้ซ˜ๆต‹้‡
69
+ #### A.1.1 ๆต‹้‡ๆกไปถ
70
+ ๆต‹้‡ๆ—ถๅฆŠๅจ ๅฆ‡ๅฅณๅบ”ๅ…ๅ† ใ€่ตค่ถณ๏ผŒ่งฃๅผ€ๅ‘้ซป๏ผŒๅฎคๆธฉ25โ„ƒๅทฆๅณใ€‚
71
+
72
+ #### A.1.2 ๆต‹้‡ๅทฅๅ…ท
73
+ ็ซ‹ๆŸฑๅผ่บซ้ซ˜่ฎก๏ผŒๅˆ†ๅบฆๅ€ผ0.1cm๏ผŒๆœ‰ๆŠตๅข™่ฃ…็ฝฎใ€‚ๆป‘ๆต‹ๆฟๅบ”ไธŽ็ซ‹ๆŸฑๅž‚็›ด๏ผŒๆป‘ๅŠจ่‡ชๅฆ‚ใ€‚
74
+
75
+ #### A.1.3 ๆต‹้‡ๆ–นๆณ•
76
+ ๅฆŠๅจ ๅฆ‡ๅฅณๅ–็ซ‹ๆญฃๅงฟๅŠฟ๏ผŒ็ซ™ๅœจ่ธๆฟไธŠ๏ผŒๆŒบ่ƒธๆ”ถ่…น๏ผŒไธค่‡‚่‡ช็„ถไธ‹ๅž‚๏ผŒ่„š่ทŸ้ ๆ‹ข๏ผŒ่„šๅฐ–ๅˆ†ๅผ€็บฆ60ๅบฆใ€‚ๅŒ่†ๅนถๆ‹ขๆŒบ็›ด๏ผŒไธค็œผๅนณ่ง†ๆญฃๅ‰ๆ–น๏ผŒ็œผ็œถไธ‹็ผ˜ไธŽ่€ณๅป“ไธŠ็ผ˜ไฟๆŒๅœจๅŒไธ€ๆฐดๅนณใ€‚่„š่ทŸใ€่‡€้ƒจๅ’Œไธค่‚ฉ่ƒ›่ง’้—ดไธ‰ไธช็‚นๅŒๆ—ถๆŽฅ่งฆ็ซ‹ๆŸฑ๏ผŒๅคด้ƒจไฟๆŒๆญฃ็ซ‹ไฝ็ฝฎใ€‚ๆต‹้‡่€…ๆ‰‹ๆ‰ถๆป‘ๆต‹ๆฟ่ฝป่ฝปๅ‘ไธ‹ๆป‘ๅŠจ๏ผŒ็›ดๅˆฐๅบ•้ขไธŽๅคด้ข…้กถ็‚น็›ธๆŽฅ่งฆ๏ผŒๆญคๆ—ถ่ง‚ๅฏŸๅฆŠๅจ ๅฆ‡ๅฅณๅงฟๅŠฟๆญฃ็กฎๅŽ่ฏปๅ–ๆ•ฐๅ€ผใ€‚
77
+
78
+ #### A.1.4 ่ฏปๆ•ฐไธŽ่ฎฐๅฝ•
79
+ ่ฏปๆ•ฐๆ—ถๆต‹้‡่€…็š„็œผ็›ไธŽๆป‘ๆต‹ๆฟๅบ•้ขๅœจๅŒไธ€ไธชๆฐดๅนณ้ขไธŠ๏ผŒ่ฏปๅ–ๆป‘ๆฟๅบ•้ขๅฏนๅบ”็ซ‹ๆŸฑๆ‰€็คบๆ•ฐๅ€ผ๏ผŒไปฅๅŽ˜็ฑณไธบๅ•ไฝ๏ผŒ็ฒพ็กฎๅˆฐ0.1cmใ€‚
80
+
81
+ ### A.2 ไฝ“้‡ๆต‹้‡
82
+ #### A.2.1 ๆต‹้‡ๆกไปถ
83
+ ๆต‹้‡ๅบ”ๅœจๆธ…ๆ™จใ€็ฉบ่…นใ€ๆŽ’ๆณ„ๅฎŒๆฏ•็š„็Šถๆ€ไธ‹่ฟ›่กŒ๏ผŒๅฎคๆธฉ25โ„ƒๅทฆๅณใ€‚
84
+
85
+ #### A.2.2 ๆต‹้‡ๅทฅๅ…ท
86
+ ็ปๆ กๅ‡†็š„็”ตๅญไฝ“้‡็งค๏ผŒๅˆ†ๅบฆๅ€ผ โ‰ค0.1 kg๏ผŒๆต‹้‡ๆ—ถไฝ“้‡่ฎกๆ”พ็ฝฎๅนณ็จณๅนถ่ฐƒ้›ถใ€‚
87
+
88
+ #### A.2.3 ๆต‹้‡ๆ–นๆณ•
89
+ ๅฆŠๅจ ๅฆ‡ๅฅณๅนณ้™็ซ™็ซ‹ไบŽไฝ“้‡็งค่ธๆฟไธญๅคฎ๏ผŒไธค่…ฟๅ‡ๅŒ€่ดŸ้‡๏ผŒๅ…ๅ† ใ€่ตค่ถณใ€็ฉฟ่ดด่บซ่–„ๅ†…่กฃ่ฃค๏ผŒๆณจๆ„ๅฎ‰ๅ…จใ€‚
90
+
91
+ #### A.2.4 ่ฏปๆ•ฐไธŽ่ฎฐๅฝ•
92
+ ๅ‡†็กฎ่ฎฐๅฝ•ไฝ“้‡็งค่ฏปๆ•ฐ๏ผŒ็ฒพ็กฎๅˆฐ0.1kgใ€‚
data/presets/.daily_status.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "2026-06-09": {
3
+ "summary_done": true,
4
+ "completed_at": "2026-06-09T00:31:27.292878"
5
+ }
6
+ }
data/presets/ไปŠๆ—ฅ็ฎ€ๆŠฅ_2026-06-10.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "date": "2026-06-10",
3
+ "generated_from": "2026-06-09",
4
+ "generated_at": "2026-06-09T00:31:27.292878",
5
+ "trimester": "ๅญ•ไธญๆœŸ",
6
+ "nutrient_focus": [],
7
+ "recommended_foods": [],
8
+ "need_ask_weight": false,
9
+ "need_ask_recipe": false,
10
+ "conversation_topics": [
11
+ "ไปŠๅคฉ็งฐไฝ“้‡ไบ†ๅ—๏ผŸ"
12
+ ],
13
+ "family_memory_summary": "{'relationships': ['- **ๅฐ็บข**: ๅญ•ๅฆ‡๏ผŒๅญ•ไธญๆœŸ', '- **ๅฐๆ˜Ž**: ไธˆๅคซ๏ผŒ่ดŸ่ดฃๅš้ฅญ', '- **ๅผ ้˜ฟๅงจ**: ๅฉ†ๅฉ†๏ผŒๅธฎๅฟ™็…ง้กพ'], 'recent_events': ['- **2026-06-07**: ไธˆๅคซๅšไบ†็•ช่Œ„็‰›่…ฉ๏ผŒๅญ•ๅฆ‡่ฏดๅพˆๅฅฝๅƒ', '- **2026-06-08**: ๅฉ†ๅฉ†็…ฒไบ†้ฒซ้ฑผ่ฑ†่…ๆฑค๏ผŒๅญ•ๅฆ‡ๅ–ไบ†ไธค็ข—', '- **2026-06-09**: ๅญ•ๅฆ‡่ฏดๆƒณๅƒๆธ…่’ธ้ฒˆ้ฑผ'], 'recent_daily': ['- **2026-06-07**: ๅญ•ๅฆ‡ไปŠๅคฉๅฟƒๆƒ…ไธ้”™๏ผŒๅƒไบ†ๅพˆๅคšๆฐดๆžœ', '- **2026-06-08**: ๅญ•ๅฆ‡ๆœ‰็‚นๅญ•ๅ๏ผŒไฝ†ๅšๆŒๅƒไบ†ๆ™š้ฅญ', '- **2026-06-09**: ๅญ•ๅฆ‡่ฏดๆœ€่ฟ‘ๆƒณๅƒ้…ธ็š„']}",
14
+ "three_day_summary": {}
15
+ }
debug2.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ add: '[OK] ๅทฒๆทปๅŠ ่œ่ฐฑ: test'
2
+ load: [{'name': 'test', 'cook': 't', 'difficulty': '', 'ingredients': '', 'notes': ''}]
3
+ len: 1
debug4.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ result: []
2
+ len: 0
debug_out.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ add: '[WARN] ่œ่ฐฑๅทฒๅญ˜ๅœจ: test'
2
+ load: [{'name': '่œๅ', 'cook': '', 'difficulty': '', 'ingredients': '', 'notes': ''}, {'name': 'test', 'cook': 't', 'difficulty': '', 'ingredients': '', 'notes': ''}]
3
+ len: 2
docs/้กน็›ฎ็†่งฃ_ๆŠ€ๆœฏๆžถๆž„.md CHANGED
@@ -1,300 +1,656 @@
1
- # ๐ŸŒธ PregoPal ้กน็›ฎ็†่งฃไธŽๆŠ€ๆœฏๆžถๆž„๏ผˆv3 - ๆ นๆฎๆ‰นๆณจไฟฎๆญฃ๏ผ‰
2
 
3
- > ๆœฌๆ–‡ๆกฃ็”จไบŽๅฏน้ฝๅฏน้กน็›ฎ็š„ๆ•ดไฝ“่ฎค็Ÿฅใ€‚v3 ๅทฒๆ•ดๅˆไฝ ๆ‰€ๆœ‰ๆ‰นๆณจใ€‚
4
 
5
  ---
6
 
7
  ## ไธ€ใ€ไธ€ๅฅ่ฏๅฎšไฝ
8
 
9
- **ไธ€ไธชๅŸบไบŽ MiniCPM-o 4.5 ๅ…จๅŒๅทฅๅคšๆจกๆ€ๅคงๆจกๅž‹็š„ AI ๅญ•ๆœŸ้™ชๆŠคๅŠฉๆ‰‹**๏ผšๅฎถไบบ๏ผˆไธˆๅคซ/ๅฉ†ๅฉ†/ๅฆˆๅฆˆ/ๅญ•ๅฆ‡ๆœฌไบบ๏ผ‰ๆ‰“ๅผ€ๆ‘„ๅƒๅคดๅ’Œ้บฆๅ…‹้ฃŽ๏ผŒไธŽ AI ๅฎžๆ—ถ่ฏญ้Ÿณๅฏน่ฏ๏ผŒAI ่ƒฝใ€Œ็œ‹่งใ€ๅ’Œใ€Œๅฌ่งใ€โ€”โ€”้€š่ฟ‡่ง†่ง‰่ฏ†ๅˆซ้ฃŸ็‰ฉใ€้€š่ฟ‡ๅฃฐ็บนๅŒบๅˆ†่บซไปฝใ€้€š่ฟ‡ๅฏน่ฏ็†่งฃ้œ€ๆฑ‚๏ผŒ่‡ชๅŠจ่ฎฐๅฝ•้ฅฎ้ฃŸใ€ๆŽจ่้ฃŸ่ฐฑใ€ๅˆ†ๆž่ฅๅ…ปๅนถ่พ“ๅ‡บๆŠฅๅ‘Šใ€‚
10
 
11
- > **โœ… ๅทฒ็กฎ่ฎคใ€‚**
12
 
13
  ---
14
 
15
- ## ไบŒใ€ๅ››ๅคงๆจกๅ—่ฏฆ่งฃ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
- ### ๆจกๅ— 1๏ผš๐Ÿ”Š ๅฃฐ็บน่ฏ†ๅˆซ + ๅคšๆจกๆ€่บซไปฝๆ„Ÿ็Ÿฅ
18
 
19
- **ๆ ธๅฟƒๅ˜ๅŒ–๏ผšไปŽใ€Œๅ•็‹ฌๅฝ•้Ÿณๆณจๅ†Œใ€ๅ˜ไธบใ€Œๅฏน่ฏไธญ่‡ช็„ถๆ„Ÿ็Ÿฅใ€**
20
 
21
- **ไธšๅŠก้œ€ๆฑ‚๏ผš**
22
- - ็”จๆˆทๅœจๅฎžๆ—ถๅฏน่ฏ่ฟ‡็จ‹ไธญ๏ผŒAI ่‡ชๅŠจ่ฏ†ๅˆซ่ฏด่ฏไบบ่บซไปฝ๏ผˆไธˆๅคซ/ๅฉ†ๅฉ†/ๅฆˆๅฆˆ/ๅญ•ๅฆ‡โ€ฆ๏ผ‰
23
- - ๆ— ้œ€ๅ•็‹ฌใ€Œๆณจๅ†Œใ€ๆญฅ้ชค๏ผŒๅœจ่‡ช็„ถๅฏน่ฏไธญๅฎŒๆˆๅฃฐ็บน้‡‡้›†ๅ’Œ่ฏ†ๅˆซ
24
- - ็ป“ๅˆๆ‘„ๅƒๅคด็”ป้ข่พ…ๅŠฉ็กฎ่ฎค๏ผˆ่ง†่ง‰+่ฏญ้Ÿณๅคšๆจกๆ€๏ผ‰
25
 
26
- **ๆŠ€ๆœฏ้€‰ๅž‹๏ผˆๆœ€็ปˆๆ–นๆกˆ๏ผ‰๏ผš**
27
- 1. **ไธป่ฆๆ–นๆกˆ๏ผšWhisper-medium encoder embedding**
28
- - MiniCPM-o 4.5 ๅ†…็ฝฎไบ† Whisper-medium ไฝœไธบ่ฏญ้Ÿณ็ผ–็ ๅ™จ
29
- - ๅฝ“้Ÿณ้ข‘็ป่ฟ‡ Whisper encoder ๆ—ถ๏ผŒไธญ้—ดๅฑ‚้š่—็Šถๆ€ๅŒ…ๅซไบ†่ฏด่ฏไบบ็š„ๅฃฐๅญฆ็‰นๅพ๏ผˆ้Ÿณ่‰ฒ/่ฏญ้€Ÿ/ๅฃ้Ÿณ๏ผ‰
30
- - ๅšๆณ•๏ผšๆๅ– encoder ่พ“ๅ‡บ็š„ hidden states๏ผŒๅšๆ—ถ้—ด็ปดๅบฆ็š„ๅนณๅ‡ๆฑ ๅŒ–๏ผŒๅพ—ๅˆฐๅ›บๅฎš็ปดๅบฆ็š„ **speaker embedding**
31
- - ๆ–ฐ้Ÿณ้ข‘ไธŽ่ฏฅ embedding ๅšไฝ™๏ฟฝ๏ฟฝ็›ธไผผๅบฆๆฏ”ๅฏน๏ผŒๅˆคๆ–ญๆ˜ฏๅฆไธบๅŒไธ€ไบบ
32
- - ่ฟ™ๆ˜ฏไธš็•Œๆˆ็†Ÿๅšๆณ•๏ผŒๆฏ”ๅฝ“ๅ‰ 6 ็ปด็ปŸ่ฎก็‰นๅพ้ฒๆฃ’่ฎธๅคš
 
 
 
 
 
 
 
33
 
34
- 2. **ๅค‡้€‰ๆ–นๆกˆ๏ผšไฟ็•™ๅฝ“ๅ‰้ข‘่ฐฑ็›ธไผผๅบฆๆ–นๆกˆ**
35
- - ไฝœไธบ fallback ๅ…œๅบ•
36
- - ไนŸๅฏไฝœไธบ็ฝฎไฟกๅบฆๅ‚่€ƒ๏ผŒไธŽ embedding ๆ–นๆกˆๅŠ ๆƒ่žๅˆ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- **้ƒจ็ฝฒ่ฏดๆ˜Ž๏ผš**
39
- - MiniCPM-o 4.5 ๆ˜ฏไธ€ไธช็ปŸไธ€็š„ๅคšๆจกๆ€ๆจกๅž‹๏ผŒไธๆ˜ฏๅคšไธช็‹ฌ็ซ‹็ป„ไปถ็š„ๆ‹ผ่ฃ…
40
- - ้œ€่ฆ็”จ MiniCPM-o ๅฎ˜ๆ–นๆŽจ็†ๆก†ๆžถ๏ผˆOpenBMB ๆไพ›๏ผ‰้ƒจ็ฝฒ
41
- - **llama.cpp ๅฏน MiniCPM-o ็š„ๅ…จๅŒๅทฅๅคšๆจกๆ€ๆ”ฏๆŒๅฏ่ƒฝไธๅฎŒๆ•ด**๏ผŒๅŽ็ปญไผšๆ นๆฎๅฎž้™…ๆƒ…ๅ†ต้€‰ๆ‹ฉ๏ผšA) OpenBMB ๅฎ˜ๆ–นๆŽจ็† B) Modal GPU ้ƒจ็ฝฒ C) llama.cpp๏ผˆๅฆ‚ๆžœๅ…ผๅฎน๏ผ‰
 
42
 
43
- > **โœ… ๅทฒๆ นๆฎไฝ ็š„ๆ‰นๆณจไฟฎๆญฃ๏ผšไผ˜ๅ…ˆๅผ€ๅ‘ Whisper-medium embedding ๆ–นๆกˆ๏ผŒ้ข‘่ฐฑ็›ธไผผๅบฆไฟ็•™ไธบๅค‡้€‰ใ€‚**
44
 
45
  ---
46
 
47
- ### ๆจกๅ— 2๏ผš๐Ÿณ ๆ™บ่ƒฝ่œๅ“ๆŽจ่๏ผˆ็”ฑ MiniCPM-o 4.5 ้ฉฑๅŠจ๏ผ‰
48
 
49
- **ๆ ธๅฟƒๅ˜ๅŒ–๏ผšไปŽใ€Œๆจกๆฟ้šๆœบ้€‰ใ€ๅ˜ไธบใ€ŒAI ๅฎžๆ—ถๅฏน่ฏๆŽจ่ใ€**
50
 
51
- **ไธšๅŠก้œ€ๆฑ‚๏ผš**
52
- - ็”จๆˆทๅ’Œ AI ๅฏน่ฏ๏ผšใ€ŒไปŠๅคฉๆƒณๅƒ้ฑผใ€ใ€Œๆœ‰็‚นๆฒก่ƒƒๅฃใ€ใ€Œๅ˜ด้‡Œๅ‘่‹ฆใ€โ€ฆ
53
- - AI ็†่งฃไธŠไธ‹ๆ–‡ โ†’ ็”Ÿๆˆไธชๆ€งๅŒ–ๆŽจ่
54
- - ่พ“ๅ‡บไธ‰้ค+ๅŠ ้คๆ–นๆกˆ + ็†็”ฑ + ๆณจๆ„ไบ‹้กน
55
 
56
- **ๆŠ€ๆœฏ้€‰ๅž‹๏ผš**
57
- - **MiniCPM-o 4.5๏ผˆ็ปŸไธ€ๆจกๅž‹๏ผ‰**๏ผš็›ดๆŽฅ็”จๅฏน่ฏ่ƒฝๅŠ›ๅšๆŽจ่
58
- - **่ฅๅ…ปๆ•ฐๆฎๆœฌๅœฐๅตŒๅ…ฅ**๏ผšๆŠŠไธญๅ›ฝๅญ•ๆœŸ่ฅๅ…ปๆ•ฐๆฎๆ•ด็†ๆˆ JSON๏ผŒๅœจ็ณป็ปŸๆ็คบ่ฏไธญๆไพ›็ป™ๆจกๅž‹
59
- - **ไธ้œ€่ฆ RAG**๏ผˆไฝ ่ฏดๅพ—ๅฏน๏ผŒ่ฟ‡ๅบฆ่ฎพ่ฎกไบ†๏ผ‰๏ผŒๅช้œ€่ฆๆŠŠ่ฅๅ…ปๆ•ฐๆฎๆ”พๅœจไธŠไธ‹ๆ–‡้‡Œ
60
- - **่ง„ๅˆ™ๅ…œๅบ•**๏ผš`MEAL_TEMPLATES` ไฟ็•™ไฝœไธบ็ฆป็บฟ fallback๏ผˆๆ— ๆจกๅž‹ๆ—ถๅฏ็”จ๏ผ‰
61
 
62
- **ๆณจๆ„๏ผš** MiniCPM-o 4.5 ๆœฌ่บซๆ˜ฏไธ€ไธช็ปŸไธ€็š„็ซฏๅˆฐ็ซฏๅคšๆจกๆ€ๆจกๅž‹๏ผŒไธๆ˜ฏใ€Œๅ…จๅฎถๆกถใ€โ€”โ€”SigLip2ใ€Whisperใ€Qwen3ใ€CosyVoice2 ๆ˜ฏๅ…ถๅ†…้ƒจ็ป„ไปถ๏ผŒไธๆ˜ฏ็‹ฌ็ซ‹ๅฎ‰่ฃ…็š„ๅบ“ใ€‚
 
63
 
64
- > **โœ… ๅทฒๆ นๆฎไฝ ็š„ๆ‰นๆณจไฟฎๆญฃ๏ผšๅŽปๆމ RAG๏ผŒ่ฅๅ…ปๆ•ฐๆฎๆœฌๅœฐๅตŒๅ…ฅ๏ผŒ่ง„ๅˆ™ๅ…œๅบ•ไฟ็•™ใ€‚**
65
 
66
- ---
 
 
 
 
 
67
 
68
- ### ๆจกๅ— 3๏ผš๐Ÿ“ ้ฅฎ้ฃŸ่ฎฐๅฝ• โ€” ๅฏน่ฏไธญ่‡ชๅŠจ่ฎฐๅฝ•๏ผŒๅญ˜ Markdown
69
-
70
- **ๆ ธๅฟƒๅ˜ๅŒ–๏ผšไปŽใ€Œๆ‰‹ๅŠจๅกซ่กจๅ•ใ€ๅ˜ไธบใ€ŒAI ่‡ชๅŠจไปŽๅฏน่ฏไธญๆๅ–ใ€**
71
-
72
- **ไธšๅŠก้œ€ๆฑ‚๏ผš**
73
- - AI ๅœจๅฏน่ฏไธญ่ฎฐๅฝ•๏ผšใ€ŒไปŠๅคฉไธญๅˆๅƒไบ†็•ช่Œ„็‰›่…ฉๅ’Œ็ฑณ้ฅญใ€
74
- - ็”จๆˆท็กฎ่ฎคๅŽ่‡ชๅŠจๅญ˜ๆกฃ
75
- - ็”Ÿๆˆ็ป“ๆž„ๅŒ–ๆ•ฐๆฎ๏ผˆJSON๏ผ‰+ ๅฏ่ฏปๆ–‡ๆกฃ๏ผˆMarkdown๏ผ‰
76
- - ๅฏนๅކๅฒ่ฎฐๅฝ•ๆ”ฏๆŒๆŸฅ่ฏข
77
-
78
- **ๆŠ€ๆœฏ้€‰ๅž‹๏ผˆไฟฎๆญฃๅŽ๏ผ‰๏ผš**
79
-
80
- **1. ๆ•ฐๆฎๆๅ–ๆ–นๅผ๏ผˆๅ…ณ้”ฎ่ฎพ่ฎก๏ผ‰**
81
- MiniCPM-o 4.5 **ๆฒกๆœ‰ toolcall ๅŠŸ่ƒฝ**๏ผŒๆ‰€ไปฅไธ่ƒฝ็›ดๆŽฅ่ฐƒ็”จ Python ๅ‡ฝๆ•ฐใ€‚
82
- ๆ”นไธบ **ใ€Œๆ ‡่ฎฐๆ ผๅผ่พ“ๅ‡บ + ๆญฃๅˆ™่งฃๆžใ€** ๆ–นๆกˆ๏ผš
83
- - ๅœจ็ณป็ปŸๆ็คบ่ฏไธญๅ‘Š่ฏ‰ๆจกๅž‹๏ผšๅฝ“ไฝ ้œ€่ฆ่ฎฐๅฝ•้ฅฎ้ฃŸๆ—ถ๏ผŒ่ฏท่พ“ๅ‡บไปฅไธ‹ๆ ผๅผโ€”โ€”
84
- ```
85
- [DIET_RECORD]
86
- ๆ—ฅๆœŸ: 2026-06-07
87
- ๆ—ฉ้ค: ๅ…จ้บฆ้ขๅŒ…+้ธก่›‹+็‰›ๅฅถ
88
- ๅˆ้ค: ๆธ…่’ธ้ฑผ+็ณ™็ฑณ้ฅญ+็‚’ๆ—ถ่”ฌ
89
- ๆ™š้ค:
90
- ๅŠ ้ค: ้…ธๅฅถ+ๅšๆžœ
91
- ๅฟƒๆƒ…: ๆŒบๅฅฝ
92
- ๅค‡ๆณจ:
93
- [/DIET_RECORD]
94
- ```
95
- - ๅŽ็ซฏ Python ็”จๆญฃๅˆ™่กจ่พพๅผ่งฃๆž `[DIET_RECORD]...[/DIET_RECORD]` ไน‹้—ด็š„ๅ†…ๅฎน
96
- - ่งฃๆžๅŽๅญ˜ๅ…ฅ JSON + ็”Ÿๆˆ Markdown
97
-
98
- **2. Markdown ๆจกๆฟๅผ•ๆ“Žๆ˜ฏไป€ไนˆ๏ผŸ**
99
- ๅฐฑๆ˜ฏๅฝ“ๅ‰ `diet_logger.py` ไธญ็š„ `_generate_markdown()` ๆ–นๆณ•โ€”โ€”**็”จ Python f-string ๆ‹ผๆŽฅ Markdown ๆ–‡ๆœฌ**ใ€‚ไธๆ˜ฏไป€ไนˆๅคๆ‚ไธœ่ฅฟ๏ผŒๅฐฑๆ˜ฏไธ€ไธชๅญ—็ฌฆไธฒๆจกๆฟๅ‡ฝๆ•ฐใ€‚ไฟ็•™ไธๅ˜๏ผŒๅชๆ˜ฏๆ•ฐๆฎๆฅๆบไปŽใ€Œ็”จๆˆทๅกซ่กจๅ•ใ€ๅ˜ไธบใ€ŒAI ๅฏน่ฏไธญๆๅ–ใ€ใ€‚
100
-
101
- **3. ไธบไป€ไนˆไธ้œ€่ฆๅ‘้‡ๆฃ€็ดข๏ผŸ**
102
- ไฝ ็›ด่ง‰ๆญฃ็กฎโ€”โ€”**็กฎๅฎžๅ†—ไฝ™ไบ†**ใ€‚ไน‹ๅ‰ๆˆ‘ๆๅ‡บๅ‘้‡ๆฃ€็ดข๏ผˆChromaDB๏ผ‰ๆ˜ฏไธบไบ†ๆ”ฏๆŒ่ฏญไน‰ๆœ็ดขใ€ŒไธŠๅ‘จไธ‰ๅƒไบ†ไป€ไนˆ๏ผŸใ€๏ผŒไฝ†ๅฎž้™…ไธŠ็›ดๆŽฅ็”จ JSON ๆŒ‰ๆ—ฅๆœŸ่ฟ‡ๆปคๅฐฑ่ƒฝๅฎž็Žฐใ€‚ๅŽปๆމๆญคๆ–นๆกˆ๏ผŒไฟๆŒ็ฎ€ๅ•ใ€‚
103
-
104
- **ๆ•ฐๆฎๆตๅ‘๏ผš**
105
  ```
106
- MiniCPM-o ๅ›žๅค (ๅซ [DIET_RECORD] ๆ ‡่ฎฐ)
107
- โ†’ Python ๆญฃๅˆ™่งฃๆž
108
- โ†’ ๅญ˜ๅ‚จๅˆฐ data/diet_logs.json (็ป“ๆž„ๅŒ–)
109
- โ†’ ๅŒๆ—ถ็”Ÿๆˆ data/logs/้ฅฎ้ฃŸๆ—ฅๅฟ—_YYYY-MM-DD.md (ๅฏ่ฏป)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  ```
111
 
112
- > **โœ… ๅทฒๆ นๆฎไฝ ็š„ๆ‰นๆณจไฟฎๆญฃ๏ผšๅŽปๆމ toolcall ๅ‡่ฎพ๏ผŒๆ”น็”จๆ ‡่ฎฐๆ ผๅผ่งฃๆž๏ผ›ๅŽปๆމๅ‘้‡ๆฃ€็ดข๏ผ›่ฏฆ็ป†่งฃ้‡Šไบ† Markdown ๆจกๆฟๅผ•ๆ“Žใ€‚**
113
 
114
- ---
115
 
116
- ### ๆจกๅ— 4๏ผš๐Ÿ“Š ่ฅๅ…ปๆŠฅๅ‘Š๏ผˆๅŸบไบŽไธญๅ›ฝๅฎ˜ๆ–นๆ ‡ๅ‡†๏ผ‰
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
- **ๆ ธๅฟƒๅ˜ๅŒ–๏ผšไปŽใ€Œๅ‡ญ่ฎฐๅฟ†็ผ–ๆ•ฐๆฎๅบ“ใ€ๅ˜ไธบใ€ŒๆŸฅไธญๅ›ฝๅฎ˜ๆ–น่ฅๅ…ปๆ ‡ๅ‡†ใ€**
119
 
120
- **ไธšๅŠก้œ€ๆฑ‚๏ผš**
121
- - ๅŸบไบŽไธญๅ›ฝๅฎ˜ๆ–น่ฅๅ…ปๆ ‡ๅ‡†ๅšๅˆ†ๆž
122
- - ่พ“ๅ‡บๅฏ่ง†ๅŒ–ๆŠฅๅ‘Š + ๆ”นๅ–„ๅปบ่ฎฎ
123
- - ๆจกๆฟ้ข„ๅ…ˆ่ฎพ่ฎกๅฅฝ๏ผŒ็พŽ่ง‚ไธ“ไธš
124
 
125
- **้œ€่ฆไฝ ไธ‹่ฝฝ็š„ๆ–‡ไปถๆธ…ๅ•๏ผš**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
- ่ฏทๆœ็ดขๅนถไธ‹่ฝฝไปฅไธ‹ๆ–‡ไปถ๏ผŒๆ”พๅˆฐ `data/nutrition/raw/` ็›ฎๅฝ•ไธ‹๏ผš
128
 
129
- | # | ๆ–‡ไปถๅ/ๅ…ณ้”ฎ่ฏ | ๅ‘ๅธƒๆœบๆž„ | ๅปบ่ฎฎๆœ็ดขๆ–นๅผ |
130
- |---|-------------|---------|------------|
131
- | 1 | **ไธญๅ›ฝ้ฃŸ็‰ฉๆˆๅˆ†่กจ๏ผˆๆ ‡ๅ‡†็‰ˆ๏ผ‰** ็ฌฌ6็‰ˆ | ไธญๅ›ฝ็–พๆŽงไธญๅฟƒ่ฅๅ…ปไธŽๅฅๅบทๆ‰€ | ๆœ็ดข "ไธญๅ›ฝ้ฃŸ็‰ฉๆˆๅˆ†่กจ ๆ ‡ๅ‡†็‰ˆ ็ฌฌ6็‰ˆ Excel" ๆˆ– PDF |
132
- | 2 | **ไธญๅ›ฝๅฑ…ๆฐ‘่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡๏ผˆDRIs 2023๏ผ‰** ๆ‘˜่ฆ | ไธญๅ›ฝ่ฅๅ…ปๅญฆไผš | ๆœ็ดข "DRIs 2023 ไธญๅ›ฝๅฑ…ๆฐ‘่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡" |
133
- | 3 | **ไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณ่†ณ้ฃŸๆŒ‡ๅ—๏ผˆ2022๏ผ‰** | ไธญๅ›ฝ่ฅๅ…ปๅญฆไผš | ๆœ็ดข "ๅญ•ๆœŸๅฆ‡ๅฅณ่†ณ้ฃŸๆŒ‡ๅ— 2022 ไธญๅ›ฝ่ฅๅ…ปๅญฆไผš" |
134
- | 4 | **ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผ๏ผˆWS/T 801-2022๏ผ‰** | ๅ›ฝๅฎถๅซๅฅๅง” | ๆœ็ดข "WS/T 801-2022 ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผ" |
135
 
136
- ๅฆ‚ๆžœไฝ ๆœ‰ไบ›ๆ–‡ไปถๆ‰พไธๅˆฐ๏ผŒ็ป™ๆˆ‘่ฏด๏ผŒๆˆ‘ๅๅŠฉๆœ็ดขใ€‚
 
 
 
 
 
 
 
 
 
 
137
 
138
- **ๅฆ‚ๆžœๆฒกๆœ‰ไธ‹่ฝฝๅˆฐๆญฃๅผๆ–‡ไปถๆ€ŽไนˆๅŠž๏ผš**
139
- ๆˆ‘ๅทฒ็ผ–ๅ†™ไบ†ไธ€ไปฝๅŸบไบŽ DRIs ๅ…ฌๅผ€ๆ•ฐๆฎ็š„่ฅๅ…ปๆ•ฐๆฎๅบ“ไฝœไธบ baseline๏ผˆๅฝ“ๅ‰ `DEFAULT_NUTRITION_DB`๏ผ‰๏ผŒๅฏไปฅๅ…ˆ็”จๅฎƒๅšๅŽŸๅž‹ๅผ€ๅ‘๏ผŒ็ญ‰ไฝ ๆ‰พๅˆฐๆญฃๅผๆ–‡ไปถๅŽๆ›ฟๆขๅณๅฏใ€‚
140
 
141
- > **โœ… ๅทฒๆ นๆฎไฝ ็š„ๆ‰นๆณจไฟฎๆญฃ๏ผšๅˆ—ๅ‡บๅ…ทไฝ“ๆ–‡ไปถๆธ…ๅ•๏ผŒไฝ ไธ‹่ฝฝๅŽๆˆ‘ๆ•ด็†ๆˆ JSONใ€‚**
142
 
143
- ---
 
 
 
 
 
144
 
145
- ## ไธ‰ใ€ไบคไบ’ๆต็จ‹่ฎพ่ฎก
 
 
146
 
147
- ### ๆ ธๅฟƒ่ฎพ่ฎกๅŽŸๅˆ™
148
 
149
- ไฝ ๆ‰นๆณจๅพ—ๅฏน๏ผš**ไธ้œ€่ฆ็ฉทไธพๆ‰€ๆœ‰ๆƒ…ๅ†ต๏ผŒ่€Œๆ˜ฏ่ฎพ่ฎกๅฅฝ MiniCPM-o ็š„็ณป็ปŸๆ็คบ่ฏ + ๅฝ“ๅ‰ๆจกๅผ็Šถๆ€ใ€‚**
150
 
151
- ### ็ณป็ปŸๆ็คบ่ฏๆžถๆž„
152
 
153
  ```
154
- ไฝ ๅซ PregoPal๏ผŒๆ˜ฏไธ€ไธชๅญ•ๆœŸ้™ชๆŠค AI ๅŠฉๆ‰‹ใ€‚
155
- ไฝ ็š„ไปปๅŠก๏ผš
156
- 1. ่ฏ†ๅˆซ่ฏด่ฏไบบ่บซไปฝ๏ผˆ้€š่ฟ‡ๅฃฐ้Ÿณๅˆคๆ–ญๆ˜ฏ่ฐๅœจ่ฏด่ฏ๏ผ‰
157
- 2. ๆ นๆฎๅฏน่ฏ็†่งฃ็”จๆˆท้œ€ๆฑ‚๏ผˆ่ฎฐๅฝ•้ฅฎ้ฃŸใ€ๆŽจ่่œๅ“ใ€้—ฒ่Š้™ชไผด๏ผ‰
158
- 3. ๅฝ“็”จๆˆทๆœ‰ๆ˜Ž็กฎ้œ€ๆฑ‚ๆ—ถ๏ผŒๆŒ‰ๆŒ‡ๅฎšๆ ผๅผ่พ“ๅ‡บ่ฎฐๅฝ•
159
-
160
- ๅฝ“ๅ‰ๆจกๅผ๏ผš{ๆจกๅผๅ็งฐ} โ† ๅŠจๆ€ๆณจๅ…ฅ๏ผˆไปปๅŠกๆจกๅผ/้—ฒ่Šๆจกๅผ๏ผ‰
161
- ๅฝ“ๅ‰่ฏด่ฏไบบ๏ผš{่บซไปฝ} โ† ๅฃฐ็บน่ฏ†ๅˆซ็ป“ๆžœ
162
-
163
- ่พ“ๅ‡บๆ ผๅผ่ง„ๅˆ™๏ผš
164
- - ๅฝ“็”จๆˆทๆ่ฟฐไบ†้ฅฎ้ฃŸๅ†…ๅฎน๏ผŒ่ฏทๅœจๅ›žๅคๆœซๅฐพ้™„ๅŠ  [DIET_RECORD]...[/DIET_RECORD]
165
- - ๅฝ“็”จๆˆท่ฆๆฑ‚ๆŽจ่่œๅ“๏ผŒ็›ดๆŽฅๆŽจ่ๅนถ็ป™ๅ‡บ็†็”ฑ
166
- - ๆ™ฎ้€šๅฏน่ฏไฟๆŒ่‡ช็„ถใ€ๆธฉ้ฆจใ€ๅ…ณๅฟƒ็š„่ฏญๆฐ”
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  ```
168
 
169
- ### ไบคไบ’ๆต็จ‹
170
 
171
- ```
172
- ็”จๆˆทๆ‰“ๅผ€ๆ‘„ๅƒๅคด+้บฆๅ…‹้ฃŽ
173
- โ”‚
174
- โ–ผ
175
- AI ๆ นๆฎ็ณป็ปŸๆ็คบ่ฏไธปๅŠจ้—ฎๅ€™
176
- โ”‚
177
- โ–ผ
178
- ็”จๆˆท่ฏด่ฏ โ†’ MiniCPM-o ๅ…จๅŒๅทฅๅค„็†
179
- โ”œโ†’ ๅฃฐ็บน่ฏ†ๅˆซ โ†’ ๆ›ดๆ–ฐใ€Œๅฝ“ๅ‰่ฏด่ฏไบบใ€
180
- โ”œโ†’ ็†่งฃ่ฏญไน‰ โ†’ ๆ›ดๆ–ฐใ€Œๅฝ“ๅ‰ๆจกๅผใ€
181
- โ””โ†’ ็”Ÿๆˆๅ›žๅค โ†’ ๅซ [DIET_RECORD] ๆ ‡่ฎฐ๏ผˆๅฆ‚้œ€๏ผ‰
182
- โ”‚
183
- โ–ผ
184
- ๅŽ็ซฏ่งฃๆžๅ›žๅค๏ผš
185
- โ”œโ†’ ๆฃ€ๆต‹ๅˆฐ [DIET_RECORD] โ†’ ๆๅ–ๆ•ฐๆฎ โ†’ ๅญ˜ JSON + Markdown
186
- โ”œโ†’ ๆฃ€ๆต‹ๅˆฐๆŽจ่่ฏทๆฑ‚ โ†’ ๆ˜พ็คบๆŽจ่็ป“ๆžœๅˆฐ UI
187
- โ””โ†’ ๅ…ถไป– โ†’ ๆญฃๅธธๅฏน่ฏ
188
- ```
189
 
190
- ### ๅŒๆจกๅผ่ฎพ่ฎก
191
 
192
- | ๆจกๅผ | ๅˆคๅฎšๆ–นๅผ | ่กŒไธบ |
193
- |------|---------|------|
194
- | ๐ŸŽฏ **ไปปๅŠกๆจกๅผ** | ็”จๆˆทๆๅˆฐใ€Œ่ฎฐๅฝ•ใ€ใ€ŒๆŽจ่ใ€ใ€Œๅˆ†ๆžใ€ใ€ŒๆŠฅๅ‘Šใ€็ญ‰ๅ…ณ้”ฎ่ฏ | ๆ‰ง่กŒๅฏนๅบ”ไธšๅŠก้€ป่พ‘ + ๆ ‡่ฎฐ่พ“ๅ‡บ |
195
- | ๐Ÿ’ฌ **้—ฒ่Šๆจกๅผ** | ็”จๆˆทๅผ€ๅฏๆ—ฅๅธธๅฏน่ฏ | ่‡ช็„ถ้™ชไผด๏ผŒไธๅš็ป“ๆž„ๅŒ–่ฎฐๅฝ• |
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
- > **โœ… ๅทฒๆ นๆฎไฝ ็š„ๆ‰นๆณจไฟฎๆญฃ๏ผš่š็„ฆ็ณป็ปŸๆ็คบ่ฏ่ฎพ่ฎก + ๆจกๅผ็ฎก็†๏ผŒไธ็ฉทไธพๆƒ…ๅ†ตใ€‚**
 
 
 
 
 
198
 
199
  ---
200
 
201
- ## ๅ››ใ€ๆŠ€ๆœฏๆ ˆไธ€่งˆ
 
 
 
 
 
 
202
 
203
- | ๅฑ‚็บง | ๆŠ€ๆœฏ | ็”จ้€” |
204
- |------|------|------|
205
- | ๆ ธๅฟƒๆจกๅž‹ | **MiniCPM-o 4.5**๏ผˆ็ปŸไธ€ๅคšๆจกๆ€ๆจกๅž‹๏ผ‰ | ๅ…จๅŒๅทฅๆŽจ็†๏ผš่ง†่ง‰+่ฏญ้Ÿณ+ๆ–‡ๆœฌ+่ฏญ้Ÿณ่พ“ๅ‡บ |
206
- | ๅ‰็ซฏๆก†ๆžถ | **Gradio** | Web ็•Œ้ข๏ผŒๅฎžๆ—ถๅฏน่ฏไบคไบ’ |
207
- | ๅฃฐ็บน่ฏ†ๅˆซ | **Whisper-medium encoder embedding**๏ผˆๆจกๅž‹ๅ†…็ฝฎ๏ผ‰ | ่ฏด่ฏไบบ่บซไปฝ่ฏ†ๅˆซ |
208
- | ้ข‘่ฐฑๆ–นๆกˆ | **NumPy + SoundFile**๏ผˆๅค‡้€‰ fallback๏ผ‰ | ๅฃฐ็บน่ฏ†ๅˆซๅ…œๅบ• |
209
- | ๆ•ฐๆฎๅญ˜ๅ‚จ | **JSON + Markdown**๏ผˆ็ป“ๆž„ๅŒ–ๅฏๆ‰ฉๅฑ•๏ผ‰ | ้ฅฎ้ฃŸ่ฎฐๅฝ• + ๆŠฅๅ‘Šๅญ˜ๆกฃ |
210
- | ่ฅๅ…ปๆ ‡ๅ‡† | **ไธญๅ›ฝๅฎ˜ๆ–น DRIs / ้ฃŸ็‰ฉๆˆๅˆ†่กจ**๏ผˆไฝ ไธ‹่ฝฝๅŽๆˆ‘ๆ•ด็†๏ผ‰ | ่ฅๅ…ปๅˆ†ๆžๅŸบๅ‡† |
211
- | ้ƒจ็ฝฒๅนณๅฐ | **Modal**๏ผˆไฝ ๆœ‰้ป‘ๅฎขๆพ้ขๅบฆ๏ผŒๅŽ็ปญ้…็ฝฎ๏ผ‰ | ไบ‘็ซฏ GPU ้ƒจ็ฝฒ |
212
-
213
- ### ๆ•ฐๆฎๅญ˜ๅ‚จ Schema ่ฎพ่ฎก๏ผˆๅฏๆ‰ฉๅฑ•๏ผ‰
214
-
215
- **JSON ๆ ผๅผ๏ผˆdiet_logs.json๏ผ‰๏ผš**
216
- ```json
217
- {
218
- "schema_version": "1.0",
219
- "records": [
220
- {
221
- "id": "a1b2c3d4",
222
- "date": "2026-06-07",
223
- "speaker": {"name": "ๅฐๆ˜Ž", "relation": "ไธˆๅคซ"},
224
- "meals": {"ๆ—ฉ้ค": "...", "ๅˆ้ค": "...", "ๆ™š้ค": "", "ๅŠ ้ค": "..."},
225
- "mood": "ๆŒบๅฅฝ",
226
- "notes": "",
227
- "extensions": {},
228
- "created_at": "2026-06-07T10:30:00"
229
- }
230
- ]
231
- }
232
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
 
234
- - `extensions: {}` ไฟ็•™็ป™ๆœชๆฅๆ‰ฉๅฑ•๏ผˆๅฆ‚่ก€็ณ–ใ€ไฝ“้‡ใ€่ƒŽๅŠจ็ญ‰๏ผ‰
235
- - `schema_version` ๆ”ฏๆŒๅŽ็ปญๆ•ฐๆฎ็ป“ๆž„ๅ‡็บง
 
236
 
237
- > **โœ… ๅทฒๆ นๆฎไฝ ็š„ๆ‰นๆณจไฟฎๆญฃ๏ผšๅŽปๆމใ€Œๅ…จๅฎถๆกถใ€่กจ่ฟฐ๏ผŒๆทปๅŠ ๆ•ฐๆฎ schema ่ฎพ่ฎก่ฏดๆ˜Žใ€‚**
238
 
239
  ---
240
 
241
- ## ไบ”ใ€ๆจกๅ—ๆ‹†ๅˆ†ๆ–นๆกˆ๏ผˆๆœ€็ปˆ็‰ˆ๏ผ‰
242
 
243
  ```
244
- PregoPal/
245
- โ”œโ”€โ”€ app.py # ไธปๅ…ฅๅฃ๏ผšๅฏๅŠจ Gradio + ๅŠ ่ฝฝๆจกๅž‹
246
- โ”œโ”€โ”€ config.py # ่ทฏๅพ„ / ๆžšไธพ / ๆจกๅž‹ๅ‚ๆ•ฐ / ็ณป็ปŸๆ็คบ่ฏๆจกๆฟ
247
- โ”œโ”€โ”€ core/ # AI ๆ ธๅฟƒๅฑ‚
248
- โ”‚ โ”œโ”€โ”€ __init__.py
249
- โ”‚ โ”œโ”€โ”€ model_loader.py # ๅŠ ่ฝฝ MiniCPM-o 4.5 ๆจกๅž‹
250
- โ”‚ โ”œโ”€โ”€ voice_processor.py # Whisper ASR + ๅฃฐ็บน embedding ๆๅ–
251
- โ”‚ โ”œโ”€โ”€ vision_processor.py # SigLip2 ่ง†่ง‰ๅค„็†
252
- โ”‚ โ””โ”€โ”€ conversation_manager.py # ๅฏน่ฏ็ฎก็† + ็ณป็ปŸๆ็คบ่ฏๆž„ๅปบ + [DIET_RECORD] ่งฃๆž
253
- โ”œโ”€โ”€ modules/ # ไธšๅŠก้€ป่พ‘ๅฑ‚
254
- โ”‚ โ”œโ”€โ”€ __init__.py
255
- ๏ฟฝ๏ฟฝ โ”œโ”€โ”€ voiceprint.py # ๅฃฐ็บนๆณจๅ†Œ/่ฏ†ๅˆซ๏ผˆ่ฐƒ็”จ core ๆˆ– fallback ้ข‘่ฐฑๆ–นๆกˆ๏ผ‰
256
- โ”‚ โ”œโ”€โ”€ meal_recommender.py # ่œๅ“ๆŽจ่๏ผˆ่ฐƒ็”จ MiniCPM-o ๆˆ–ๅ…œๅบ•่ง„ๅˆ™๏ผ‰
257
- โ”‚ โ”œโ”€โ”€ diet_logger.py # ้ฅฎ้ฃŸ่ฎฐๅฝ• + Markdown ็”Ÿๆˆ๏ผˆJSON ๅŒๅ†™๏ผ‰
258
- โ”‚ โ””โ”€โ”€ nutrition_analyzer.py # ่ฅๅ…ปๅˆ†ๆž๏ผˆๅŸบไบŽๅฎ˜ๆ–นๆ ‡ๅ‡†๏ผ‰+ matplotlib ๅฏ่ง†ๅŒ–
259
- โ”œโ”€โ”€ ui/ # ่กจ็Žฐๅฑ‚
260
- โ”‚ โ”œโ”€โ”€ __init__.py
261
- โ”‚ โ””โ”€โ”€ app_builder.py # Gradio ็•Œ้ข + ไบ‹ไปถ็ป‘ๅฎš
262
- โ”œโ”€โ”€ data/ # ๆ•ฐๆฎๅญ˜ๅ‚จ
263
- โ”‚ โ”œโ”€โ”€ nutrition/
264
- โ”‚ โ”‚ โ””โ”€โ”€ raw/ # โ† ไฝ ไธ‹่ฝฝ็š„่ฅๅ…ปๆ ‡ๅ‡†ๅŽŸๅง‹ๆ–‡ไปถๆ”พ่ฟ™้‡Œ
265
- โ”‚ โ”œโ”€โ”€ voices/ # ๅฃฐ็บนๆ•ฐๆฎ
266
- โ”‚ โ”œโ”€โ”€ logs/ # Markdown ้ฅฎ้ฃŸๆ—ฅๅฟ—
267
- โ”‚ โ””โ”€โ”€ reports/ # ๅฏผๅ‡บๆŠฅๅ‘Š
268
- โ”œโ”€โ”€ docs/
269
- โ”‚ โ”œโ”€โ”€ ้กน็›ฎ็†่งฃ_ๆŠ€ๆœฏๆžถๆž„.md # ๆœฌๆ–‡ๆกฃ
270
- โ”‚ โ””โ”€โ”€ ๅผ€ๅ‘ๆ—ฅๅฟ—.md # ่ฎฐๅฝ•้”™่ฏฏใ€่ฐƒ่ฏ•็ป้ชŒใ€ๆจกๅž‹่ฐƒ็”จๆŠ€ๅทง
271
- โ”œโ”€โ”€ requirements.txt # ๆฏๆฌก่ฟ่กŒๆˆๅŠŸๅŽๆ นๆฎ็Žฏๅขƒ็‰ˆๆœฌ้”ๅฎš
272
- โ””โ”€โ”€ README.md
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  ```
274
 
275
- > **โœ… ๅทฒ็กฎ่ฎคใ€‚**
276
 
277
  ---
278
 
279
- ## ๅ…ญใ€ๅ†ณ็ญ–่ฎฐๅฝ•๏ผˆไฝ ๅทฒๅ›ž็ญ”๏ผ‰
 
 
 
 
 
 
 
 
 
 
 
 
280
 
281
- | # | ้—ฎ้ข˜ | ไฝ ็š„ๅ†ณ็ญ– |
282
- |---|------|---------|
283
- | 1 | ๅฃฐ็บน่ฏ†ๅˆซๆ–นๆกˆ๏ผŸ | **Whisper-medium embedding**๏ผˆไผ˜ๅ…ˆ๏ผ‰๏ผŒ้ข‘่ฐฑ็›ธไผผๅบฆ๏ผˆๅค‡้€‰๏ผ‰ |
284
- | 2 | ้ƒจ็ฝฒๆ–นๅผ๏ผŸ | **Modal**๏ผˆไฝ ๆœ‰้ป‘ๅฎขๆพ้ขๅบฆ๏ผ‰๏ผŒๅŽ็ปญๆˆ‘ๅธฎไฝ ้…็ฝฎ |
285
- | 3 | ่ฅๅ…ปๆ ‡ๅ‡†่ฐๆฅๆ•ด็†๏ผŸ | **ไฝ ไธ‹่ฝฝๆ–‡ไปถ**ๅˆฐ `data/nutrition/raw/`๏ผŒๆˆ‘ๆ•ด็†ๆˆ JSON |
286
- | 4 | ๆ‹†ๅˆ†ๆ—ถๆœบ๏ผŸ | **ๅค„็†ๅฅฝไธŠ่ฟฐ้—ฎ้ข˜ๅŽ**็ซ‹ๅณๆ‹†ๅˆ† |
287
 
288
  ---
289
 
290
- ## ไธƒใ€ๅŽ็ปญ่กŒๅŠจ่ฎกๅˆ’๏ผˆๆŒ‰้กบๅบ๏ผ‰
291
 
292
- - [ ] **ไฝ ๅš็š„ไบ‹๏ผš** ไธ‹่ฝฝ่ฅๅ…ปๆ ‡ๅ‡†ๆ–‡ไปถๅˆฐ `data/nutrition/raw/`
293
- - [ ] **ๆˆ‘ๅš็š„ไบ‹๏ผš** ๆ›ดๆ–ฐๅผ€ๅ‘ๆ—ฅๅฟ— โ†’ ๅˆ—ๅ‡บ้œ€่ฆไธ‹่ฝฝ็š„่ฅๅ…ปๆ–‡ไปถๆธ…ๅ• โ†’ ็ญ‰ๆ–‡ไปถๅฐฑ็ปชๅŽๆ‰ง่กŒๆ–‡ไปถๆ‹†ๅˆ†
294
- - [ ] **็„ถๅŽ๏ผš** ็ ”็ฉถ Whisper-medium embedding ๆๅ–ๆ–นๆกˆ
295
- - [ ] **็„ถๅŽ๏ผš** ้…็ฝฎ Modal ้ƒจ็ฝฒ
296
- - [ ] **็„ถๅŽ๏ผš** ้€ๆญฅๆ›ฟๆข่ง„ๅˆ™ๅผ•ๆ“Žไธบ AI ้ฉฑๅŠจ
 
 
 
 
 
297
 
298
  ---
299
 
300
- *ๆ–‡ๆกฃ็”Ÿๆˆๆ—ถ้—ด๏ผš2026-06-07 | v3 - ๅทฒๆ•ดๅˆๆ‰€ๆœ‰ๆ‰นๆณจ*
 
1
+ # ๐ŸŒธ PregoPal ้กน็›ฎ็†่งฃไธŽๆŠ€ๆœฏๆžถๆž„๏ผˆv5 - ๆ•ดๅˆๆ‰นๆณจ๏ผŒ็ป†ๅŒ–ๅฎž็Žฐ๏ผ‰
2
 
3
+ > ๆœฌๆ–‡ๆกฃๅทฒๆ•ดๅˆไฝ ๆ‰€ๆœ‰ๆ‰นๆณจๆ„่ง๏ผŒๆฏไธชๅฐ่Š‚ไฟ็•™ๆ‰นๆณจๅŒบไพ›็ปง็ปญ่ฎจ่ฎบใ€‚
4
 
5
  ---
6
 
7
  ## ไธ€ใ€ไธ€ๅฅ่ฏๅฎšไฝ
8
 
9
+ **ไธ€ไธชๅŸบไบŽๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ Loop ้ฉฑๅŠจ็š„ๅญ•ๆœŸ้™ชๆŠค AI ๅŠฉๆ‰‹**๏ผšๆฏๅคฉ้ฆ–ๆฌกๅฏๅŠจๆ—ถ่‡ชๅŠจๆ€ป็ป“ๆ˜จๆ—ฅ้ฅฎ้ฃŸใ€ๅฏนๆฏ”ๅ›ฝๅฎถ่ฅๅ…ปๆ ‡ๅ‡†๏ผˆDRIs/่†ณ้ฃŸๆŒ‡ๅ—/ไฝ“้‡ๆ ‡ๅ‡†๏ผ‰๏ผŒ็”ŸๆˆไปŠๆ—ฅ็ฎ€ๆŠฅๆณจๅ…ฅๅฏน่ฏไธŠไธ‹ๆ–‡๏ผ›็™ฝๅคฉไธŽๅฎถๅบญๆˆๅ‘˜๏ผˆ้€š่ฟ‡ๅฃฐ็บนๅŒบๅˆ†๏ผ‰่‡ช็„ถไบคไบ’๏ผŒๅฎžๆ—ถ่ฎฐๅฝ•้ฅฎ้ฃŸใ€ๆŽจ่้ฃŸ่ฐฑ๏ผ›ๆฌกๆ—ฅๅพช็Žฏๅพ€ๅคใ€‚
10
 
11
+ > **ๆ‰นๆณจ๏ผˆๅทฒ้‡‡็บณ๏ผ‰๏ผš** ๅฎžๆ—ถ่ฎฐๅฝ•้ฅฎ้ฃŸ = ไธปๅŠจๆๅ–ๅญ•ๅฆ‡็š„้ฅฎ้ฃŸไน ๆƒฏใ€‚ๅœบๆ™ฏๅŒ…ๆ‹ฌ๏ผšโ‘ ๅญ•ๅฆ‡่‡ชๅทฑ่ฏดๆƒณๅƒไป€ไนˆ โ‘กๅฎถไบบ่ฏดๅญ•ๅฆ‡ไน‹ๅ‰ๆƒณๅƒไป€ไนˆ โ†’ ้ƒฝ่ฎฐๅฝ•ๅˆฐๅญ•ๅฆ‡็š„้ฅฎ้ฃŸไน ๆƒฏ md ๆ–‡ไปถใ€‚ๅŒๆ—ถไธปๅŠจ่ฏข้—ฎๅฎถไบบไผšๅšไป€ไนˆ่œ โ†’ ่ฎฐๅฝ•ๅˆฐๅฎถๅบญ่œๅ•ใ€‚้€š่ฟ‡ system prompt + ๆญฃๅˆ™ๅŒ–ๆๅ–ๅฎž็Žฐใ€‚
12
 
13
  ---
14
 
15
+ ## ไบŒใ€ไธ‰ไธช่ฅๅ…ปๆ–‡ๆกฃ็š„ๆ“ไฝœๆ–นๆณ•
16
+
17
+ ไฝ ๅทฒ็ปไธ‹่ฝฝๅˆฐ `data/nutrition/raw/` ็š„ไธ‰ไธชๆ–‡ไปถ๏ผŒๅ„่‡ชๆ‰ฟๆ‹…ไธๅŒ่ง’่‰ฒ๏ผš
18
+
19
+ | ๆ–‡ๆกฃ | ๆ–‡ไปถ | ็”จ้€” | PregoPal ็š„ๆ“ไฝœๆ–นๅผ |
20
+ |------|------|------|-------------------|
21
+ | **โ‘  ไฝ“้‡ๅขž้•ฟๆ ‡ๅ‡†** | `ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผๆ ‡ๅ‡†.md` | ไฝ“้‡็›‘ๆต‹ๅŸบๅ‡† | **ไธปๅŠจ่ฏข้—ฎไฝ“้‡** โ€” ๆฏๅคฉ Loop ไธญๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ่ฏข้—ฎ๏ผŒๅฏน็…ง BMI ๅˆ†็ฑป็ป™ๅ‡บ่ฏ„ไปท |
22
+ | **โ‘ก ่†ณ้ฃŸๆŒ‡ๅ—** | `ไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณ่†ณ้ฃŸๆŒ‡ๅ—2022ๅ›พ็‰‡่ฝฌmd็‰ˆ.md` | ้ฃŸ่ฐฑๆŽจ่ๅŸบๅ‡† | **ไฝœไธบๆŽจ่้ฃŸ่ฐฑ็š„็บฆๆŸๅŸบ็ก€** โ€” ๆ นๆฎๅญ•ๆœŸ้˜ถๆฎต็”จๅฎๅก”ๆŽจ่้‡็”Ÿๆˆๆจกๆฟ |
23
+ | **โ‘ข DRIs** | `ๅค‡ๅญ•&ๅญ•ๆ—ฉไธญๆ™šไธ‰ๆœŸๅ’Œๅ“บไนณๆœŸ็š„ๆ‰€ๆœ‰่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡.md` | ่ฅๅ…ปๅˆ†ๆžๅŸบๅ‡† | **Agent ๅฎšๆœŸๆ€่€ƒ** โ€” ๆฏๅคฉ่‡ชๅŠจๅฏนๆฏ” RNI๏ผŒๅˆ†ๆžไธ่ถณ๏ผŒๅ†™ๅ…ฅๆฌกๆ—ฅ้ข„่ฎพ |
24
+
25
+ > **ๆ‰นๆณจ๏ผˆๅทฒ้‡‡็บณ๏ผ‰๏ผš** ๆ‰€ๆœ‰ md ๆ–‡ไปถ้ƒฝ้œ€่ฆๆˆ‘ไปฌ่‡ชๅทฑๅ†™ๅ‡ฝๆ•ฐ่ฏปๅ–๏ผŒ่€Œไธๆ˜ฏ่ฎฉๅคงๆจกๅž‹่‡ชๅทฑ่ฏปใ€‚ๆ•ฐๆฎ็ฑป็š„้œ€่ฆๅ†™ๅ…จ้ข็š„่ฏปๅ–ๆฏ”่พƒๅ‡ฝๆ•ฐๆŽฅๅฃ๏ผŒๆ–‡ๆœฌ็ฑป็š„้œ€่ฆ่ฎพ่ฎกๅฅฝ่‡ชๅŠจๆๅ–่พ“ๅ‡บ็š„ๅ‡ฝๆ•ฐใ€‚ๆฏๆ—ฅ็ฌฌไธ€ๆฌกๅฏน่ฏๅ‰ PregoPal ่‡ชๅŠจๆ•ด็†ๅฝ“ๅคฉ็š„ๅ‰็ฝฎ system prompt ๆ—ถ๏ผŒ่ฆ่€ƒ่™‘๏ผš่ฅๅ…ปใ€ไฝ“้‡ใ€ๅฎถๅบญ่œ่ฐฑใ€่ฅๅ…ป็ด ้œ€ๆฑ‚ใ€ๆ ธๅฟƒ่ฎฐๅฟ†ๆ–‡ไปถ๏ผˆๅฎถๅบญๅ…ณ็ณปใ€่ฐๅ’Œ่ฐไบฒ่ฟ‘ใ€ๅฎถ้‡Œๅ‘็”Ÿ่ฟ‡ไป€ไนˆ๏ผ‰ใ€‚
26
+
27
+ ### 2.1 ไฝ“้‡ๅขž้•ฟๆ ‡ๅ‡† โ†’ ไธปๅŠจ่ฏข้—ฎไฝ“้‡
28
+
29
+ **ๅฎž็Žฐๆ–นๅผ**๏ผšๅ†™ไธ€ไธช `WeightStandardParser` ็ฑป๏ผŒๅฐ† WS/T 801-2022 ่กจ1 ็ผ–่ฏ‘ไธบ็ป“ๆž„ๅŒ–ๆ•ฐๆฎ๏ผŒๆไพ›ๆŸฅ่ฏขๆŽฅๅฃใ€‚
30
+
31
+ ```python
32
+ # modules/nutrition_standards.py๏ผˆๆ–ฐๅขž๏ผ‰
33
+ class WeightStandardParser:
34
+ """่งฃๆžไฝ“้‡ๅขž้•ฟๆ ‡ๅ‡† md ๆ–‡ไปถ๏ผŒๆไพ›ๆŸฅ่ฏขๆŽฅๅฃ"""
35
+
36
+ @staticmethod
37
+ def load() -> dict:
38
+ """่ฏปๅ– md ๆ–‡ไปถ๏ผŒ่ฟ”ๅ›ž็ป“ๆž„ๅŒ–ๆ•ฐๆฎ"""
39
+ # ่ฟ”ๅ›ž๏ผš
40
+ # {
41
+ # "bmi_standards": [
42
+ # {"category": "ไฝŽไฝ“้‡", "bmi_range": (0, 18.5),
43
+ # "total_gain": (11.0, 16.0), "weekly_gain": 0.46,
44
+ # "weekly_range": (0.37, 0.56)},
45
+ # ...
46
+ # ]
47
+ # }
48
+
49
+ @staticmethod
50
+ def evaluate(bmi_before_pregnancy: float, current_week: int,
51
+ total_gain: float) -> dict:
52
+ """่ฏ„ไผฐไฝ“้‡ๅขž้•ฟๆ˜ฏๅฆๅœจๆŽจ่่Œƒๅ›ดๅ†…"""
53
+ # ่ฟ”ๅ›ž {"status": "ok"/"warning", "message": "...", "suggestion": "..."}
54
+ ```
55
+
56
+ **่ฐƒ็”จๆ—ถๆœบ**๏ผšๆฏๅคฉๆ—ฉไธŠ Loop ็š„ `weight_check` ๆ’ไปถ่ฐƒ็”จๆญคๅ‡ฝๆ•ฐ๏ผŒ็ป“ๆžœๅ†™ๅ…ฅไปŠๆ—ฅ็ฎ€ๆŠฅใ€‚
57
 
58
+ > **ๆ‰นๆณจ๏ผˆๅทฒ้‡‡็บณ๏ผ‰๏ผš** ๆ•ด็†ๆˆๅ‡ฝๆ•ฐ๏ผŒไธ่ฆๆœŸๅพ… 32B ๅฐๅ‚ๆ•ฐๆจกๅž‹ๅŽปๅš่ฟ™ไบ›๏ผŒ่€Œๆ˜ฏ่‡ชๅŠจๆ”พๅˆฐไธŠไธ‹ๆ–‡ไธญใ€‚
59
 
60
+ ### 2.2 ่†ณ้ฃŸๆŒ‡ๅ— โ†’ ้ฃŸ่ฐฑๆŽจ่ๅŸบ็ก€
61
 
62
+ **ๅฎž็Žฐๆ–นๅผ**๏ผšๅ†™ไธ€ไธช `DietaryGuideParser` ็ฑป๏ผŒๅฐ†ๅนณ่กก่†ณ้ฃŸๅฎๅก”็ผ–่ฏ‘ไธบ็ป“ๆž„ๅŒ–ๆ•ฐๆฎใ€‚
 
 
 
63
 
64
+ ```python
65
+ # modules/nutrition_standards.py
66
+ class DietaryGuideParser:
67
+ """่งฃๆž่†ณ้ฃŸๆŒ‡ๅ— md ๆ–‡ไปถ๏ผŒๆไพ›ๅ„ๅญ•ๆœŸๆŽจ่ๆ‘„ๅ…ฅ้‡"""
68
+
69
+ @staticmethod
70
+ def get_recommendations(trimester: str) -> dict:
71
+ """่ฟ”ๅ›žๆŒ‡ๅฎšๅญ•ๆœŸ็š„้ฃŸ็‰ฉๆŽจ่้‡"""
72
+ # ่ฟ”ๅ›žๅญ•ไธญๆœŸ/ๅญ•ๆ™šๆœŸ/ๅ“บไนณๆœŸ็š„ๅฎๅก”ๆ•ฐๆฎ
73
+
74
+ @staticmethod
75
+ def get_core_principles() -> list[str]:
76
+ """่ฟ”ๅ›žๅ…ญๆกๆ ธๅฟƒๅปบ่ฎฎ"""
77
+ ```
78
 
79
+ **ไธŽๅฎถๅบญ่œ่ฐฑ็ป“ๅˆ**๏ผš
80
+ - `data/family/recipes.md` โ€” ่ฎฐๅฝ•ๅฎถไบบไผšๅš็š„่œ๏ผˆไธปๅŠจ่ฏข้—ฎๅŽ่ฎฐๅฝ•๏ผ‰
81
+ - `data/family/preferences.md` โ€” ่ฎฐๅฝ•ๆ‰€ๆœ‰ๅฎถไบบ็š„้ฅฎ้ฃŸๅๅฅฝใ€ๅฟŒๅฃใ€่ฟ‡ๆ•
82
+ - ๆŽจ่้ฃŸ่ฐฑๆ—ถ๏ผš่†ณ้ฃŸๆŒ‡ๅ—็บฆๆŸ + ๅฎถๅบญ่œ่ฐฑ่ฟ‡ๆปค + ไธชไบบๅๅฅฝๆŽ’ๅบ
83
+
84
+ > **ๆ‰นๆณจ๏ผˆๅทฒ้‡‡็บณ๏ผ‰๏ผš** ้œ€่ฆ่ฎพ่ฎกๅฅฝๅฆ‚ไฝ•ไธŽ็”จๆˆทๅฎถๅบญ่œ่ฐฑ็ป“ๅˆ๏ผŒ่€Œไธๆ˜ฏๅŽปๆๅ‡บๅšไธ€ไบ›ไธๅฏ่ƒฝ็š„่œใ€‚้ฅฎ้ฃŸๅๅฅฝๅบ”่ฏฅ่ฎฐๅฝ•ๆ‰€ๆœ‰ๅฎถไบบ๏ผˆไธๅชๆ˜ฏๅญ•ๅฆ‡๏ผ‰๏ผŒๅˆ†ๆจกๅ—่ฎฐๅฝ•๏ผŒ่ฎพ่ฎกๅฅฝๆๅ–็š„ๅ‡ฝๆ•ฐๆŽฅๅฃใ€‚ๆณจๆ„่ฎฐๅฝ•ๅฎถ้‡Œๆ‰€ๆœ‰ไบบๆ˜ฏๅฆๆœ‰ๅฟŒๅฃใ€่ฟ‡ๆ•ใ€‚
85
+
86
+ ### 2.3 DRIs โ†’ Agent ๅฎšๆœŸๅˆ†ๆž๏ผˆ่‡ชๅŠจ่ฟ่กŒ โ†’ ๅ†™ๅ…ฅๆฌกๆ—ฅ้ข„่ฎพ๏ผ‰
87
+
88
+ **ๆ”น่ฟ›ๆ–นๆกˆ**๏ผš
89
+
90
+ ```python
91
+ # modules/nutrition_standards.py
92
+ class DRIsParser:
93
+ """่งฃๆž DRIs md ๆ–‡ไปถ๏ผˆ่กจ15-18๏ผ‰๏ผŒๆไพ›่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡ๆŸฅ่ฏข"""
94
+
95
+ @staticmethod
96
+ def get_rni(stage: str) -> dict:
97
+ """่ฟ”ๅ›žๆŒ‡ๅฎš้˜ถๆฎต็š„ RNI ๆ•ฐๆฎ
98
+ stage: "pre_pregnancy" / "early" / "mid" / "late" / "lactation"
99
+ """
100
+
101
+ @staticmethod
102
+ def compare_with_intake(stage: str, intake: dict) -> dict:
103
+ """ๅฏนๆฏ”ๅฎž้™…ๆ‘„ๅ…ฅไธŽ RNI๏ผŒ่ฟ”ๅ›žๅทฎๅผ‚ๅˆ†ๆž"""
104
+ # ่ฟ”ๅ›žๆฏไธช่ฅๅ…ป็ด ็š„ๅทฎๅผ‚็™พๅˆ†ๆฏ” + ้‡็‚นๅ…ณๆณจๆ ‡่ฎฐ
105
+ ```
106
 
107
+ **ๅˆ†ๆžๆต็จ‹**๏ผš
108
+ 1. ่ฏปๅ–ๆ˜จๆ—ฅ้ฅฎ้ฃŸๆ—ฅๅฟ—๏ผˆ`data/logs/้ฅฎ้ฃŸๆ—ฅๅฟ—_YYYY-MM-DD.md`๏ผ‰
109
+ 2. ็”จ `DRIsParser.compare_with_intake()` ๅฏนๆฏ”
110
+ 3. ็ป“ๅˆๅฎถๅบญ่œ่ฐฑ๏ผŒ็ป™ๅ‡บใ€ŒไปŠๅคฉๅปบ่ฎฎๅคšๅƒๅ“ชไบ›ๅฎถ้‡Œ่ƒฝๅš็š„่œใ€
111
+ 4. ๅ†™ๅ…ฅ `data/presets/ไปŠๆ—ฅ็ฎ€ๆŠฅ_YYYY-MM-DD.json`
112
 
113
+ > **ๆ‰นๆณจ๏ผˆๅพ…ๆ”น่ฟ›๏ผ‰๏ผš** ่ฏทๅŸบไบŽๅ…ถๅฎƒๆ‰นๆณจๆ”น่ฟ›ๆ–นๆกˆใ€‚โœ… ๅทฒๆ”น่ฟ›๏ผš็ป“ๅˆๅฎถๅบญ่œ่ฐฑ๏ผŒๅปบ่ฎฎๅ…ทไฝ“ๅฏๅš็š„่œใ€‚
114
 
115
  ---
116
 
117
+ ## ไธ‰ใ€ๆ ธๅฟƒๆžถๆž„๏ผšLoop ้ฉฑๅŠจ๏ผˆ็Šถๆ€ๆœบ + ๆ’ไปถๆณจๅ†Œ๏ผ‰
118
 
119
+ ### 3.1 ่ฎพ่ฎก็†ๅฟต
120
 
121
+ PregoPal ไธๆ˜ฏไธ€ไธชใ€Œ็”จๆˆท็‚นๆŒ‰้’ฎ โ†’ ๅ‡บ็ป“ๆžœใ€็š„่ขซๅŠจๅบ”็”จ๏ผŒ่€Œๆ˜ฏ**ๆœ‰ๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ็š„ไธปๅŠจไผดไพฃ**ใ€‚
 
 
 
122
 
123
+ ๅ‚่€ƒไฝ ๆไพ›็š„ `nanobot_core/agent/loop.py` ไธญ็š„**็Šถๆ€ๆœบไบ‹ไปถ้ฉฑๅŠจๆจกๅผ**๏ผŒPregoPal ็š„ Loop ๆๅ–ไธคไธชๆ ธๅฟƒ่ฎพ่ฎก๏ผš
 
 
 
 
124
 
125
+ 1. **TurnState ็Šถๆ€ๆœบ** โ€” ็ฎก็†ๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ็š„้˜ถๆฎตๆต่ฝฌ
126
+ 2. **ๅฏๆณจๅ†Œ็š„ๆ‰ฉๅฑ•่ƒฝๅŠ›** โ€” ๆฏไธช้˜ถๆฎต็š„ๅ…ทไฝ“้€ป่พ‘็”ฑ Plugin ๅฎž็Žฐ
127
 
128
+ > **ๆ‰นๆณจ๏ผˆๅทฒ้‡‡็บณ๏ผ‰๏ผš** ๅ…ทไฝ“ๅฎž็Žฐไธ่ƒฝๅคชๅคๆ‚๏ผŒ่พพๅˆฐ็›ฎ็š„๏ผŒๅ…ทๆœ‰ๅฏๆ‹“ๅฑ•ๆ€ง๏ผŒๅ…ทๆœ‰็จณๅฎšๆ€ง๏ผˆไธไผšๅ› ไธบๆจกๅž‹ๅถๅฐ”็š„็Šฏ้”™ๆˆ–่€…่พ“ๅ‡บไธ็จณๅฎš่€ŒๅฎŒๅ…จ้€ป่พ‘ๆททไนฑ๏ผ‰ใ€‚
129
 
130
+ ### 3.2 ๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผˆv5 ๆ”น่ฟ›็‰ˆ๏ผ‰
131
+
132
+ ๆ นๆฎไฝ ็š„ๆ‰นๆณจ๏ผŒๅ…ณ้”ฎๅ˜ๆ›ด๏ผš
133
+ - **่งฆๅ‘ๆ—ถๆœบ**๏ผšๆฏๆ™š 00:00 ่‡ชๅŠจๆ€ป็ป“๏ผˆๆˆ–็จ‹ๅบๅฏๅŠจๆ—ถๆฃ€ๆŸฅ็Šถๆ€ไฝ๏ผ‰
134
+ - **ๆ–ฐๅขž้˜ถๆฎต**๏ผš`FAMILY_QUIZ`๏ผˆไธปๅŠจ่ฏข้—ฎๅฎถๅบญ่œ่ฐฑ/ๅๅฅฝ๏ผ‰ใ€`THREE_DAY_SUMMARY`๏ผˆๆฏไธ‰ๅคฉๆ€ป็ป“๏ผ‰
135
+ - **็Šถๆ€ไฝๆœบๅˆถ**๏ผš`data/presets/.daily_status.json` ่ฎฐๅฝ•ๆฏๆ—ฅๅฎŒๆˆ็Šถๆ€
136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  ```
138
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
139
+ โ”‚ LAUNCH โ”‚ โ† ๆฃ€ๆŸฅไปŠๆ—ฅ็Šถๆ€ไฝ
140
+ โ”‚ (ๅฏๅŠจ) โ”‚ ่‹ฅๅทฒๆ€ป็ป“ โ†’ ็›ดๆŽฅ INTERACT
141
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ่‹ฅๆœชๆ€ป็ป“ โ†’ ่ฟ›ๅ…ฅๆ€ป็ป“ๆต็จ‹
142
+ โ”‚
143
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
144
+ โ”‚ โ”‚
145
+ ไปŠๆ—ฅๆœชๆ€ป็ป“ ไปŠๆ—ฅๅทฒๆ€ป็ป“
146
+ โ”‚ โ”‚
147
+ โ–ผ โ–ผ
148
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
149
+ โ”‚ FAMILY_QUIZ โ”‚ โ”‚ โ”‚
150
+ โ”‚ (ๅฎถๅบญ้—ฎๅท) โ”‚ โ”‚ โ”‚
151
+ โ”‚ โ”œ ๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ โ”‚ โ”‚ โ”‚
152
+ โ”‚ โ”‚ ่ฏข้—ฎๆ–ฐ่œ่ฐฑ โ”‚ โ”‚ โ”‚
153
+ โ”‚ โ”” ๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ โ”‚ โ”‚ โ”‚
154
+ โ”‚ ่ฏข้—ฎไฝ“้‡ โ”‚ โ”‚ โ”‚
155
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
156
+ โ”‚ โ”‚ โ”‚
157
+ โ–ผ โ”‚ โ”‚
158
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
159
+ โ”‚ SUMMARIZE โ”‚ โ”‚ โ”‚
160
+ โ”‚ (ๆ˜จๆ—ฅๆ€ป็ป“) โ”‚ โ”‚ โ”‚
161
+ โ”‚ โ”œ ่ฏปๅ–้ฅฎ้ฃŸๆ—ฅๅฟ— โ”‚ โ”‚ โ”‚
162
+ โ”‚ โ”œ ่ฏปๅ–ไฝ“้‡่ฎฐๅฝ• โ”‚ โ”‚ โ”‚
163
+ โ”‚ โ”” ่ฏปๅ–ๅฎถๅบญ่ฎฐๅฟ† โ”‚ โ”‚ โ”‚
164
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
165
+ โ”‚ โ”‚ โ”‚
166
+ โ–ผ โ”‚ โ”‚
167
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
168
+ โ”‚ ANALYZE โ”‚ โ”‚ โ”‚
169
+ โ”‚ (่ฅๅ…ปๅˆ†ๆž) โ”‚ โ”‚ โ”‚
170
+ โ”‚ โ”” ๅฏนๆฏ”DRIs โ”‚ โ”‚ โ”‚
171
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
172
+ โ”‚ โ”‚ โ”‚
173
+ โ–ผ โ”‚ โ”‚
174
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
175
+ โ”‚ BRIEF โ”‚ โ”‚ โ”‚
176
+ โ”‚ (็”Ÿๆˆ็ฎ€ๆŠฅ) โ”‚ โ”‚ โ”‚
177
+ โ”‚ โ”” ๅ†™JSON โ”‚ โ”‚ โ”‚
178
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
179
+ โ”‚ โ”‚ โ”‚
180
+ โ–ผ โ–ผ โ”‚
181
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
182
+ โ”‚ INTERACT โ”‚โ—„โ”€โ”˜
183
+ โ”‚ (็™ฝๅคฉไบคไบ’ๆจกๅผ) โ”‚
184
+ โ”‚ ๏ฟฝ๏ฟฝ ๅฃฐ็บน่ฏ†ๅˆซ โ†’ ๅŒบๅˆ†่ฏด่ฏไบบ โ”‚
185
+ โ”‚ โ”œ ๅฏน่ฏ็†่งฃ โ†’ ๆญฃๅˆ™ๆๅ–้ฅฎ้ฃŸ่ฎฐๅฝ• โ”‚
186
+ โ”‚ โ”‚ โ†’ ๅ†™ๅ…ฅ้ฅฎ้ฃŸไน ๆƒฏ.md โ”‚
187
+ โ”‚ โ”‚ โ†’ ๅ†™ๅ…ฅๅฎถๅบญ่œ่ฐฑ.md โ”‚
188
+ โ”‚ โ”œ ๆŽจ่ โ†’ ่†ณ้ฃŸๆŒ‡ๅ—+ๅฎถๅบญ่œ่ฐฑ็บฆๆŸ โ”‚
189
+ โ”‚ โ”” ็ฎ€ๆŠฅๆณจๅ…ฅ โ†’ AI ็Ÿฅ้“ไปŠๆ—ฅๅ…ณๆณจ็‚น โ”‚
190
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
191
+ โ”‚
192
+ ๆฏๆ™š 00:00๏ผˆๆˆ–ๅ…ณ้—ญๆ—ถ๏ผ‰
193
+ โ”‚
194
+ โ–ผ
195
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
196
+ โ”‚ CONSOLIDATE โ”‚
197
+ โ”‚ (ๆ™š้—ดๆ•ด็†) โ”‚
198
+ โ”‚ โ”œ ๆฑ‡ๆ€ปไปŠๆ—ฅ โ”‚
199
+ โ”‚ โ”œ ๆฃ€ๆŸฅๆ˜ฏๅฆๅˆฐ โ”‚
200
+ โ”‚ โ”‚ ไธ‰ๅคฉๆ€ป็ป“ โ”‚
201
+ โ”‚ โ”” ๅ†™ๆ˜Žๆ—ฅ้ข„่ฎพ โ”‚
202
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
203
+ โ”‚
204
+ โ–ผ
205
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
206
+ โ”‚ DONE โ”‚
207
+ โ”‚ ๆ ‡่ฎฐไปŠๆ—ฅๅฎŒๆˆ โ”‚
208
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
209
+ ```
210
+
211
+ > **ๆ‰นๆณจ๏ผˆๅทฒ้‡‡็บณ๏ผ‰๏ผš** ๆฏๆ™š 00:00 ่‡ชๅŠจๆ€ป็ป“๏ผŒ่ฎพ็ฝฎ็Šถๆ€ไฝใ€‚็จ‹ๅบๅ…ณ้—ญๅŽ็ฌฌไบŒๅคฉๅฏๅŠจ่‡ชๅŠจๆฃ€ๆŸฅ็Šถๆ€ไฝใ€‚็•Œ้ข่ฎพ่ฎก๏ผš4 ไธชๅญ้กต้ขใ€‚
212
+
213
+ ### 3.3 ็Šถๆ€ๆœบๅฎšไน‰๏ผˆv5 ๆ”น่ฟ›็‰ˆ๏ผ‰
214
+
215
+ ```python
216
+ class LoopState(Enum):
217
+ LAUNCH = "launch" # ๅฏๅŠจๆฃ€ๆŸฅ๏ผšๆฃ€ๆŸฅไปŠๆ—ฅ็Šถๆ€ไฝ
218
+ FAMILY_QUIZ = "family_quiz" # ๅฎถๅบญ้—ฎๅท๏ผšๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ่ฏข้—ฎ่œ่ฐฑ/ไฝ“้‡
219
+ SUMMARIZE = "summarize" # ๆ˜จๆ—ฅๆ€ป็ป“๏ผšๅˆ†ๆžๆ˜จๆ—ฅ้ฅฎ้ฃŸ/ไฝ“้‡/ๅฎถๅบญ่ฎฐๅฟ†
220
+ ANALYZE = "analyze" # ่ฅๅ…ปๅˆ†ๆž๏ผšๅฏนๆฏ” DRIs
221
+ BRIEF = "brief" # ็”ŸๆˆไปŠๆ—ฅ็ฎ€ๆŠฅ
222
+ INTERACT = "interact" # ็™ฝๅคฉไบคไบ’ๆจกๅผ๏ผˆ็ญ‰ๅพ…็”จๆˆทๆ“ไฝœ๏ผ‰
223
+ THREE_DAY = "three_day" # ๆฏไธ‰ๅคฉ่‡ชๅŠจๆ€ป็ป“๏ผˆ็”ฑ CONSOLIDATE ่งฆๅ‘๏ผ‰
224
+ CONSOLIDATE = "consolidate" # ๆ™š้—ดๆ•ด็†
225
+ DONE = "done"
226
+
227
+ _TRANSITIONS = {
228
+ (LoopState.LAUNCH, "need_summary"): LoopState.FAMILY_QUIZ,
229
+ (LoopState.LAUNCH, "already_done"): LoopState.INTERACT,
230
+ (LoopState.FAMILY_QUIZ, "ok"): LoopState.SUMMARIZE,
231
+ (LoopState.SUMMARIZE, "ok"): LoopState.ANALYZE,
232
+ (LoopState.ANALYZE, "ok"): LoopState.BRIEF,
233
+ (LoopState.BRIEF, "ok"): LoopState.INTERACT,
234
+ (LoopState.INTERACT, "day_ended"): LoopState.CONSOLIDATE,
235
+ (LoopState.CONSOLIDATE, "need_3day"): LoopState.THREE_DAY,
236
+ (LoopState.CONSOLIDATE, "ok"): LoopState.DONE,
237
+ (LoopState.THREE_DAY, "ok"): LoopState.DONE,
238
+ }
239
  ```
240
 
241
+ > **ๆ‰นๆณจ๏ผˆๅทฒ้‡‡็บณ๏ผ‰๏ผš** ็Šถๆ€ๆœบ่ฎพ่ฎกๆ นๆฎ็›ฎ็š„่ฟญไปฃ๏ผŒๅทฒๆ•ดๅˆไธŠไธ‹ๆ‰นๆณจใ€‚
242
 
243
+ ### 3.4 ็Šถๆ€ๅค„็†ๅ™จ
244
 
245
+ | ็Šถๆ€ | Handler | ๅŠŸ่ƒฝ |
246
+ |------|---------|------|
247
+ | `LAUNCH` | `_state_launch()` | ่ฏปๅ– `data/presets/.daily_status.json` โ†’ ๅ†ณๅฎšๆต็จ‹ |
248
+ | `FAMILY_QUIZ` | `_state_family_quiz()` | ๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ่ฏข้—ฎๆ–ฐ่œ่ฐฑ/ไฝ“้‡ โ†’ ๅ†™ๅ…ฅไปŠๆ—ฅ็ฎ€ๆŠฅๅพ…ๅŠž |
249
+ | `SUMMARIZE` | `_state_summarize()` | ้ๅކๆ‰ง่กŒ SUMMARIZE ้˜ถๆฎต Plugin |
250
+ | `ANALYZE` | `_state_analyze()` | ้ๅކๆ‰ง่กŒ ANALYZE ้˜ถๆฎต Plugin |
251
+ | `BRIEF` | `_state_brief()` | ๆฑ‡ๆ€ปไธบ `ไปŠๆ—ฅ็ฎ€ๆŠฅ.json` |
252
+ | `INTERACT` | `_state_interact()` | ็ญ‰ๅพ…็”จๆˆทไบคไบ’๏ผŒๆถˆ่ดน Gradio event queue |
253
+ | `THREE_DAY` | `_state_three_day()` | ๆฏไธ‰ๅคฉ่ฟ่กŒ๏ผšๅˆ†ๆž่ฅๅ…ป็ผบๅคฑ โ†’ ๆ”น่ฟ›ๅฎถๅบญ่œๅ•ๅปบ่ฎฎ |
254
+ | `CONSOLIDATE` | `_state_consolidate()` | ๆ™š้—ดๆ•ด็†๏ผŒๆฃ€ๆŸฅๆ˜ฏๅฆ่งฆๅ‘ THREE_DAY |
255
+ | `DONE` | `_state_done()` | ๅ†™ๅ…ฅ็Šถๆ€ไฝ๏ผŒๆธ…็†่ต„ๆบ |
256
+
257
+ > **ๆ‰นๆณจ๏ผˆๅทฒ้‡‡็บณ๏ผ‰๏ผš** ็Šถๆ€ๅค„็†ๅ™จๆ นๆฎ็›ฎ็š„่ฟญไปฃ๏ผŒๅทฒๆ•ดๅˆไธŠไธ‹ๆ‰นๆณจใ€‚
258
+
259
+ ### 3.5 ไธปๅพช็Žฏๅ…ฅๅฃ
260
+
261
+ ```python
262
+ class PregoPalLoop:
263
+ def __init__(self):
264
+ self.plugins = PluginRegistry()
265
+ self.state = LoopState.LAUNCH
266
+ self._register_default_plugins()
267
+
268
+ async def run(self) -> None:
269
+ while self.state is not LoopState.DONE:
270
+ handler_name = f"_state_{self.state.value}"
271
+ handler = getattr(self, handler_name)
272
+ event = await handler()
273
+ next_state = _TRANSITIONS.get((self.state, event))
274
+ if next_state is None:
275
+ raise RuntimeError(f"No transition from {self.state} on {event}")
276
+ self.state = next_state
277
+ ```
278
 
279
+ > **ๆ‰นๆณจ๏ผš** ________
280
 
281
+ ---
 
 
 
282
 
283
+ ## ๅ››ใ€ๆ’ไปถ็ณป็ปŸ่ฎพ่ฎก๏ผˆๅฏๆ‰ฉๅฑ•ๆ€ง๏ผ‰
284
+
285
+ ### 4.1 ๆ’ไปถๅŸบ็ฑป
286
+
287
+ ```python
288
+ class LoopStage(Enum):
289
+ FAMILY_QUIZ = "family_quiz"
290
+ SUMMARIZE = "summarize"
291
+ ANALYZE = "analyze"
292
+ BRIEF = "brief"
293
+ THREE_DAY = "three_day"
294
+ CONSOLIDATE = "consolidate"
295
+
296
+ @dataclass
297
+ class LoopContext:
298
+ briefing: dict = field(default_factory=dict)
299
+ weight_data: dict = field(default_factory=dict)
300
+ diet_records: list = field(default_factory=list)
301
+ family_recipes: list = field(default_factory=list) # ๆ–ฐๅขž๏ผšๅฎถๅบญ่œ่ฐฑ
302
+ family_memory: dict = field(default_factory=dict) # ๆ–ฐๅขž๏ผšๅฎถๅบญ่ฎฐๅฟ†
303
+ analysis_results: dict = field(default_factory=dict)
304
+ errors: list = field(default_factory=list)
305
+
306
+ class LoopPlugin(ABC):
307
+ @abstractmethod
308
+ def stage(self) -> LoopStage: ...
309
+ @abstractmethod
310
+ def name(self) -> str: ...
311
+ @abstractmethod
312
+ async def run(self, ctx: LoopContext) -> PluginResult: ...
313
+ ```
314
 
315
+ > **ๆ‰นๆณจ๏ผš** ________
316
 
317
+ ### 4.2 ๅ†…็ฝฎๆ’ไปถๆธ…ๅ•๏ผˆv5 ๆ›ดๆ–ฐ็‰ˆ๏ผ‰
 
 
 
 
 
318
 
319
+ | ๆ’ไปถ | ็ฑปๅ | ๆณจๅ†Œ้˜ถๆฎต | ๅŠŸ่ƒฝ | ๆ•ฐๆฎๆบ |
320
+ |------|------|---------|------|--------|
321
+ | ๅฎถๅบญ่œ่ฐฑๆฃ€ๆŸฅ | `FamilyRecipeQuizPlugin` | FAMILY_QUIZ | ๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ่ฏข้—ฎๆ–ฐ่œ่ฐฑ | `data/family/recipes.md` |
322
+ | ไฝ“้‡่ฏข้—ฎๆฃ€ๆŸฅ | `WeightQuizPlugin` | FAMILY_QUIZ | ๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ่ฏข้—ฎไฝ“้‡ | `data/logs/` |
323
+ | ๆ˜จๆ—ฅ้ฅฎ้ฃŸๆ€ป็ป“ | `DietSummaryPlugin` | SUMMARIZE | ่ฏปๅ–ๆ˜จๆ—ฅ้ฅฎ้ฃŸๆ—ฅๅฟ—๏ผŒๆฑ‡ๆ€ปไธ‰้ค | `data/logs/*.md` |
324
+ | ไฝ“้‡ๆฃ€ๆŸฅ | `WeightCheckPlugin` | SUMMARIZE | ๆฃ€ๆŸฅไฝ“้‡่ฎฐๅฝ•๏ผŒๅฏนๆฏ” WS/T 801 | `WeightStandardParser` |
325
+ | ๅฎถๅบญ่ฎฐๅฟ†ๅŠ ่ฝฝ | `FamilyMemoryPlugin` | SUMMARIZE | ๅŠ ่ฝฝๅฎถๅบญๅ…ณ็ณป/ไบ‹ไปถ่ฎฐๅฟ† | `data/family/memory.md` |
326
+ | DRIs ๅˆ†ๆž | `DRIAnalysisPlugin` | ANALYZE | ๅฏนๆฏ”่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡ | `DRIsParser` + ๆ˜จๆ—ฅ้ฅฎ้ฃŸ |
327
+ | ็ฎ€ๆŠฅ็”Ÿๆˆ | `BriefingGeneratorPlugin` | BRIEF | ๆฑ‡ๆ€ปๅˆ†ๆžไธบ็ป“ๆž„ๅŒ– JSON | `LoopContext` |
328
+ | ไธ‰ๅคฉๆ€ป็ป“ | `ThreeDaySummaryPlugin` | THREE_DAY | ๅˆ†ๆž่ฅๅ…ป็ผบๅคฑ่ถ‹ๅŠฟ๏ผŒๆ”น่ฟ›ๅฎถๅบญ่œๅ• | ่ฟ‘ไธ‰ๅคฉ้ฅฎ้ฃŸ่ฎฐๅฝ• |
329
+ | ้ข„่ฎพๅ†™ๅ…ฅ | `PresetWriterPlugin` | CONSOLIDATE | ็”Ÿๆˆๆ˜Žๆ—ฅ้ข„่ฎพๆ–‡ไปถ | `data/presets/` |
330
 
331
+ > **ๆ‰นๆณจ๏ผš** ________
 
332
 
333
+ ### 4.3 ๆ‰ฉๅฑ•ๆ–นๅผ
334
 
335
+ ```python
336
+ # ๆ–ฐๅขžๅŠŸ่ƒฝๅช้œ€ไธคๆญฅ๏ผš
337
+ class NewPlugin(LoopPlugin):
338
+ def stage(self) -> LoopStage: return LoopStage.SUMMARIZE
339
+ def name(self) -> str: return "new_feature"
340
+ async def run(self, ctx: LoopContext) -> PluginResult: ...
341
 
342
+ loop.plugins.register(NewPlugin())
343
+ # ไธ้œ€่ฆไฟฎๆ”น loop.py ็š„็Šถๆ€ๆœบไปฃ็ 
344
+ ```
345
 
346
+ > **ๆ‰นๆณจ๏ผš** ________
347
 
348
+ ---
349
 
350
+ ## ไบ”ใ€ๆ•ดไฝ“ๆ–‡ไปถ็ป“ๆž„๏ผˆv5 ๆ›ดๆ–ฐ็‰ˆ๏ผ‰
351
 
352
  ```
353
+ PregoPal/
354
+ โ”œโ”€โ”€ app.py # ไธปๅ…ฅๅฃ๏ผšๅฏๅŠจ Gradio + Loop
355
+ โ”œโ”€โ”€ config.py # ๅ…จๅฑ€้…็ฝฎ
356
+ โ”œโ”€โ”€ utils.py # ๅทฅๅ…ทๅ‡ฝๆ•ฐ
357
+ โ”œโ”€โ”€ loop.py โ† ๐Ÿ†• ๆ–ฐๅขž # ๆ ธๅฟƒๅพช็Žฏๅผ•ๆ“Ž๏ผˆ็Šถๆ€ๆœบ้ฉฑๅŠจ๏ผ‰
358
+ โ”‚
359
+ โ”œโ”€โ”€ plugins/ โ† ๐Ÿ†• ๆ–ฐๅขž # Loop ๆ’ไปถ
360
+ โ”‚ โ”œโ”€โ”€ __init__.py
361
+ โ”‚ โ”œโ”€โ”€ base.py # LoopPlugin ๅŸบ็ฑป + PluginRegistry
362
+ โ”‚ โ”œโ”€โ”€ family_quiz.py # ๅฎถๅบญ่œ่ฐฑ/ไฝ“้‡่ฏข้—ฎๆฃ€ๆŸฅ
363
+ โ”‚ โ”œโ”€โ”€ diet_summary.py # ๆ˜จๆ—ฅ้ฅฎ้ฃŸๆ€ป็ป“
364
+ โ”‚ โ”œโ”€โ”€ weight_check.py # ไฝ“้‡ๆฃ€ๆŸฅ๏ผˆWS/T 801๏ผ‰
365
+ โ”‚ โ”œโ”€โ”€ family_memory.py # ๅฎถๅบญ่ฎฐๅฟ†ๅŠ ่ฝฝ
366
+ โ”‚ โ”œโ”€โ”€ dri_analysis.py # DRIs ่ฅๅ…ป็ด ๅฏนๆฏ”ๅˆ†ๆž
367
+ โ”‚ โ”œโ”€โ”€ briefing_generator.py # ไปŠๆ—ฅ็ฎ€ๆŠฅ็”Ÿๆˆๅ™จ
368
+ โ”‚ โ”œโ”€โ”€ three_day_summary.py # ๆฏไธ‰ๅคฉๆ€ป็ป“
369
+ โ”‚ โ””โ”€โ”€ preset_writer.py # ้ข„่ฎพๆ–‡ไปถๅ†™ๅ…ฅ
370
+ โ”‚
371
+ โ”œโ”€โ”€ modules/ # ไธšๅŠก้€ป่พ‘ๅฑ‚
372
+ โ”‚ โ”œโ”€โ”€ __init__.py
373
+ โ”‚ โ”œโ”€โ”€ nutrition_standards.py # โ† ๐Ÿ†• ๆ–ฐๅขž๏ผš่ฅๅ…ปๆ ‡ๅ‡†่งฃๆžๅ™จ
374
+ โ”‚ โ”‚ โ”œโ”€โ”€ WeightStandardParser # ไฝ“้‡ๆ ‡ๅ‡†่งฃๆž
375
+ โ”‚ โ”‚ โ”œโ”€โ”€ DietaryGuideParser # ่†ณ้ฃŸๆŒ‡ๅ—่งฃๆž
376
+ โ”‚ โ”‚ โ””โ”€โ”€ DRIsParser # DRIs ่งฃๆž
377
+ โ”‚ โ”œโ”€โ”€ family_manager.py # โ† ๐Ÿ†• ๆ–ฐๅขž๏ผšๅฎถๅบญไฟกๆฏ็ฎก็†
378
+ โ”‚ โ”‚ โ”œโ”€โ”€ ่ฏปๅ–/ๅ†™ๅ…ฅ recipes.md
379
+ โ”‚ โ”‚ โ”œโ”€โ”€ ่ฏปๅ–/ๅ†™ๅ…ฅ preferences.md
380
+ โ”‚ โ”‚ โ””โ”€โ”€ ่ฏปๅ–/ๅ†™ๅ…ฅ memory.md
381
+ โ”‚ โ”œโ”€โ”€ diet_extractor.py # โ† ๐Ÿ†• ๆ–ฐๅขž๏ผšsystem prompt + ๆญฃๅˆ™ๆๅ–
382
+ โ”‚ โ”‚ โ”œโ”€โ”€ ไปŽๅฏน่ฏไธญๆๅ–้ฅฎ้ฃŸ่ฎฐๅฝ•
383
+ โ”‚ โ”‚ โ”œโ”€โ”€ ไปŽๅฏน่ฏไธญๆๅ–่œ่ฐฑไฟกๆฏ
384
+ โ”‚ โ”‚ โ””โ”€โ”€ ไปŽๅฏน่ฏไธญๆๅ–ๅฎถๅบญๅ…ณ็ณป
385
+ โ”‚ โ”œโ”€โ”€ voiceprint.py # ๅฃฐ็บน่ฏ†ๅˆซ
386
+ โ”‚ โ”œโ”€โ”€ meal_recommender.py # ่œๅ“ๆŽจ่
387
+ โ”‚ โ”œโ”€โ”€ diet_logger.py # ้ฅฎ้ฃŸ่ฎฐๅฝ• + Markdown ็”Ÿๆˆ
388
+ โ”‚ โ””โ”€โ”€ nutrition_analyzer.py # ่ฅๅ…ปๅˆ†ๆž + ๅฏ่ง†ๅŒ–
389
+ โ”‚
390
+ โ”œโ”€โ”€ core/ # AI ๆ ธๅฟƒๅฑ‚๏ผˆ็ญ‰ๅพ… MiniCPM-o๏ผ‰
391
+ โ”‚ โ”œโ”€โ”€ __init__.py
392
+ โ”‚ โ”œโ”€โ”€ model_loader.py
393
+ โ”‚ โ”œโ”€โ”€ voice_processor.py
394
+ โ”‚ โ”œโ”€โ”€ vision_processor.py
395
+ โ”‚ โ””โ”€โ”€ conversation_manager.py
396
+ โ”‚
397
+ โ”œโ”€โ”€ ui/ # ่กจ็Žฐๅฑ‚
398
+ โ”‚ โ”œโ”€โ”€ __init__.py
399
+ โ”‚ โ””โ”€โ”€ app_builder.py # Gradio ็•Œ้ข
400
+ โ”‚
401
+ โ”œโ”€โ”€ data/
402
+ โ”‚ โ”œโ”€โ”€ nutrition/
403
+ โ”‚ โ”‚ โ””โ”€โ”€ raw/ # ไธ‰ไธช MD ๆ–‡ไปถ
404
+ โ”‚ โ”œโ”€โ”€ family/ โ† ๐Ÿ†• ๆ–ฐๅขž # ๅฎถๅบญไฟกๆฏ
405
+ โ”‚ โ”‚ โ”œโ”€โ”€ recipes.md # ๅฎถๅบญ่œ่ฐฑ๏ผˆๅฎถไบบไผšๅš็š„่œ๏ผ‰
406
+ โ”‚ โ”‚ โ”œโ”€โ”€ preferences.md # ้ฅฎ้ฃŸๅๅฅฝ/ๅฟŒๅฃ/่ฟ‡ๆ•
407
+ โ”‚ โ”‚ โ””โ”€โ”€ memory.md # ๅฎถๅบญ่ฎฐๅฟ†๏ผˆๅ…ณ็ณป/ไบ‹ไปถ๏ผ‰
408
+ โ”‚ โ”œโ”€โ”€ presets/ # ๆฏๆ—ฅ็ฎ€ๆŠฅ
409
+ โ”‚ โ”‚ โ””โ”€โ”€ .daily_status.json # ็Šถๆ€ไฝๆ–‡ไปถ
410
+ โ”‚ โ”œโ”€โ”€ voices/
411
+ โ”‚ โ”œโ”€โ”€ logs/ # Markdown ้ฅฎ้ฃŸๆ—ฅๅฟ—
412
+ โ”‚ โ””โ”€โ”€ reports/ # ๅฏผๅ‡บๆŠฅๅ‘Š
413
+ โ”‚
414
+ โ”œโ”€โ”€ docs/
415
+ โ”‚ โ”œโ”€โ”€ ้กน็›ฎ็†่งฃ_ๆŠ€ๆœฏๆžถๆž„.md
416
+ โ”‚ โ””โ”€โ”€ ๅผ€ๅ‘ๆ—ฅๅฟ—.md
417
+ โ”œโ”€โ”€ requirements.txt
418
+ โ””โ”€โ”€ README.md
419
  ```
420
 
421
+ > **ๆ‰นๆณจ๏ผš** ________
422
 
423
+ ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
 
425
+ ## ๅ…ญใ€UI ็•Œ้ข่ฎพ่ฎก๏ผˆๆ นๆฎๆ‰นๆณจๆ–ฐๅขž๏ผ‰
426
 
427
+ ๆ นๆฎไฝ ็š„ๆ‰นๆณจ๏ผŒGradio ็•Œ้ขๆ”นไธบ **4 ไธชๅญ้กต้ข**๏ผš
428
+
429
+ ### ้กต้ข 1๏ผš่ฏญ้Ÿณไบคไบ’๏ผˆไธป็•Œ้ข๏ผ‰
430
+ - ่ฏญ้Ÿณ่พ“ๅ…ฅ/่พ“ๅ‡บ๏ผˆๆœชๆฅๆ”ฏๆŒ่ง†้ข‘๏ผ‰
431
+ - **ๆ˜พ็คบ PregoPal ๅฝ“ๅ‰ๆ€่€ƒ/ๆ“ไฝœๅ…ณ้”ฎ่ฏ**๏ผˆ้€š่ฟ‡ system prompt + ๆญฃๅˆ™ๆๅ–๏ผŒๆฏๆฌกๆ‰ง่กŒไธ‹ไธ€ๆญฅๆ—ถ็”จ็‰นๅฎšๅญ—็ฌฆๅŒ…่ฃนไธ‹ไธ€ๆญฅไธป้ข˜๏ผ‰
432
+ - **่‡ชๅŠจๅฑ•็คบ็›ธๅ…ณๆ–‡ไปถๆ“ไฝœ็š„่พ“ๅ‡บ็ป“ๆžœ**๏ผˆๆˆชๆ–ญ + ็œ็•ฅๅท๏ผ‰
433
+ - ๅฃฐ็บน่ฏ†ๅˆซ็Šถๆ€ๆ˜พ็คบ
434
+
435
+ ### ้กต้ข 2๏ผšๅฎถๅบญๆˆๅ‘˜้ฅฎ้ฃŸไน ๆƒฏ
436
+ - ๅฑ•็คบๆ‰€ๆœ‰ๅฎถๅบญๆˆๅ‘˜็š„้ฅฎ้ฃŸๅๅฅฝใ€ๅฟŒๅฃใ€่ฟ‡ๆ•
437
+ - ๅฑ•็คบๅฎถๅบญ่œ่ฐฑ๏ผˆๅฎถไบบไผšๅš็š„่œ๏ผ‰
438
+ - ๆ”ฏๆŒๆ‰‹ๅŠจๆทปๅŠ /ไฟฎๆ”น
439
+
440
+ ### ้กต้ข 3๏ผšๆฏไธ‰ๅคฉ่‡ชๅŠจๆ€ป็ป“
441
+ - ๅˆ†ๆžๅญ•ๅฆ‡้ฅฎ้ฃŸๆ˜ฏๅฆๅญ˜ๅœจ่ฅๅ…ป็ผบๅคฑ
442
+ - ๅฏนๅฎถๅบญ่œๅ•็ป™ๅ‡บๆ”น่ฟ›ๅปบ่ฎฎ
443
+ - ็”ฑ `THREE_DAY` ็Šถๆ€่งฆๅ‘
444
 
445
+ ### ้กต้ข 4๏ผš่ฅๅ…ปๆŠฅๅ‘Š
446
+ - ๅฏ่ง†ๅŒ–ๆŠฅๅ‘Š๏ผˆไฟ็•™ๅŽŸๆœ‰๏ผ‰
447
+ - ไฝ“้‡ๅขž้•ฟ่ถ‹ๅŠฟๅ›พ
448
+ - ่ฅๅ…ป็ด ๆ‘„ๅ…ฅๅฏนๆฏ”ๅ›พ
449
+
450
+ > **ๆ‰นๆณจ๏ผš** ________
451
 
452
  ---
453
 
454
+ ## ไธƒใ€system prompt + ๆญฃๅˆ™ๆๅ–่ฎพ่ฎก๏ผˆๆ นๆฎๆ‰นๆณจๆ–ฐๅขž๏ผ‰
455
+
456
+ ่ฟ™ๆ˜ฏ PregoPal ็š„ๆ ธๅฟƒๆœบๅˆถ๏ผŒ็”จไบŽๅœจไธ๏ฟฝ๏ฟฝ๏ฟฝ่ต– toolcall ็š„ๆƒ…ๅ†ตไธ‹ๅฎž็Žฐ็ป“ๆž„ๅŒ–ๆ•ฐๆฎๆๅ–ใ€‚
457
+
458
+ ### 7.1 ๆๅ–ๆ ‡่ฎฐๆ ผๅผ
459
+
460
+ ๅœจ system prompt ไธญๅ‘Š่ฏ‰ๆจกๅž‹๏ผŒๅฝ“้œ€่ฆ่ฎฐๅฝ•ไฟกๆฏๆ—ถ๏ผŒไฝฟ็”จไปฅไธ‹ๆ ‡่ฎฐๆ ผๅผ๏ผš
461
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  ```
463
+ [EXTRACT_DIET]
464
+ ๆ—ฅๆœŸ: 2026-06-08
465
+ ้คๆฌก: ๅˆ้ค
466
+ ้ฃŸ็‰ฉ: ็•ช่Œ„็‰›่…ฉ, ็ฑณ้ฅญ
467
+ ไปฝ้‡: ไธ€็ข—
468
+ ่ฎฐๅฝ•ไบบ: ไธˆๅคซ
469
+ ๅค‡ๆณจ: ๅญ•ๅฆ‡่ฏดๆƒณๅƒ
470
+ [/EXTRACT_DIET]
471
+
472
+ [EXTRACT_RECIPE]
473
+ ่œๅ: ๆธ…่’ธ้ฒˆ้ฑผ
474
+ ๅˆถไฝœไบบ: ไธˆๅคซ
475
+ ้šพๅบฆ: ไธญ็ญ‰
476
+ ้ฃŸๆ: ้ฒˆ้ฑผ, ่‘ฑ, ๅงœ, ่’ธ้ฑผ่ฑ‰ๆฒน
477
+ ๅค‡ๆณจ: ๅญ•ๅฆ‡็ˆฑๅƒ
478
+ [/EXTRACT_RECIPE]
479
+
480
+ [EXTRACT_PREFERENCE]
481
+ ไบบๅ‘˜: ไธˆๅคซ
482
+ ็ฑปๅž‹: ๅฟŒๅฃ
483
+ ๅ†…ๅฎน: ไธๅƒ้ฆ™่œ
484
+ [/EXTRACT_PREFERENCE]
485
+
486
+ [EXTRACT_WEIGHT]
487
+ ๆ—ฅๆœŸ: 2026-06-08
488
+ ไฝ“้‡: 62.5
489
+ ่ฎฐๅฝ•ไบบ: ๅญ•ๅฆ‡
490
+ [/EXTRACT_WEIGHT]
491
+
492
+ [THINKING]
493
+ ๅฝ“ๅ‰ๆญฅ้ชค: ๅˆ†ๆžๆ˜จๆ—ฅ้’™ๆ‘„ๅ…ฅ
494
+ ไธ‹ไธ€ๆญฅ: ๅฏนๆฏ”DRIsๆ ‡ๅ‡†
495
+ [/THINKING]
496
+ ```
497
+
498
+ ### 7.2 ๅŽ็ซฏๆญฃๅˆ™่งฃๆž
499
+
500
+ ```python
501
+ # modules/diet_extractor.py
502
+ import re
503
+
504
+ class DietExtractor:
505
+ """ไปŽ AI ๅ›žๅคไธญๆๅ–็ป“ๆž„ๅŒ–ๆ•ฐๆฎ"""
506
+
507
+ DIET_PATTERN = re.compile(
508
+ r'\[EXTRACT_DIET\](.*?)\[/EXTRACT_DIET\]', re.DOTALL
509
+ )
510
+ RECIPE_PATTERN = re.compile(
511
+ r'\[EXTRACT_RECIPE\](.*?)\[/EXTRACT_RECIPE\]', re.DOTALL
512
+ )
513
+ PREFERENCE_PATTERN = re.compile(
514
+ r'\[EXTRACT_PREFERENCE\](.*?)\[/EXTRACT_PREFERENCE\]', re.DOTALL
515
+ )
516
+ WEIGHT_PATTERN = re.compile(
517
+ r'\[EXTRACT_WEIGHT\](.*?)\[/EXTRACT_WEIGHT\]', re.DOTALL
518
+ )
519
+ THINKING_PATTERN = re.compile(
520
+ r'\[THINKING\](.*?)\[/THINKING\]', re.DOTALL
521
+ )
522
+
523
+ @staticmethod
524
+ def extract_all(text: str) -> dict:
525
+ """ไปŽๆ–‡ๆœฌไธญๆๅ–ๆ‰€ๆœ‰็ป“ๆž„ๅŒ–ๆ•ฐๆฎ"""
526
+ return {
527
+ "diets": DietExtractor._parse_diets(text),
528
+ "recipes": DietExtractor._parse_recipes(text),
529
+ "preferences": DietExtractor._parse_preferences(text),
530
+ "weights": DietExtractor._parse_weights(text),
531
+ "thinking": DietExtractor._parse_thinking(text),
532
+ }
533
+
534
+ @staticmethod
535
+ def _parse_diets(text: str) -> list[dict]:
536
+ """่งฃๆž [EXTRACT_DIET] ๅ—"""
537
+ results = []
538
+ for match in DietExtractor.DIET_PATTERN.finditer(text):
539
+ block = match.group(1)
540
+ entry = {}
541
+ for line in block.strip().split('\n'):
542
+ if ':' in line:
543
+ key, val = line.split(':', 1)
544
+ entry[key.strip()] = val.strip()
545
+ if entry:
546
+ results.append(entry)
547
+ return results
548
+ ```
549
+
550
+ ### 7.3 ็จณๅฎšๆ€ง่ฎพ่ฎก
551
 
552
+ - **ๆญฃๅˆ™ๅŒน้…ๅคฑ่ดฅๆ—ถ็š„ fallback**๏ผšๅฆ‚ๆžœๆจกๅž‹่พ“ๅ‡บๆ ผๅผไธๅฎŒๆ•ด๏ผŒๅฐ่ฏ•็”จๅ…ณ้”ฎ่ฏๅŒน้…๏ผˆๅฆ‚ "ๅƒไบ†"ใ€"ๆƒณๅƒ"ใ€"่ฎฐๅฝ•" ็ญ‰๏ผ‰
553
+ - **็”จๆˆท็กฎ่ฎคๆœบๅˆถ**๏ผšๆๅ–็š„ๆ•ฐๆฎๅ…ˆๅฑ•็คบ็ป™็”จๆˆท็กฎ่ฎค๏ผŒๅ†ๅ†™ๅ…ฅๆ–‡ไปถ
554
+ - **ๅคš่ฝฎ็ดฏ็งฏ**๏ผšๅŒไธ€้คๆฌก็š„ไฟกๆฏๅฏ่ƒฝๅˆ†ๆ•ฃๅœจๅคš่ฝฎๅฏน่ฏไธญ๏ผŒ้œ€่ฆ็ดฏ็งฏๅˆๅนถ
555
 
556
+ > **ๆ‰นๆณจ๏ผš** ________
557
 
558
  ---
559
 
560
+ ## ๅ…ซใ€ๆ•ฐๆฎๆตๅ…จๆ™ฏ๏ผˆv5 ๆ›ดๆ–ฐ็‰ˆ๏ผ‰
561
 
562
  ```
563
+ data/nutrition/raw/ data/family/
564
+ โ”œโ”€โ”€ ไฝ“้‡ๆ ‡ๅ‡†.md โ”œโ”€โ”€ recipes.md
565
+ โ”œโ”€โ”€ ่†ณ้ฃŸๆŒ‡ๅ—.md โ”œโ”€โ”€ preferences.md
566
+ โ””โ”€โ”€ DRIs.md โ””โ”€โ”€ memory.md
567
+ โ”‚ โ”‚
568
+ โ–ผ โ–ผ
569
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
570
+ โ”‚ nutrition_ โ”‚ โ”‚ family_manager.py โ”‚
571
+ โ”‚ standards.py โ”‚ โ”‚ ่ฏปๅ–/ๅ†™ๅ…ฅๅฎถๅบญไฟกๆฏ โ”‚
572
+ โ”‚ ็ผ–่ฏ‘ไธบ็ป“ๆž„ๅŒ–ๆ•ฐๆฎ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
573
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
574
+ โ”‚ โ”‚
575
+ โ–ผ โ–ผ
576
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
577
+ โ”‚ loop.py โ”‚
578
+ โ”‚ LAUNCH โ†’ FAMILY_QUIZ โ†’ SUMMARIZE โ†’ ANALYZE โ”‚
579
+ โ”‚ โ†’ BRIEF โ†’ INTERACT โ†’ CONSOLIDATE โ†’ (THREE_DAY) โ”‚
580
+ โ”‚ โ”‚
581
+ โ”‚ ๆฏไธช้˜ถๆฎต่ฐƒ็”จๅฏนๅบ” Plugin โ”‚
582
+ โ”‚ Plugin ่ฐƒ็”จ modules/ ๅฑ‚็š„ๅ‡ฝๆ•ฐ โ”‚
583
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
584
+ โ”‚
585
+ โ–ผ
586
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
587
+ โ”‚ data/presets/ไปŠๆ—ฅ็ฎ€ๆŠฅ_YYYY-MM-DD.json โ”‚
588
+ โ”‚ { โ”‚
589
+ โ”‚ "date": "2026-06-08", โ”‚
590
+ โ”‚ "weight_check": {"need_ask": true/false}, โ”‚
591
+ โ”‚ "recipe_check": {"need_ask": true/false}, โ”‚
592
+ โ”‚ "nutrient_focus": ["้’™", "้“", "ๅถ้…ธ"], โ”‚
593
+ โ”‚ "recommended_foods": ["่ ่œ", "็˜ฆ่‚‰", "่ฑ†่…"],โ”‚
594
+ โ”‚ "family_recipes_available": ["็•ช่Œ„็‰›่…ฉ",...], โ”‚
595
+ โ”‚ "conversation_topics": ["ไปŠๅคฉๆƒณๅƒ้ฑผๅ—๏ผŸ"], โ”‚
596
+ โ”‚ "family_memory": "ๆ˜จๅคฉไธˆๅคซ่ฏด...", โ”‚
597
+ โ”‚ "thinking_keywords": "ๅˆ†ๆž้’™ๆ‘„ๅ…ฅ" โ”‚
598
+ โ”‚ } โ”‚
599
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
600
+ โ”‚
601
+ โ–ผ
602
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
603
+ โ”‚ ui/app_builder.py (Gradio 4้กต้ข) โ”‚
604
+ โ”‚ ้กต้ข1: ่ฏญ้Ÿณไบคไบ’ (ๆ˜พ็คบ thinking_keywords + ๆˆชๆ–ญ) โ”‚
605
+ โ”‚ ้กต้ข2: ๅฎถๅบญ้ฅฎ้ฃŸไน ๆƒฏ โ”‚
606
+ โ”‚ ้กต้ข3: ไธ‰ๅคฉๆ€ป็ป“ โ”‚
607
+ โ”‚ ้กต้ข4: ่ฅๅ…ปๆŠฅๅ‘Š โ”‚
608
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
609
+ โ”‚
610
+ โ–ผ
611
+ modules/diet_extractor.py (ไปŽๅฏน่ฏไธญๆญฃๅˆ™ๆๅ–)
612
+ modules/family_manager.py (ๅ†™ๅ…ฅๅฎถๅบญไฟกๆฏ)
613
+ modules/diet_logger.py (่ฎฐๅฝ•้ฅฎ้ฃŸ)
614
+ โ”‚
615
+ โ–ผ
616
+ ๆฌกๆ—ฅ loop.py ๅ†ๆฌกๅฏๅŠจ โ†’ ๅพช็Žฏ
617
  ```
618
 
619
+ > **ๆ‰นๆณจ๏ผš** ________
620
 
621
  ---
622
 
623
+ ## ไนใ€ๆŠ€ๆœฏๆ ˆไธ€่งˆ
624
+
625
+ | ๅฑ‚็บง | ๆŠ€ๆœฏ | ็”จ้€” |
626
+ |------|------|------|
627
+ | ๆ ธๅฟƒๆจกๅž‹ | **MiniCPM-o 4.5**๏ผˆ็ปŸไธ€ๅคšๆจกๆ€ๆจกๅž‹๏ผ‰ | ๅ…จๅŒๅทฅๆŽจ็†๏ผš่ง†่ง‰+่ฏญ้Ÿณ+ๆ–‡ๆœฌ+่ฏญ้Ÿณ่พ“ๅ‡บ |
628
+ | ๅ‰็ซฏๆก†ๆžถ | **Gradio 6.x** | Web ็•Œ้ข๏ผŒ4 ไธชๅญ้กต้ข |
629
+ | ๅฃฐ็บน่ฏ†ๅˆซ | Whisper-medium encoder embedding๏ผˆไผ˜ๅ…ˆ๏ผ‰| ่ฏด่ฏไบบ่บซไปฝ่ฏ†ๅˆซ |
630
+ | ้ข‘่ฐฑๆ–นๆกˆ | NumPy + SoundFile๏ผˆๅค‡้€‰ fallback๏ผ‰ | ๅฃฐ็บน่ฏ†ๅˆซๅ…œๅบ• |
631
+ | ๆ•ฐๆฎๅญ˜ๅ‚จ | JSON + Markdown | ้ฅฎ้ฃŸ่ฎฐๅฝ• + ๆŠฅๅ‘Šๅญ˜ๆกฃ + ๆฏๆ—ฅ็ฎ€ๆŠฅ + ๅฎถๅบญไฟกๆฏ |
632
+ | ่ฅๅ…ปๆ ‡ๅ‡† | ไธ‰ไธช MD ๆ–‡ไปถ๏ผˆๅทฒไธ‹่ฝฝ๏ผ‰+ ่‡ชๅ†™่งฃๆžๅ™จ | ไฝ“้‡ๆ ‡ๅ‡†/่†ณ้ฃŸๆŒ‡ๅ—/DRIs |
633
+ | ๅพช็Žฏๅผ•ๆ“Ž | ่‡ช็ ”็Šถๆ€ๆœบ + ๆ’ไปถๆณจๅ†Œ | ๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ็ฎก็† |
634
+ | ๆ•ฐๆฎๆๅ– | ๆญฃๅˆ™่กจ่พพๅผ๏ผˆsystem prompt ๆ ‡่ฎฐๆ ผๅผ๏ผ‰ | ไปŽๅฏน่ฏไธญๆๅ–็ป“ๆž„ๅŒ–ๆ•ฐๆฎ |
635
+ | ้ƒจ็ฝฒๅนณๅฐ | HuggingFace Spaces๏ผˆ็›ฎๅ‰๏ผ‰+ Modal๏ผˆๅŽ็ปญ๏ผ‰ | ไบ‘็ซฏ้ƒจ็ฝฒ |
636
 
637
+ > **ๆ‰นๆณจ๏ผš** ________
 
 
 
 
 
638
 
639
  ---
640
 
641
+ ## ๅใ€ๅพ…่ฎจ่ฎบ้—ฎ้ข˜ๆธ…ๅ•
642
 
643
+ | # | ้—ฎ้ข˜ | ไฝ ็š„้€‰ๆ‹ฉ / ๆ„่ง |
644
+ |---|------|----------------|
645
+ | 1 | **Loop ่งฆๅ‘ๆ—ถๆœบ**๏ผšๆฏๆ™š 00:00 ่‡ชๅŠจๆ€ป็ป“ + ็จ‹ๅบๅฏๅŠจๆ—ถๆฃ€ๆŸฅ็Šถๆ€ไฝ๏ผˆๅทฒ้‡‡็บณ๏ผ‰ | โœ… ๅทฒ็กฎ่ฎค |
646
+ | 2 | **็ฎ€ๆŠฅๆ‰ฟ่ฝฝๅฝขๅผ**๏ผšJSON ๆ–‡ไปถ `data/presets/` ่ฝ็›˜๏ผˆๅทฒ้‡‡็บณ๏ผ‰ | โœ… ๅทฒ็กฎ่ฎค |
647
+ | 3 | **็Šถๆ€ไฝๆœบๅˆถ**๏ผš`data/presets/.daily_status.json` ่ฎฐๅฝ•ๆฏๆ—ฅๅฎŒๆˆ็Šถๆ€ | ________ |
648
+ | 4 | **ๅฎถๅบญไฟกๆฏๆ–‡ไปถๆ ผๅผ**๏ผšไธ‰ไธช md ๆ–‡ไปถ๏ผˆrecipes.md / preferences.md / memory.md๏ผ‰ | ________ |
649
+ | 5 | **system prompt ๆ ‡่ฎฐๆ ผๅผ**๏ผš`[EXTRACT_DIET]` / `[EXTRACT_RECIPE]` / `[THINKING]` ็ญ‰ | ________ |
650
+ | 6 | **UI 4 ้กต้ข**๏ผš่ฏญ้Ÿณไบคไบ’ / ๅฎถๅบญ้ฅฎ้ฃŸไน ๆƒฏ / ไธ‰ๅคฉๆ€ป็ป“ / ่ฅๅ…ปๆŠฅๅ‘Š | ________ |
651
+ | 7 | **ไธ‰ๅคฉๆ€ป็ป“่งฆๅ‘ๆกไปถ**๏ผšๆฏ่‡ช็„ถๆ—ฅ 00:00 ๆฃ€ๆŸฅๆ˜ฏๅฆๆปก 3 ๅคฉ๏ผŸ่ฟ˜ๆ˜ฏๆฏ 3 ๆฌก CONSOLIDATE๏ผŸ | ________ |
652
+ | 8 | **่ฟ˜ๆœ‰ไป€ไนˆ้œ€่ฆ่ฐƒๆ•ด็š„๏ผŸ** | ________ |
653
 
654
  ---
655
 
656
+ *ๆ–‡ๆกฃ็”Ÿๆˆๆ—ถ้—ด๏ผš2026-06-08 | v5 - ๆ•ดๅˆๆ‰นๆณจ๏ผŒ็ป†ๅŒ–ๅฎž็Žฐๆ–นๆกˆ*
loop.py ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ PregoPal - ๆ ธๅฟƒๅพช็Žฏๅผ•ๆ“Ž
3
+ =======================
4
+ ็Šถๆ€ๆœบ้ฉฑๅŠจ็š„ๆฏๆ—ฅ็”Ÿๅ‘ฝๅ‘จๆœŸ็ฎก็†ใ€‚
5
+
6
+ ็Šถๆ€ๆต่ฝฌ๏ผš
7
+ LAUNCH โ†’ FAMILY_QUIZ โ†’ SUMMARIZE โ†’ ANALYZE โ†’ BRIEF โ†’ INTERACT
8
+ โ†’ CONSOLIDATE โ†’ (THREE_DAY) โ†’ DONE
9
+
10
+ ็Šถๆ€ไฝๆœบๅˆถ๏ผš
11
+ data/presets/.daily_status.json ่ฎฐๅฝ•ๆฏๆ—ฅๅฎŒๆˆ็Šถๆ€
12
+ """
13
+
14
+ import json
15
+ import datetime
16
+ import asyncio
17
+ from enum import Enum
18
+ from pathlib import Path
19
+ from dataclasses import dataclass, field
20
+
21
+ from plugins.base import LoopPlugin, PluginResult, PluginRegistry, LoopStage, LoopContext
22
+
23
+ PRESETS_DIR = Path("data/presets")
24
+ STATUS_FILE = PRESETS_DIR / ".daily_status.json"
25
+
26
+
27
+ # ============================================================
28
+ # ็Šถๆ€ๆžšไธพ
29
+ # ============================================================
30
+ class LoopState(Enum):
31
+ LAUNCH = "launch" # ๅฏๅŠจๆฃ€ๆŸฅ๏ผšๆฃ€ๆŸฅไปŠๆ—ฅ็Šถๆ€ไฝ
32
+ FAMILY_QUIZ = "family_quiz" # ๅฎถๅบญ้—ฎๅท๏ผšๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ่ฏข้—ฎ่œ่ฐฑ/ไฝ“้‡
33
+ SUMMARIZE = "summarize" # ๆ˜จๆ—ฅๆ€ป็ป“๏ผšๅˆ†ๆžๆ˜จๆ—ฅ้ฅฎ้ฃŸ/ไฝ“้‡/ๅฎถๅบญ่ฎฐๅฟ†
34
+ ANALYZE = "analyze" # ่ฅๅ…ปๅˆ†ๆž๏ผšๅฏนๆฏ” DRIs
35
+ BRIEF = "brief" # ็”ŸๆˆไปŠๆ—ฅ็ฎ€ๆŠฅ
36
+ INTERACT = "interact" # ็™ฝๅคฉไบคไบ’ๆจกๅผ๏ผˆ็ญ‰ๅพ…็”จๆˆทๆ“ไฝœ๏ผ‰
37
+ THREE_DAY = "three_day" # ๆฏไธ‰ๅคฉ่‡ชๅŠจๆ€ป็ป“
38
+ CONSOLIDATE = "consolidate" # ๆ™š้—ดๆ•ด็†
39
+ DONE = "done" # ๆ ‡่ฎฐไปŠๆ—ฅๅฎŒๆˆ
40
+
41
+
42
+ # ============================================================
43
+ # ็Šถๆ€่ฝฌ็งป่กจ
44
+ # ============================================================
45
+ _TRANSITIONS = {
46
+ (LoopState.LAUNCH, "need_summary"): LoopState.FAMILY_QUIZ,
47
+ (LoopState.LAUNCH, "already_done"): LoopState.INTERACT,
48
+ (LoopState.FAMILY_QUIZ, "ok"): LoopState.SUMMARIZE,
49
+ (LoopState.SUMMARIZE, "ok"): LoopState.ANALYZE,
50
+ (LoopState.ANALYZE, "ok"): LoopState.BRIEF,
51
+ (LoopState.BRIEF, "ok"): LoopState.INTERACT,
52
+ (LoopState.INTERACT, "day_ended"): LoopState.CONSOLIDATE,
53
+ (LoopState.CONSOLIDATE, "need_3day"): LoopState.THREE_DAY,
54
+ (LoopState.CONSOLIDATE, "ok"): LoopState.DONE,
55
+ (LoopState.THREE_DAY, "ok"): LoopState.DONE,
56
+ }
57
+
58
+
59
+ # ============================================================
60
+ # ็Šถๆ€ไฝ็ฎก็†
61
+ # ============================================================
62
+ class DailyStatus:
63
+ """็ฎก็†ๆฏๆ—ฅ็Šถๆ€ไฝ"""
64
+
65
+ STATUS_FILE = STATUS_FILE
66
+
67
+ @staticmethod
68
+ def load() -> dict:
69
+ """ๅŠ ่ฝฝ็Šถๆ€ไฝๆ–‡ไปถ"""
70
+ if STATUS_FILE.exists():
71
+ with open(STATUS_FILE, 'r', encoding='utf-8') as f:
72
+ return json.load(f)
73
+ return {}
74
+
75
+ @staticmethod
76
+ def save(status: dict):
77
+ """ไฟๅญ˜็Šถๆ€ไฝๆ–‡ไปถ"""
78
+ PRESETS_DIR.mkdir(parents=True, exist_ok=True)
79
+ with open(STATUS_FILE, 'w', encoding='utf-8') as f:
80
+ json.dump(status, f, ensure_ascii=False, indent=2)
81
+
82
+ @staticmethod
83
+ def is_today_done() -> bool:
84
+ """ๆฃ€ๆŸฅไปŠๆ—ฅๆ˜ฏๅฆๅทฒๅฎŒๆˆๆ€ป็ป“"""
85
+ today = datetime.date.today().isoformat()
86
+ status = DailyStatus.load()
87
+ return status.get(today, {}).get("summary_done", False)
88
+
89
+ @staticmethod
90
+ def mark_summary_done():
91
+ """ๆ ‡่ฎฐไปŠๆ—ฅๆ€ป็ป“ๅฎŒๆˆ"""
92
+ today = datetime.date.today().isoformat()
93
+ status = DailyStatus.load()
94
+ status[today] = status.get(today, {})
95
+ status[today]["summary_done"] = True
96
+ status[today]["completed_at"] = datetime.datetime.now().isoformat()
97
+ DailyStatus.save(status)
98
+
99
+ @staticmethod
100
+ def mark_day_ended():
101
+ """ๆ ‡่ฎฐไปŠๆ—ฅ็ป“ๆŸ"""
102
+ today = datetime.date.today().isoformat()
103
+ status = DailyStatus.load()
104
+ status[today] = status.get(today, {})
105
+ status[today]["day_ended"] = True
106
+ status[today]["ended_at"] = datetime.datetime.now().isoformat()
107
+ DailyStatus.save(status)
108
+
109
+ @staticmethod
110
+ def get_last_summary_date() -> str | None:
111
+ """่Žทๅ–ๆœ€่ฟ‘ไธ€ๆฌกๆ€ป็ป“็š„ๆ—ฅๆœŸ"""
112
+ status = DailyStatus.load()
113
+ done_dates = [d for d, v in status.items() if v.get("summary_done")]
114
+ return max(done_dates) if done_dates else None
115
+
116
+ @staticmethod
117
+ def days_since_last_summary() -> int:
118
+ """่ท็ฆปไธŠๆฌกๆ€ป็ป“็š„ๅคฉๆ•ฐ"""
119
+ last = DailyStatus.get_last_summary_date()
120
+ if last is None:
121
+ return 999
122
+ last_date = datetime.date.fromisoformat(last)
123
+ return (datetime.date.today() - last_date).days
124
+
125
+ @staticmethod
126
+ def should_three_day_summary() -> bool:
127
+ """ๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ่ฟ›่กŒไธ‰ๅคฉๆ€ป็ป“"""
128
+ return DailyStatus.days_since_last_summary() >= 3
129
+
130
+
131
+ # ============================================================
132
+ # ไธปๅพช็Žฏๅผ•ๆ“Ž
133
+ # ============================================================
134
+ class PregoPalLoop:
135
+ """ๆ ธๅฟƒๅพช็Žฏๅผ•ๆ“Ž"""
136
+
137
+ def __init__(self):
138
+ self.plugins = PluginRegistry()
139
+ self.state = LoopState.LAUNCH
140
+ self.context = LoopContext()
141
+ self._register_default_plugins()
142
+
143
+ def _register_default_plugins(self):
144
+ """ๆณจๅ†Œ้ป˜่ฎคๆ’ไปถ"""
145
+ from plugins.family_quiz import FamilyRecipeQuizPlugin, WeightQuizPlugin
146
+ from plugins.diet_summary import DietSummaryPlugin
147
+ from plugins.weight_check import WeightCheckPlugin
148
+ from plugins.family_memory import FamilyMemoryPlugin
149
+ from plugins.dri_analysis import DRIAnalysisPlugin
150
+ from plugins.briefing_generator import BriefingGeneratorPlugin
151
+ from plugins.three_day_summary import ThreeDaySummaryPlugin
152
+ from plugins.preset_writer import PresetWriterPlugin
153
+
154
+ self.plugins.register(FamilyRecipeQuizPlugin())
155
+ self.plugins.register(WeightQuizPlugin())
156
+ self.plugins.register(DietSummaryPlugin())
157
+ self.plugins.register(WeightCheckPlugin())
158
+ self.plugins.register(FamilyMemoryPlugin())
159
+ self.plugins.register(DRIAnalysisPlugin())
160
+ self.plugins.register(BriefingGeneratorPlugin())
161
+ self.plugins.register(ThreeDaySummaryPlugin())
162
+ self.plugins.register(PresetWriterPlugin())
163
+
164
+ async def run(self) -> None:
165
+ """ไธปๅพช็Žฏๅ…ฅๅฃ"""
166
+ while self.state is not LoopState.DONE:
167
+ handler_name = f"_state_{self.state.value}"
168
+ handler = getattr(self, handler_name)
169
+ event = await handler()
170
+ next_state = _TRANSITIONS.get((self.state, event))
171
+ if next_state is None:
172
+ raise RuntimeError(
173
+ f"No transition from {self.state} on '{event}'"
174
+ )
175
+ self.state = next_state
176
+
177
+ # ============================================================
178
+ # ็Šถๆ€ๅค„็†ๅ™จ
179
+ # ============================================================
180
+
181
+ async def _state_launch(self) -> str:
182
+ """ๅฏๅŠจๆฃ€ๆŸฅ๏ผšๆฃ€ๆŸฅไปŠๆ—ฅ็Šถๆ€ไฝ"""
183
+ if DailyStatus.is_today_done():
184
+ return "already_done"
185
+ return "need_summary"
186
+
187
+ async def _state_family_quiz(self) -> str:
188
+ """ๅฎถๅบญ้—ฎๅท๏ผšๆฃ€ๆŸฅๆ˜ฏๅฆ้œ€่ฆ่ฏข้—ฎ่œ่ฐฑ/ไฝ“้‡"""
189
+ for plugin in self.plugins.get_plugins(LoopStage.FAMILY_QUIZ):
190
+ result = await plugin.run(self.context)
191
+ if not result.success:
192
+ self.context.errors.append(result.message)
193
+ return "ok"
194
+
195
+ async def _state_summarize(self) -> str:
196
+ """ๆ˜จๆ—ฅๆ€ป็ป“๏ผšๆ‰ง่กŒๆ‰€ๆœ‰ SUMMARIZE ้˜ถๆฎตๆ’ไปถ"""
197
+ for plugin in self.plugins.get_plugins(LoopStage.SUMMARIZE):
198
+ result = await plugin.run(self.context)
199
+ if not result.success:
200
+ self.context.errors.append(result.message)
201
+ return "ok"
202
+
203
+ async def _state_analyze(self) -> str:
204
+ """่ฅๅ…ปๅˆ†ๆž๏ผšๆ‰ง่กŒๆ‰€ๆœ‰ ANALYZE ้˜ถๆฎตๆ’ไปถ"""
205
+ for plugin in self.plugins.get_plugins(LoopStage.ANALYZE):
206
+ result = await plugin.run(self.context)
207
+ if not result.success:
208
+ self.context.errors.append(result.message)
209
+ return "ok"
210
+
211
+ async def _state_brief(self) -> str:
212
+ """็”ŸๆˆไปŠๆ—ฅ็ฎ€ๆŠฅ๏ผšๆ‰ง่กŒๆ‰€ๆœ‰ BRIEF ้˜ถๆฎตๆ’ไปถ"""
213
+ for plugin in self.plugins.get_plugins(LoopStage.BRIEF):
214
+ result = await plugin.run(self.context)
215
+ if not result.success:
216
+ self.context.errors.append(result.message)
217
+ return "ok"
218
+
219
+ async def _state_interact(self) -> str:
220
+ """
221
+ ็™ฝๅคฉไบคไบ’ๆจกๅผ๏ผš็ญ‰ๅพ…็”จๆˆทๆ“ไฝœ
222
+ ๆญค็Šถๆ€็”ฑๅค–้ƒจไบ‹ไปถ่งฆๅ‘๏ผˆGradio ็•Œ้ขไบคไบ’๏ผ‰
223
+ """
224
+ return "day_ended"
225
+
226
+ async def _state_three_day(self) -> str:
227
+ """ๆฏไธ‰ๅคฉๆ€ป็ป“๏ผšๆ‰ง่กŒๆ‰€ๆœ‰ THREE_DAY ้˜ถๆฎตๆ’ไปถ"""
228
+ for plugin in self.plugins.get_plugins(LoopStage.THREE_DAY):
229
+ result = await plugin.run(self.context)
230
+ if not result.success:
231
+ self.context.errors.append(result.message)
232
+ return "ok"
233
+
234
+ async def _state_consolidate(self) -> str:
235
+ """ๆ™š้—ดๆ•ด็†๏ผšๆ‰ง่กŒๆ‰€ๆœ‰ CONSOLIDATE ้˜ถๆฎตๆ’ไปถ"""
236
+ for plugin in self.plugins.get_plugins(LoopStage.CONSOLIDATE):
237
+ result = await plugin.run(self.context)
238
+ if not result.success:
239
+ self.context.errors.append(result.message)
240
+
241
+ if DailyStatus.should_three_day_summary():
242
+ return "need_3day"
243
+ return "ok"
244
+
245
+ async def _state_done(self) -> str:
246
+ """ๆ ‡่ฎฐไปŠๆ—ฅๅฎŒๆˆ"""
247
+ DailyStatus.mark_day_ended()
248
+ return "done_complete"
249
+
250
+ # ============================================================
251
+ # ๅค–้ƒจๆŽฅๅฃ
252
+ # ============================================================
253
+
254
+ def get_briefing(self) -> dict:
255
+ """่Žทๅ–ไปŠๆ—ฅ็ฎ€ๆŠฅ"""
256
+ return self.context.briefing
257
+
258
+ def get_thinking_keywords(self) -> str:
259
+ """่Žทๅ–ๅฝ“ๅ‰ๆ€่€ƒๅ…ณ้”ฎ่ฏ๏ผˆ็”จไบŽ UI ๆ˜พ็คบ๏ผ‰"""
260
+ return self.context.briefing.get("thinking_keywords", "")
261
+
262
+ def get_errors(self) -> list[str]:
263
+ """่Žท๏ฟฝ๏ฟฝ้”™่ฏฏๅˆ—่กจ"""
264
+ return self.context.errors
265
+
266
+ def run_sync(self):
267
+ """ๅŒๆญฅ่ฟ่กŒ๏ผˆ็”จไบŽ้žๅผ‚ๆญฅ็Žฏๅขƒ๏ผ‰"""
268
+ asyncio.run(self.run())
269
+
270
+
271
+ # ============================================================
272
+ # ไพฟๆทๅ‡ฝๆ•ฐ
273
+ # ============================================================
274
+ def run_daily_loop():
275
+ """่ฟ่กŒๆฏๆ—ฅๅพช็Žฏ๏ผˆๅŒๆญฅๅ…ฅๅฃ๏ผ‰"""
276
+ loop = PregoPalLoop()
277
+ loop.run_sync()
278
+ return loop
279
+
280
+
281
+ def check_and_run_loop() -> PregoPalLoop:
282
+ """
283
+ ๆฃ€ๆŸฅๅนถ่ฟ่กŒๅพช็Žฏ๏ผˆไพ› Gradio ๅฏๅŠจๆ—ถ่ฐƒ็”จ๏ผ‰
284
+
285
+ ๅฆ‚ๆžœไปŠๆ—ฅๅทฒๆ€ป็ป“๏ผŒ็›ดๆŽฅ่ฟ”ๅ›ž loop ๅฎžไพ‹๏ผˆไธๆ‰ง่กŒๆ€ป็ป“ๆต็จ‹๏ผ‰
286
+ ๅฆ‚ๆžœไปŠๆ—ฅๆœชๆ€ป็ป“๏ผŒๆ‰ง่กŒๅฎŒๆ•ดๆ€ป็ป“ๆต็จ‹
287
+ """
288
+ loop = PregoPalLoop()
289
+ if not DailyStatus.is_today_done():
290
+ loop.run_sync()
291
+ return loop
modules/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (309 Bytes). View file
 
modules/__pycache__/diet_extractor.cpython-311.pyc ADDED
Binary file (12.2 kB). View file
 
modules/__pycache__/diet_extractor.cpython-313.pyc ADDED
Binary file (11.5 kB). View file
 
modules/__pycache__/family_manager.cpython-311.pyc ADDED
Binary file (20.7 kB). View file
 
modules/__pycache__/family_manager.cpython-313.pyc ADDED
Binary file (17.9 kB). View file
 
modules/__pycache__/nutrition_standards.cpython-311.pyc ADDED
Binary file (16 kB). View file
 
modules/__pycache__/nutrition_standards.cpython-313.pyc ADDED
Binary file (14.6 kB). View file
 
modules/diet_extractor.py ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ PregoPal - ๅฏน่ฏๅ†…ๅฎนๆๅ–ๅ™จ
3
+ =========================
4
+ ไปŽ AI ๅ›žๅคไธญ้€š่ฟ‡ๆญฃๅˆ™่กจ่พพๅผๆๅ–็ป“ๆž„ๅŒ–ๆ•ฐๆฎใ€‚
5
+
6
+ ๆๅ–ๆ ‡่ฎฐๆ ผๅผ๏ผˆๅœจ system prompt ไธญๅ‘Š็Ÿฅๆจกๅž‹ไฝฟ็”จ๏ผ‰๏ผš
7
+ [EXTRACT_DIET]...[/EXTRACT_DIET] # ้ฅฎ้ฃŸ่ฎฐๅฝ•
8
+ [EXTRACT_RECIPE]...[/EXTRACT_RECIPE] # ่œ่ฐฑไฟกๆฏ
9
+ [EXTRACT_PREFERENCE]...[/EXTRACT_PREFERENCE] # ๅๅฅฝ/ๅฟŒๅฃ/่ฟ‡ๆ•
10
+ [EXTRACT_WEIGHT]...[/EXTRACT_WEIGHT] # ไฝ“้‡่ฎฐๅฝ•
11
+ [EXTRACT_MEMORY]...[/EXTRACT_MEMORY] # ๅฎถๅบญ่ฎฐๅฟ†
12
+ [THINKING]...[/THINKING] # ๅฝ“ๅ‰ๆ€่€ƒๆญฅ้ชค
13
+ """
14
+
15
+ import re
16
+ import datetime
17
+
18
+
19
+ class DietExtractor:
20
+ """ไปŽ AI ๅ›žๅคไธญๆๅ–ๆ‰€ๆœ‰็ป“ๆž„ๅŒ–ๆ•ฐๆฎ"""
21
+
22
+ # ============================================================
23
+ # ๆญฃๅˆ™ๆจกๅผ
24
+ # ============================================================
25
+ DIET_PATTERN = re.compile(
26
+ r'\[EXTRACT_DIET\](.*?)\[/EXTRACT_DIET\]', re.DOTALL
27
+ )
28
+ RECIPE_PATTERN = re.compile(
29
+ r'\[EXTRACT_RECIPE\](.*?)\[/EXTRACT_RECIPE\]', re.DOTALL
30
+ )
31
+ PREFERENCE_PATTERN = re.compile(
32
+ r'\[EXTRACT_PREFERENCE\](.*?)\[/EXTRACT_PREFERENCE\]', re.DOTALL
33
+ )
34
+ WEIGHT_PATTERN = re.compile(
35
+ r'\[EXTRACT_WEIGHT\](.*?)\[/EXTRACT_WEIGHT\]', re.DOTALL
36
+ )
37
+ MEMORY_PATTERN = re.compile(
38
+ r'\[EXTRACT_MEMORY\](.*?)\[/EXTRACT_MEMORY\]', re.DOTALL
39
+ )
40
+ THINKING_PATTERN = re.compile(
41
+ r'\[THINKING\](.*?)\[/THINKING\]', re.DOTALL
42
+ )
43
+
44
+ # ============================================================
45
+ # ็ปŸไธ€ๆๅ–ๆŽฅๅฃ
46
+ # ============================================================
47
+ @staticmethod
48
+ def extract_all(text: str) -> dict:
49
+ """ไปŽๆ–‡ๆœฌไธญๆๅ–ๆ‰€ๆœ‰็ป“ๆž„ๅŒ–ๆ•ฐๆฎ"""
50
+ return {
51
+ "diets": DietExtractor._parse_diets(text),
52
+ "recipes": DietExtractor._parse_recipes(text),
53
+ "preferences": DietExtractor._parse_preferences(text),
54
+ "weights": DietExtractor._parse_weights(text),
55
+ "memories": DietExtractor._parse_memories(text),
56
+ "thinking": DietExtractor._parse_thinking(text),
57
+ }
58
+
59
+ # ============================================================
60
+ # ๅ„็ฑปๅž‹่งฃๆž
61
+ # ============================================================
62
+ @staticmethod
63
+ def _parse_block(text: str, pattern: re.Pattern) -> list[dict]:
64
+ """้€š็”จ่งฃๆžๅ—"""
65
+ results = []
66
+ for match in pattern.finditer(text):
67
+ block = match.group(1).strip()
68
+ entry = {}
69
+ for line in block.split('\n'):
70
+ line = line.strip()
71
+ if ':' in line:
72
+ key, val = line.split(':', 1)
73
+ entry[key.strip()] = val.strip()
74
+ if entry:
75
+ results.append(entry)
76
+ return results
77
+
78
+ @staticmethod
79
+ def _parse_diets(text: str) -> list[dict]:
80
+ """่งฃๆž [EXTRACT_DIET] ๅ—"""
81
+ results = []
82
+ for match in DietExtractor.DIET_PATTERN.finditer(text):
83
+ block = match.group(1).strip()
84
+ entry = {"meals": {}}
85
+ for line in block.split('\n'):
86
+ line = line.strip()
87
+ if not line or ':' not in line:
88
+ continue
89
+ key, val = line.split(':', 1)
90
+ key = key.strip()
91
+ val = val.strip()
92
+ if key in ('ๆ—ฅๆœŸ', '่ฎฐๅฝ•ไบบ', 'ๅค‡ๆณจ'):
93
+ entry[key] = val
94
+ elif key in ('ๆ—ฉ้ค', 'ๅˆ้ค', 'ๆ™š้ค', 'ๅŠ ้ค'):
95
+ if val:
96
+ entry["meals"][key] = val
97
+ if entry.get("meals"):
98
+ results.append(entry)
99
+ return results
100
+
101
+ @staticmethod
102
+ def _parse_recipes(text: str) -> list[dict]:
103
+ """่งฃๆž [EXTRACT_RECIPE] ๅ—"""
104
+ return DietExtractor._parse_block(text, DietExtractor.RECIPE_PATTERN)
105
+
106
+ @staticmethod
107
+ def _parse_preferences(text: str) -> list[dict]:
108
+ """่งฃๆž [EXTRACT_PREFERENCE] ๅ—"""
109
+ return DietExtractor._parse_block(text, DietExtractor.PREFERENCE_PATTERN)
110
+
111
+ @staticmethod
112
+ def _parse_weights(text: str) -> list[dict]:
113
+ """่งฃๆž [EXTRACT_WEIGHT] ๅ—"""
114
+ return DietExtractor._parse_block(text, DietExtractor.WEIGHT_PATTERN)
115
+
116
+ @staticmethod
117
+ def _parse_memories(text: str) -> list[dict]:
118
+ """่งฃๆž [EXTRACT_MEMORY] ๅ—"""
119
+ return DietExtractor._parse_block(text, DietExtractor.MEMORY_PATTERN)
120
+
121
+ @staticmethod
122
+ def _parse_thinking(text: str) -> dict | None:
123
+ """่งฃๆž [THINKING] ๅ—๏ผˆๅชๅ–็ฌฌไธ€ไธช๏ผ‰"""
124
+ match = DietExtractor.THINKING_PATTERN.search(text)
125
+ if not match:
126
+ return None
127
+ block = match.group(1).strip()
128
+ result = {}
129
+ for line in block.split('\n'):
130
+ line = line.strip()
131
+ if ':' in line:
132
+ key, val = line.split(':', 1)
133
+ result[key.strip()] = val.strip()
134
+ return result if result else None
135
+
136
+ # ============================================================
137
+ # Fallback ๅ…ณ้”ฎ่ฏๅŒน้…๏ผˆๅฝ“ๆญฃๅˆ™ๅคฑ่ดฅๆ—ถไฝฟ็”จ๏ผ‰
138
+ # ============================================================
139
+ @staticmethod
140
+ def fallback_extract_diet(text: str) -> dict | None:
141
+ """
142
+ ๅฝ“ [EXTRACT_DIET] ๆ ผๅผไธๅฎŒๆ•ดๆ—ถ๏ผŒ็”จๅ…ณ้”ฎ่ฏๅŒน้…ๅฐ่ฏ•ๆๅ–
143
+
144
+ ๅŒน้…ๆจกๅผ๏ผš
145
+ - "ๅƒไบ†" โ†’ ่ฎฐๅฝ•้ฃŸ็‰ฉ
146
+ - "ๆƒณๅƒ" โ†’ ่ฎฐๅฝ•ๆ„ฟๆœ›
147
+ - "่ฎฐๅฝ•" โ†’ ่ฎฐๅฝ•ๅ†…ๅฎน
148
+ """
149
+ result = {"meals": {}, "notes": ""}
150
+
151
+ # ๅฐ่ฏ•ๅŒน้… "ๅƒไบ†" ๆจกๅผ
152
+ eat_patterns = [
153
+ r'(ๆ—ฉ้ค|ๅˆ้ค|ๆ™š้ค|ๅŠ ้ค).{0,5}(?:ๅƒไบ†|ๅƒ็š„|ๅƒ็š„ๆ˜ฏ|ๆƒณๅƒ)(.{1,50})',
154
+ r'(?:ๅƒไบ†|ๅƒ็š„|ๅƒ็š„ๆ˜ฏ|ๆƒณๅƒ).{0,5}(ๆ—ฉ้ค|ๅˆ้ค|ๆ™š้ค|ๅŠ ้ค)(.{1,50})',
155
+ ]
156
+ for pattern in eat_patterns:
157
+ for match in re.finditer(pattern, text):
158
+ meal_time = match.group(1)
159
+ food = match.group(2).strip()
160
+ if meal_time in ('ๆ—ฉ้ค', 'ๅˆ้ค', 'ๆ™š้ค', 'ๅŠ ้ค') and food:
161
+ result["meals"][meal_time] = food
162
+
163
+ # ๅฐ่ฏ•ๅŒน้… "่ฎฐๅฝ•" ๆจกๅผ
164
+ record_match = re.search(r'่ฎฐๅฝ•[ไบ†:๏ผš]?\s*(.{1,100})', text)
165
+ if record_match:
166
+ result["notes"] = record_match.group(1).strip()
167
+
168
+ return result if result["meals"] else None
169
+
170
+ @staticmethod
171
+ def fallback_extract_thinking(text: str) -> dict | None:
172
+ """
173
+ ๅฝ“ [THINKING] ๆ ผๅผไธๅฎŒๆ•ดๆ—ถ๏ผŒ็”จๅ…ณ้”ฎ่ฏๅŒน้…ๅฐ่ฏ•ๆๅ–
174
+ """
175
+ result = {}
176
+ step_match = re.search(r'(?:ๅฝ“ๅ‰ๆญฅ้ชค|ๆญฃๅœจ|ๅฝ“ๅ‰).{0,5}(.{5,30})', text)
177
+ if step_match:
178
+ result["ๅฝ“ๅ‰ๆญฅ้ชค"] = step_match.group(1).strip()
179
+ next_match = re.search(r'(?:ไธ‹ไธ€ๆญฅ|ๆŽฅไธ‹ๆฅ|็„ถๅŽ).{0,5}(.{5,30})', text)
180
+ if next_match:
181
+ result["ไธ‹ไธ€ๆญฅ"] = next_match.group(1).strip()
182
+ return result if result else None
183
+
184
+ # ============================================================
185
+ # ็ปผๅˆๆๅ–๏ผˆๆญฃๅˆ™ไผ˜ๅ…ˆ + fallback๏ผ‰
186
+ # ============================================================
187
+ @staticmethod
188
+ def robust_extract(text: str) -> dict:
189
+ """็ปผๅˆๆๅ–๏ผšๅ…ˆ็”จๆญฃๅˆ™๏ผŒๅคฑ่ดฅๆ—ถ็”จ fallback"""
190
+ result = DietExtractor.extract_all(text)
191
+
192
+ # ๅฆ‚ๆžœๆญฃๅˆ™ๆฒกๆๅ–ๅˆฐ้ฅฎ้ฃŸ๏ผŒๅฐ่ฏ• fallback
193
+ if not result["diets"]:
194
+ fallback = DietExtractor.fallback_extract_diet(text)
195
+ if fallback:
196
+ result["diets"] = [fallback]
197
+
198
+ # ๅฆ‚ๆžœๆญฃๅˆ™ๆฒกๆๅ–ๅˆฐ thinking๏ผŒๅฐ่ฏ• fallback
199
+ if not result["thinking"]:
200
+ fallback = DietExtractor.fallback_extract_thinking(text)
201
+ if fallback:
202
+ result["thinking"] = fallback
203
+
204
+ return result
205
+
206
+
207
+ # ============================================================
208
+ # System Prompt ๆจกๆฟ๏ผˆๅ‘Š็Ÿฅๆจกๅž‹ไฝฟ็”จๆ ‡่ฎฐๆ ผๅผ๏ผ‰
209
+ # ============================================================
210
+ EXTRACT_SYSTEM_PROMPT = """
211
+ ## ๆ•ฐๆฎ่ฎฐๅฝ•ๆ ผๅผ
212
+
213
+ ๅฝ“ๅฏน่ฏไธญๅ‡บ็Žฐไปฅไธ‹ๆƒ…ๅ†ตๆ—ถ๏ผŒ่ฏทไฝฟ็”จ็‰นๅฎšๆ ‡่ฎฐๅŒ…่ฃน็ป“ๆž„ๅŒ–ๆ•ฐๆฎ๏ผš
214
+
215
+ ### 1. ่ฎฐๅฝ•้ฅฎ้ฃŸ
216
+ ๅฝ“ๅญ•ๅฆ‡ๆˆ–ๅฎถไบบๆๅˆฐๅƒไบ†ไป€ไนˆใ€ๆƒณๅƒไป€ไนˆๆ—ถ๏ผŒ่พ“ๅ‡บ๏ผš
217
+ [EXTRACT_DIET]
218
+ ๆ—ฅๆœŸ: {date}
219
+ ้คๆฌก: ๆ—ฉ้ค/ๅˆ้ค/ๆ™š้ค/ๅŠ ้ค
220
+ ้ฃŸ็‰ฉ: ๅ…ทไฝ“้ฃŸ็‰ฉๅ็งฐ
221
+ ไปฝ้‡: ๅคงๆฆ‚ไปฝ้‡
222
+ ่ฎฐๅฝ•ไบบ: ่ฏด่ฏไบบ่บซไปฝ
223
+ ๅค‡ๆณจ: ๅญ•ๅฆ‡่ฏดๆƒณๅƒ/ๅญ•ๅฆ‡ๅƒไบ†/ๅฎถไบบ่ฏดๅญ•ๅฆ‡ๆƒณๅƒ
224
+ [/EXTRACT_DIET]
225
+
226
+ ### 2. ่ฎฐๅฝ•่œ่ฐฑ
227
+ ๅฝ“ๅฎถไบบๆๅˆฐไผšๅšไป€ไนˆ่œๆ—ถ๏ผŒ่พ“ๅ‡บ๏ผš
228
+ [EXTRACT_RECIPE]
229
+ ่œๅ: ่œๅ
230
+ ๅˆถไฝœไบบ: ่ฐๅš็š„
231
+ ้šพๅบฆ: ็ฎ€ๅ•/ไธญ็ญ‰/ๅ›ฐ้šพ
232
+ ้ฃŸๆ: ไธป่ฆ้ฃŸๆ
233
+ ๅค‡ๆณจ: ๅญ•ๅฆ‡็ˆฑๅƒ/ๅฎถไบบ็ˆฑๅƒ
234
+ [/EXTRACT_RECIPE]
235
+
236
+ ### 3. ่ฎฐๅฝ•ๅๅฅฝ/ๅฟŒๅฃ/่ฟ‡ๆ•
237
+ ๅฝ“ๆๅˆฐ้ฅฎ้ฃŸๅๅฅฝใ€ๅฟŒๅฃๆˆ–่ฟ‡ๆ•ๆ—ถ๏ผŒ่พ“ๅ‡บ๏ผš
238
+ [EXTRACT_PREFERENCE]
239
+ ไบบๅ‘˜: ๅง“ๅ
240
+ ็ฑปๅž‹: ๅๅฅฝ/ๅฟŒๅฃ/่ฟ‡ๆ•
241
+ ๅ†…ๅฎน: ๅ…ทไฝ“ๅ†…ๅฎน
242
+ [/EXTRACT_PREFERENCE]
243
+
244
+ ### 4. ่ฎฐๅฝ•ไฝ“้‡
245
+ ๅฝ“ๅญ•ๅฆ‡ๆๅˆฐไฝ“้‡ๆ—ถ๏ผŒ่พ“ๅ‡บ๏ผš
246
+ [EXTRACT_WEIGHT]
247
+ ๆ—ฅๆœŸ: {date}
248
+ ไฝ“้‡: ๆ•ฐๅ€ผ(kg)
249
+ ่ฎฐๅฝ•ไบบ: ่ฏด่ฏไบบ่บซไปฝ
250
+ [/EXTRACT_WEIGHT]
251
+
252
+ ### 5. ่ฎฐๅฝ•ๅฎถๅบญ่ฎฐๅฟ†
253
+ ๅฝ“ๆๅˆฐๅฎถๅบญๅ…ณ็ณปๆˆ–้‡่ฆไบ‹ไปถๆ—ถ๏ผŒ่พ“ๅ‡บ๏ผš
254
+ [EXTRACT_MEMORY]
255
+ ็ฑปๅž‹: ๅ…ณ็ณป/ไบ‹ไปถ/ๆ—ฅๅธธ
256
+ ๅ†…ๅฎน: ๅ…ทไฝ“ๅ†…ๅฎน
257
+ [/EXTRACT_MEMORY]
258
+
259
+ ### 6. ๆ˜พ็คบๅฝ“ๅ‰ๆ€่€ƒ
260
+ ๆฏๆฌกๆ‰ง่กŒไธ‹ไธ€ๆญฅๆ“ไฝœๆ—ถ๏ผŒ่พ“ๅ‡บ๏ผš
261
+ [THINKING]
262
+ ๅฝ“ๅ‰ๆญฅ้ชค: ๆญฃๅœจๅšไป€ไนˆ
263
+ ไธ‹ไธ€ๆญฅ: ๆŽฅไธ‹ๆฅ่ฆๅšไป€ไนˆ
264
+ [/THINKING]
265
+
266
+ ๆณจๆ„๏ผšๆ ‡่ฎฐๅ—ๅฏไปฅๅ‡บ็Žฐๅœจๅ›žๅค็š„ไปปไฝ•ไฝ็ฝฎ๏ผŒไธๅฝฑๅ“ๆญฃๅธธๅฏน่ฏๅ†…ๅฎนใ€‚
267
+ """
268
+
269
+
270
+ def get_extract_prompt(date_str: str = None) -> str:
271
+ """่Žทๅ–ๅธฆๆ—ฅๆœŸ็š„ๆๅ–ๆ็คบ่ฏ"""
272
+ if date_str is None:
273
+ date_str = datetime.date.today().isoformat()
274
+ return EXTRACT_SYSTEM_PROMPT.format(date=date_str)
modules/family_manager.py ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ PregoPal - ๅฎถๅบญไฟกๆฏ็ฎก็†
3
+ =======================
4
+ ็ฎก็†ๅฎถๅบญ่œ่ฐฑใ€้ฅฎ้ฃŸๅๅฅฝ/ๅฟŒๅฃ/่ฟ‡ๆ•ใ€ๅฎถๅบญ่ฎฐๅฟ†๏ผˆๅ…ณ็ณป/ไบ‹ไปถ๏ผ‰ใ€‚
5
+
6
+ ๆ•ฐๆฎๆ–‡ไปถ๏ผš
7
+ data/family/
8
+ โ”œโ”€โ”€ recipes.md # ๅฎถๅบญ่œ่ฐฑ๏ผˆๅฎถไบบไผšๅš็š„่œ๏ผ‰
9
+ โ”œโ”€โ”€ preferences.md # ้ฅฎ้ฃŸๅๅฅฝ/ๅฟŒๅฃ/่ฟ‡ๆ•
10
+ โ””โ”€โ”€ memory.md # ๅฎถๅบญ่ฎฐๅฟ†๏ผˆๅ…ณ็ณป/ไบ‹ไปถ๏ผ‰
11
+ """
12
+
13
+ import datetime
14
+ import re
15
+ from pathlib import Path
16
+
17
+ FAMILY_DIR = Path("data/family")
18
+
19
+
20
+ # ============================================================
21
+ # ็กฎไฟ็›ฎๅฝ•ๅญ˜ๅœจ
22
+ # ============================================================
23
+ def ensure_family_dir():
24
+ FAMILY_DIR.mkdir(parents=True, exist_ok=True)
25
+
26
+
27
+ # ============================================================
28
+ # 1. ๅฎถๅบญ่œ่ฐฑ็ฎก็†
29
+ # ============================================================
30
+ class RecipeManager:
31
+ """็ฎก็†ๅฎถๅบญ่œ่ฐฑ๏ผˆๅฎถไบบไผšๅš็š„่œ๏ผ‰"""
32
+
33
+ RECIPES_FILE = FAMILY_DIR / "recipes.md"
34
+
35
+ @classmethod
36
+ def ensure_file(cls):
37
+ ensure_family_dir()
38
+ if not cls.RECIPES_FILE.exists():
39
+ with open(cls.RECIPES_FILE, 'w', encoding='utf-8') as f:
40
+ f.write("# ๅฎถๅบญ่œ่ฐฑ\n\n> ่ฎฐๅฝ•ๅฎถไบบไผšๅš็š„่œใ€‚\n\n## ่œ่ฐฑๅˆ—่กจ\n\n")
41
+
42
+ @classmethod
43
+ def load_all(cls) -> list[dict]:
44
+ """่ฏปๅ–ๆ‰€ๆœ‰่œ่ฐฑ"""
45
+ cls.ensure_file()
46
+ content = cls.RECIPES_FILE.read_text(encoding='utf-8')
47
+ recipes = []
48
+ blocks = re.split(r'\n### ', content)[1:]
49
+ for block in blocks:
50
+ lines = block.strip().split('\n')
51
+ name = lines[0].strip()
52
+ if not name or name.startswith('<!--'):
53
+ continue
54
+ recipe = {"name": name, "cook": "", "difficulty": "", "ingredients": "", "notes": ""}
55
+ for line in lines[1:]:
56
+ line = line.strip()
57
+ if line.startswith('- **ๅˆถไฝœไบบ**'):
58
+ recipe["cook"] = line.split(':', 1)[-1].strip()
59
+ elif line.startswith('- **้šพๅบฆ**'):
60
+ recipe["difficulty"] = line.split(':', 1)[-1].strip()
61
+ elif line.startswith('- **้ฃŸๆ**'):
62
+ recipe["ingredients"] = line.split(':', 1)[-1].strip()
63
+ elif line.startswith('- **ๅค‡ๆณจ**'):
64
+ recipe["notes"] = line.split(':', 1)[-1].strip()
65
+ if name:
66
+ recipes.append(recipe)
67
+ return recipes
68
+
69
+ @classmethod
70
+ def add_recipe(cls, name: str, cook: str = "", difficulty: str = "",
71
+ ingredients: str = "", notes: str = "") -> str:
72
+ """ๆทปๅŠ ไธ€้“่œ่ฐฑ"""
73
+ cls.ensure_file()
74
+ existing = cls.load_all()
75
+ if any(r["name"] == name for r in existing):
76
+ return "[WARN] ่œ่ฐฑๅทฒๅญ˜ๅœจ: " + name
77
+
78
+ entry = f"""
79
+ ### {name}
80
+ - **ๅˆถไฝœไบบ**: {cook}
81
+ - **้šพๅบฆ**: {difficulty}
82
+ - **้ฃŸๆ**: {ingredients}
83
+ - **ๅค‡ๆณจ**: {notes}
84
+ """
85
+ with open(cls.RECIPES_FILE, 'a', encoding='utf-8') as f:
86
+ f.write(entry)
87
+ return "[OK] ๅทฒๆทปๅŠ ่œ่ฐฑ: " + name
88
+
89
+ @classmethod
90
+ def format_for_prompt(cls) -> str:
91
+ """ๆ ผๅผๅŒ–ไธบ system prompt ๅฏ็”จ็š„ๆ–‡ๆœฌ"""
92
+ recipes = cls.load_all()
93
+ if not recipes:
94
+ return "ใ€ๅฎถๅบญ่œ่ฐฑใ€‘ๆš‚ๆ— ่ฎฐๅฝ•๏ผŒ่ฏทไธปๅŠจ่ฏข้—ฎๅฎถไบบไผšๅšไป€ไนˆ่œใ€‚"
95
+ lines = ["ใ€ๅฎถๅบญ่œ่ฐฑใ€‘"]
96
+ for r in recipes:
97
+ lines.append(f" - {r['name']}๏ผˆ{r['cook']}ไผšๅš๏ผ‰")
98
+ return "\n".join(lines)
99
+
100
+ @classmethod
101
+ def get_names(cls) -> list[str]:
102
+ """่Žทๅ–ๆ‰€ๆœ‰่œๅ"""
103
+ return [r["name"] for r in cls.load_all()]
104
+
105
+
106
+ # ============================================================
107
+ # 2. ้ฅฎ้ฃŸๅๅฅฝ็ฎก็†
108
+ # ============================================================
109
+ class PreferenceManager:
110
+ """็ฎก็†ๆ‰€ๆœ‰ๅฎถๅบญๆˆๅ‘˜็š„้ฅฎ้ฃŸๅๅฅฝใ€ๅฟŒๅฃใ€่ฟ‡ๆ•"""
111
+
112
+ PREFERENCES_FILE = FAMILY_DIR / "preferences.md"
113
+
114
+ @classmethod
115
+ def ensure_file(cls):
116
+ ensure_family_dir()
117
+ if not cls.PREFERENCES_FILE.exists():
118
+ with open(cls.PREFERENCES_FILE, 'w', encoding='utf-8') as f:
119
+ f.write("# ๅฎถๅบญๆˆๅ‘˜้ฅฎ้ฃŸๅๅฅฝ\n\n> ่ฎฐๅฝ•ๆ‰€ๆœ‰ๅฎถไบบ็š„้ฅฎ้ฃŸๅๅฅฝใ€ๅฟŒๅฃใ€่ฟ‡ๆ•ไฟกๆฏใ€‚\n\n## ๆˆๅ‘˜ๅˆ—่กจ\n\n")
120
+
121
+ @classmethod
122
+ def load_all(cls) -> list[dict]:
123
+ """่ฏปๅ–ๆ‰€ๆœ‰ๆˆๅ‘˜ๅๅฅฝ"""
124
+ cls.ensure_file()
125
+ content = cls.PREFERENCES_FILE.read_text(encoding='utf-8')
126
+ members = []
127
+ blocks = re.split(r'\n### ๆˆๅ‘˜[๏ผš:]', content)[1:]
128
+ for block in blocks:
129
+ lines = block.strip().split('\n')
130
+ name_line = lines[0].strip()
131
+ if not name_line or name_line.startswith('<!--'):
132
+ continue
133
+ # ๆๅ–็บฏๅ็งฐ๏ผˆๅŽปๆމๆ‹ฌๅทไธญ็š„่ง’่‰ฒไฟกๆฏ๏ผ‰
134
+ clean_name = name_line.split('๏ผˆ')[0].strip() if '๏ผˆ' in name_line else name_line
135
+ member = {"name": clean_name, "role": "", "preferences": "", "avoid": "", "allergies": "", "notes": ""}
136
+ for line in lines[1:]:
137
+ line = line.strip()
138
+ if line.startswith('- **ๅๅฅฝ**'):
139
+ member["preferences"] = line.split(':', 1)[-1].strip()
140
+ elif line.startswith('- **ๅฟŒๅฃ**'):
141
+ member["avoid"] = line.split(':', 1)[-1].strip()
142
+ elif line.startswith('- **่ฟ‡ๆ•**'):
143
+ member["allergies"] = line.split(':', 1)[-1].strip()
144
+ elif line.startswith('- **ๅค‡ๆณจ**'):
145
+ member["notes"] = line.split(':', 1)[-1].strip()
146
+ if clean_name:
147
+ members.append(member)
148
+ return members
149
+
150
+ @classmethod
151
+ def add_member(cls, name: str, role: str = "", preferences: str = "",
152
+ avoid: str = "", allergies: str = "", notes: str = "") -> str:
153
+ """ๆทปๅŠ ๆˆ–ๆ›ดๆ–ฐๆˆๅ‘˜ๅๅฅฝ"""
154
+ cls.ensure_file()
155
+ existing = cls.load_all()
156
+ remaining = [m for m in existing if m["name"] != name]
157
+
158
+ content = "# ๅฎถๅบญๆˆๅ‘˜้ฅฎ้ฃŸๅๅฅฝ\n\n> ่ฎฐๅฝ•ๆ‰€ๆœ‰ๅฎถไบบ็š„้ฅฎ้ฃŸๅๅฅฝใ€ๅฟŒๅฃใ€่ฟ‡ๆ•ไฟกๆฏใ€‚\n\n## ๆˆๅ‘˜ๅˆ—่กจ\n\n"
159
+ for m in remaining:
160
+ role_str = f"๏ผˆ{m['role']}๏ผ‰" if m['role'] else ""
161
+ content += f"""### ๆˆๅ‘˜๏ผš{m['name']}{role_str}
162
+ - **ๅๅฅฝ**: {m['preferences']}
163
+ - **ๅฟŒๅฃ**: {m['avoid']}
164
+ - **่ฟ‡ๆ•**: {m['allergies']}
165
+ - **ๅค‡ๆณจ**: {m['notes']}
166
+
167
+ """
168
+ role_str = f"๏ผˆ{role}๏ผ‰" if role else ""
169
+ content += f"""### ๆˆๅ‘˜๏ผš{name}{role_str}
170
+ - **ๅๅฅฝ**: {preferences}
171
+ - **ๅฟŒๅฃ**: {avoid}
172
+ - **่ฟ‡ๆ•**: {allergies}
173
+ - **ๅค‡ๆณจ**: {notes}
174
+
175
+ """
176
+ with open(cls.PREFERENCES_FILE, 'w', encoding='utf-8') as f:
177
+ f.write(content)
178
+ return "[OK] ๅทฒไฟๅญ˜ " + role + " - " + name + " ็š„้ฅฎ้ฃŸๅๅฅฝ"
179
+
180
+ @classmethod
181
+ def format_for_prompt(cls) -> str:
182
+ """ๆ ผๅผๅŒ–ไธบ system prompt ๅฏ็”จ็š„ๆ–‡ๆœฌ"""
183
+ members = cls.load_all()
184
+ if not members:
185
+ return "ใ€ๅฎถๅบญๆˆๅ‘˜้ฅฎ้ฃŸๅๅฅฝใ€‘ๆš‚ๆ— ่ฎฐๅฝ•ใ€‚"
186
+ lines = ["ใ€ๅฎถๅบญๆˆๅ‘˜้ฅฎ้ฃŸๅๅฅฝใ€‘"]
187
+ for m in members:
188
+ parts = [f" - {m['name']}๏ผˆ{m['role']}๏ผ‰"]
189
+ if m['preferences']:
190
+ parts.append(f"ๅๅฅฝ: {m['preferences']}")
191
+ if m['avoid']:
192
+ parts.append(f"ๅฟŒๅฃ: {m['avoid']}")
193
+ if m['allergies']:
194
+ parts.append(f"่ฟ‡ๆ•: {m['allergies']}")
195
+ lines.append(" | ".join(parts))
196
+ return "\n".join(lines)
197
+
198
+
199
+ # ============================================================
200
+ # 3. ๅฎถๅบญ่ฎฐๅฟ†็ฎก็†
201
+ # ============================================================
202
+ class MemoryManager:
203
+ """็ฎก็†ๅฎถๅบญ่ฎฐๅฟ†๏ผˆๅ…ณ็ณปใ€ไบ‹ไปถใ€ๆ—ฅๅธธ๏ผ‰"""
204
+
205
+ MEMORY_FILE = FAMILY_DIR / "memory.md"
206
+
207
+ @classmethod
208
+ def ensure_file(cls):
209
+ ensure_family_dir()
210
+ if not cls.MEMORY_FILE.exists():
211
+ with open(cls.MEMORY_FILE, 'w', encoding='utf-8') as f:
212
+ f.write("# ๅฎถๅบญ่ฎฐๅฟ†\n\n> ่ฎฐๅฝ•ๅฎถๅบญๅ…ณ็ณปใ€้‡่ฆไบ‹ไปถใ€ๆ—ฅๅธธ็‚นๆปดใ€‚\n\n## ๅฎถๅบญๅ…ณ็ณป\n\n## ้‡่ฆไบ‹ไปถ\n\n## ๆ—ฅๅธธ่ฎฐๅฝ•\n\n")
213
+
214
+ @classmethod
215
+ def load_all(cls) -> dict:
216
+ """่ฏปๅ–ๆ‰€ๆœ‰ๅฎถๅบญ่ฎฐๅฟ†"""
217
+ cls.ensure_file()
218
+ content = cls.MEMORY_FILE.read_text(encoding='utf-8')
219
+ sections = re.split(r'\n## ', content)
220
+
221
+ result = {"relationships": [], "events": [], "daily": []}
222
+
223
+ for section in sections:
224
+ if section.startswith("ๅฎถๅบญๅ…ณ็ณป"):
225
+ for line in section.split('\n'):
226
+ if line.strip().startswith('- **'):
227
+ result["relationships"].append(line.strip())
228
+ elif section.startswith("้‡่ฆไบ‹ไปถ"):
229
+ for line in section.split('\n'):
230
+ if line.strip().startswith('- **'):
231
+ result["events"].append(line.strip())
232
+ elif section.startswith("ๆ—ฅๅธธ่ฎฐๅฝ•"):
233
+ for line in section.split('\n'):
234
+ if line.strip().startswith('- **'):
235
+ result["daily"].append(line.strip())
236
+
237
+ return result
238
+
239
+ @classmethod
240
+ def _append_to_section(cls, section_title: str, entry: str):
241
+ """ๅฐ†ๆก็›ฎ่ฟฝๅŠ ๅˆฐๆŒ‡ๅฎš็ซ ่Š‚ไธ‹"""
242
+ cls.ensure_file()
243
+ content = cls.MEMORY_FILE.read_text(encoding='utf-8')
244
+ marker = f"## {section_title}"
245
+ idx = content.find(marker)
246
+ if idx == -1:
247
+ # ็ซ ่Š‚ไธๅญ˜ๅœจ๏ผŒ่ฟฝๅŠ ๅˆฐๆœซๅฐพ
248
+ content += f"\n{marker}\n{entry}\n"
249
+ else:
250
+ # ๅœจ็ซ ่Š‚ๆ ‡้ข˜ๅŽๆ’ๅ…ฅ
251
+ after_title = content[idx + len(marker):]
252
+ # ๆ‰พๅˆฐ็ซ ่Š‚ๅ†…ๅฎน็š„ๆœซๅฐพ๏ผˆไธ‹ไธ€ไธช ## ๆˆ–ๆ–‡ไปถๆœซๅฐพ๏ผ‰
253
+ next_section = after_title.find("\n## ")
254
+ if next_section == -1:
255
+ insert_pos = len(content)
256
+ else:
257
+ insert_pos = idx + len(marker) + next_section
258
+ content = content[:insert_pos] + "\n" + entry + content[insert_pos:]
259
+ cls.MEMORY_FILE.write_text(content, encoding='utf-8')
260
+
261
+ @classmethod
262
+ def add_event(cls, description: str) -> str:
263
+ """ๆทปๅŠ ไธ€ๆก้‡่ฆไบ‹ไปถ"""
264
+ date_str = datetime.date.today().isoformat()
265
+ entry = f"- **{date_str}**: {description}"
266
+ cls._append_to_section("้‡่ฆไบ‹ไปถ", entry)
267
+ return "[OK] ๅทฒ่ฎฐๅฝ•ไบ‹ไปถ"
268
+
269
+ @classmethod
270
+ def add_daily(cls, content: str) -> str:
271
+ """ๆทปๅŠ ไธ€ๆกๆ—ฅๅธธ่ฎฐๅฝ•"""
272
+ date_str = datetime.date.today().isoformat()
273
+ entry = f"- **{date_str}**: {content}"
274
+ cls._append_to_section("ๆ—ฅๅธธ่ฎฐๅฝ•", entry)
275
+ return "[OK] ๅทฒ่ฎฐๅฝ•ๆ—ฅๅธธ"
276
+
277
+ @classmethod
278
+ def format_for_prompt(cls) -> str:
279
+ """ๆ ผๅผๅŒ–ไธบ system prompt ๅฏ็”จ็š„ๆ–‡ๆœฌ"""
280
+ data = cls.load_all()
281
+ lines = ["ใ€ๅฎถๅบญ่ฎฐๅฟ†ใ€‘"]
282
+ if data["relationships"]:
283
+ lines.append(" ๅฎถๅบญๅ…ณ็ณป๏ผš")
284
+ for r in data["relationships"][:5]:
285
+ lines.append(f" {r}")
286
+ if data["events"]:
287
+ lines.append(" ้‡่ฆไบ‹ไปถ๏ผš")
288
+ for e in data["events"][:5]:
289
+ lines.append(f" {e}")
290
+ if data["daily"]:
291
+ lines.append(" ่ฟ‘ๆœŸๆ—ฅๅธธ๏ผš")
292
+ for d in data["daily"][-3:]:
293
+ lines.append(f" {d}")
294
+ if not any(data.values()):
295
+ lines.append(" ๆš‚ๆ— ่ฎฐๅฝ•")
296
+ return "\n".join(lines)
297
+
298
+
299
+ # ============================================================
300
+ # 4. ็ปŸไธ€ๅŠ ่ฝฝๆŽฅๅฃ
301
+ # ============================================================
302
+ def load_all_family_info() -> dict:
303
+ """ๅŠ ่ฝฝๆ‰€ๆœ‰ๅฎถๅบญไฟกๆฏ"""
304
+ return {
305
+ "recipes": RecipeManager.load_all(),
306
+ "preferences": PreferenceManager.load_all(),
307
+ "memory": MemoryManager.load_all(),
308
+ }
309
+
310
+
311
+ def format_all_for_prompt() -> str:
312
+ """ๅฐ†ๆ‰€ๆœ‰ๅฎถๅบญไฟกๆฏๆ ผๅผๅŒ–ไธบ system prompt ๆ–‡ๆœฌ"""
313
+ parts = [
314
+ RecipeManager.format_for_prompt(),
315
+ "",
316
+ PreferenceManager.format_for_prompt(),
317
+ "",
318
+ MemoryManager.format_for_prompt(),
319
+ ]
320
+ return "\n".join(parts)
modules/nutrition_standards.py ADDED
@@ -0,0 +1,377 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ PregoPal - ่ฅๅ…ปๆ ‡ๅ‡†่งฃๆžๅ™จ
3
+ =========================
4
+ ่งฃๆžไธ‰ไธชๅฎ˜ๆ–น MD ๆ–‡ไปถ๏ผˆไฝ“้‡ๆ ‡ๅ‡†/่†ณ้ฃŸๆŒ‡ๅ—/DRIs๏ผ‰๏ผŒๆไพ›็ป“ๆž„ๅŒ–ๆŸฅ่ฏขๆŽฅๅฃใ€‚
5
+
6
+ ๆ•ฐๆฎๆฅๆบ๏ผš
7
+ data/nutrition/raw/
8
+ โ”œโ”€โ”€ ๅฆŠๅจ ๆœŸๅฆ‡ๅฅณไฝ“้‡ๅขž้•ฟๆŽจ่ๅ€ผๆ ‡ๅ‡†.md
9
+ โ”œโ”€โ”€ ไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณ่†ณ้ฃŸๆŒ‡ๅ—2022ๅ›พ็‰‡่ฝฌmd็‰ˆ.md
10
+ โ””โ”€โ”€ ๅค‡ๅญ•&ๅญ•ๆ—ฉไธญๆ™šไธ‰ๆœŸๅ’Œๅ“บไนณๆœŸ็š„ๆ‰€ๆœ‰่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡.md
11
+ """
12
+
13
+ import re
14
+ import json
15
+ from pathlib import Path
16
+
17
+ NUTRITION_RAW_DIR = Path("data/nutrition/raw")
18
+ PRESETS_DIR = Path("data/presets")
19
+
20
+
21
+ # ============================================================
22
+ # 1. ไฝ“้‡ๅขž้•ฟๆ ‡ๅ‡†่งฃๆžๅ™จ
23
+ # ============================================================
24
+ class WeightStandardParser:
25
+ """่งฃๆž WS/T 801-2022 ไฝ“้‡ๅขž้•ฟๆ ‡ๅ‡†๏ผŒๆไพ›ๆŸฅ่ฏขๆŽฅๅฃ"""
26
+
27
+ # ็กฌ็ผ–็ ๆ ‡ๅ‡†่กจ๏ผˆWS/T 801-2022 ่กจ1๏ผ‰
28
+ BMI_STANDARDS = [
29
+ {"category": "ไฝŽไฝ“้‡", "bmi_range": (0, 18.5),
30
+ "total_gain": (11.0, 16.0), "weekly_gain": 0.46,
31
+ "weekly_range": (0.37, 0.56)},
32
+ {"category": "ๆญฃๅธธ", "bmi_range": (18.5, 24.0),
33
+ "total_gain": (8.0, 14.0), "weekly_gain": 0.37,
34
+ "weekly_range": (0.26, 0.48)},
35
+ {"category": "่ถ…้‡", "bmi_range": (24.0, 28.0),
36
+ "total_gain": (7.0, 11.0), "weekly_gain": 0.30,
37
+ "weekly_range": (0.22, 0.37)},
38
+ {"category": "่‚ฅ่ƒ–", "bmi_range": (28.0, 999),
39
+ "total_gain": (5.0, 9.0), "weekly_gain": 0.22,
40
+ "weekly_range": (0.15, 0.30)},
41
+ ]
42
+
43
+ @classmethod
44
+ def load(cls) -> dict:
45
+ """่ฏปๅ– md ๆ–‡ไปถ๏ผŒ่ฟ”ๅ›ž็ป“ๆž„ๅŒ–ๆ•ฐๆฎ๏ผˆๅ…ผๅฎนๆŽฅๅฃ๏ผ‰"""
46
+ return {"bmi_standards": cls.BMI_STANDARDS}
47
+
48
+ @classmethod
49
+ def get_standard(cls, bmi_before_pregnancy: float) -> dict | None:
50
+ """ๆ นๆฎๅญ•ๅ‰ BMI ่Žทๅ–ๅฏนๅบ”็š„ๅขž้•ฟๆ ‡ๅ‡†"""
51
+ for std in cls.BMI_STANDARDS:
52
+ low, high = std["bmi_range"]
53
+ if low <= bmi_before_pregnancy < high:
54
+ return std
55
+ return None
56
+
57
+ @classmethod
58
+ def evaluate(cls, bmi_before_pregnancy: float, current_week: int,
59
+ total_gain: float) -> dict:
60
+ """
61
+ ่ฏ„ไผฐไฝ“้‡ๅขž้•ฟๆ˜ฏๅฆๅœจๆŽจ่่Œƒๅ›ดๅ†…
62
+
63
+ Args:
64
+ bmi_before_pregnancy: ๅญ•ๅ‰ BMI
65
+ current_week: ๅฝ“ๅ‰ๅญ•ๅ‘จ
66
+ total_gain: ๅฝ“ๅ‰ๆ€ปๅขž้•ฟๅ€ผ (kg)
67
+
68
+ Returns:
69
+ {"status": "ok"/"warning", "message": "...", "suggestion": "..."}
70
+ """
71
+ std = cls.get_standard(bmi_before_pregnancy)
72
+ if std is None:
73
+ return {"status": "error", "message": "ๆ— ๆณ•ๅŒน้… BMI ๅˆ†็ฑป", "suggestion": ""}
74
+
75
+ low, high = std["total_gain"]
76
+
77
+ if low <= total_gain <= high:
78
+ return {
79
+ "status": "ok",
80
+ "message": f"โœ… ไฝ“้‡ๅขž้•ฟๅœจ {std['category']} ๆ ‡ๅ‡†่Œƒๅ›ดๅ†…๏ผˆ{low}~{high}kg๏ผ‰๏ผŒ็ปง็ปญไฟๆŒ๏ผ",
81
+ "suggestion": f"ๅปบ่ฎฎๆฏๅ‘จๅขž้•ฟ {std['weekly_gain']}kg ๅทฆๅณ๏ผˆ่Œƒๅ›ด {std['weekly_range'][0]}~{std['weekly_range'][1]}kg๏ผ‰"
82
+ }
83
+ elif total_gain < low:
84
+ return {
85
+ "status": "warning",
86
+ "message": f"โš ๏ธ ไฝ“้‡ๅขž้•ฟๅๆ…ข๏ผˆๅฝ“ๅ‰ {total_gain}kg๏ผŒๆ ‡ๅ‡† {low}~{high}kg๏ผ‰",
87
+ "suggestion": "ๅปบ่ฎฎๅขžๅŠ ่ฅๅ…ปๆ‘„ๅ…ฅ๏ผŒ็‰นๅˆซๆ˜ฏไผ˜่ดจ่›‹็™ฝๅ’Œๅฅๅบท่„‚่‚ช๏ผŒๅ’จ่ฏขๅŒป็”Ÿๆ˜ฏๅฆ้œ€่ฆ่ฐƒๆ•ด้ฅฎ้ฃŸ"
88
+ }
89
+ else:
90
+ return {
91
+ "status": "warning",
92
+ "message": f"โš ๏ธ ไฝ“้‡ๅขž้•ฟๅๅฟซ๏ผˆๅฝ“ๅ‰ {total_gain}kg๏ผŒๆ ‡ๅ‡† {low}~{high}kg๏ผ‰",
93
+ "suggestion": "ๅปบ่ฎฎๆŽงๅˆถ้ซ˜็ณ–้ซ˜่„‚้ฃŸ็‰ฉๆ‘„ๅ…ฅ๏ผŒ้€‚ๅฝ“ๅขžๅŠ ่ฟๅŠจ้‡๏ผŒๅ’จ่ฏขๅŒป็”Ÿๆ˜ฏๅฆ้œ€่ฆ่ฐƒๆ•ด้ฅฎ้ฃŸ"
94
+ }
95
+
96
+
97
+ # ============================================================
98
+ # 2. ่†ณ้ฃŸๆŒ‡ๅ—่งฃๆžๅ™จ
99
+ # ============================================================
100
+ class DietaryGuideParser:
101
+ """่งฃๆžไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณ่†ณ้ฃŸๆŒ‡ๅ—๏ผŒๆไพ›ๅ„ๅญ•ๆœŸๆŽจ่ๆ‘„ๅ…ฅ้‡"""
102
+
103
+ # ไธญๅ›ฝๅญ•ๆœŸๅฆ‡ๅฅณๅนณ่กก่†ณ้ฃŸๅฎๅก”๏ผˆ็ป“ๆž„ๅŒ–ๆ•ฐๆฎ๏ผ‰
104
+ FOOD_PAGODA = {
105
+ "ๅค‡ๅญ•": {
106
+ "ๅฅถ็ฑป": "300g",
107
+ "้ฑผ็ฆฝ่›‹่‚‰็ฑป": "150g",
108
+ "่ฐท็ฑป": "200-250g",
109
+ "่”ฌ่œ": "400-500g",
110
+ "ๆฐดๆžœ": "200-300g",
111
+ "่–ฏ็ฑป": "75g",
112
+ "ๅคง่ฑ†": "20g",
113
+ "ๅšๆžœ": "10g",
114
+ "ๆฒน": "25g",
115
+ "็›": "5g",
116
+ },
117
+ "ๅญ•ไธญๆœŸ": {
118
+ "ๅฅถ็ฑป": "300-500g",
119
+ "้ฑผ็ฆฝ่›‹่‚‰็ฑป": "150-200g",
120
+ "่ฐท็ฑป": "200-250g",
121
+ "่”ฌ่œ": "400-500g",
122
+ "ๆฐดๆžœ": "200-300g",
123
+ "่–ฏ็ฑป": "75g",
124
+ "ๅคง่ฑ†": "20g",
125
+ "ๅšๆžœ": "10g",
126
+ "ๆฒน": "25g",
127
+ "็›": "5g",
128
+ },
129
+ "ๅญ•ๆ™šๆœŸ": {
130
+ "ๅฅถ็ฑป": "300-500g",
131
+ "้ฑผ็ฆฝ่›‹่‚‰็ฑป": "175-225g",
132
+ "่ฐท็ฑป": "225-275g",
133
+ "่”ฌ่œ": "400-500g",
134
+ "ๆฐดๆžœ": "200-350g",
135
+ "่–ฏ๏ฟฝ๏ฟฝ": "75g",
136
+ "ๅคง่ฑ†": "20g",
137
+ "ๅšๆžœ": "10g",
138
+ "ๆฒน": "25g",
139
+ "็›": "5g",
140
+ },
141
+ "ๅ“บไนณๆœŸ": {
142
+ "ๅฅถ็ฑป": "300-500g",
143
+ "้ฑผ็ฆฝ่›‹่‚‰็ฑป": "200-250g",
144
+ "่ฐท็ฑป": "250-300g",
145
+ "่”ฌ่œ": "400-500g",
146
+ "ๆฐดๆžœ": "200-350g",
147
+ "่–ฏ็ฑป": "75g",
148
+ "ๅคง่ฑ†": "25g",
149
+ "ๅšๆžœ": "10g",
150
+ "ๆฒน": "25g",
151
+ "็›": "5g",
152
+ },
153
+ }
154
+
155
+ CORE_PRINCIPLES = [
156
+ "1. ่ฐƒๆ•ดๅญ•ๅ‰ไฝ“้‡่‡ณๆญฃๅธธ่Œƒๅ›ด",
157
+ "2. ๅธธๅƒๅซ้“้ฃŸ็‰ฉ๏ผŒ้€‰็”จ็ข˜็›๏ผŒ่กฅๅ……ๅถ้…ธๅ’Œ็ปด็”Ÿ็ด D",
158
+ "3. ๅญ•ๅไธฅ้‡่€…ๅฐ‘้‡ๅคš้ค",
159
+ "4. ๅญ•ไธญๆ™šๆœŸๅขžๅŠ ๅฅถใ€้ฑผใ€็ฆฝใ€่›‹ใ€็˜ฆ่‚‰",
160
+ "5. ็ปๅธธๆˆทๅค–ๆดปๅŠจ๏ผŒ็ฆ็ƒŸ้…’",
161
+ "6. ๆ„‰ๅฟซๅญ•่‚ฒๆ–ฐ็”Ÿๅ‘ฝ๏ผŒ็งฏๆžๅ‡†ๅค‡ๆฏไนณๅ–‚ๅ…ป",
162
+ ]
163
+
164
+ @classmethod
165
+ def load(cls) -> dict:
166
+ """่ฏปๅ– md ๆ–‡ไปถ๏ผŒ่ฟ”ๅ›ž็ป“ๆž„ๅŒ–ๆ•ฐๆฎ๏ผˆๅ…ผๅฎนๆŽฅๅฃ๏ผ‰"""
167
+ return {"food_pagoda": cls.FOOD_PAGODA, "core_principles": cls.CORE_PRINCIPLES}
168
+
169
+ @classmethod
170
+ def get_recommendations(cls, trimester: str) -> dict:
171
+ """่ฟ”ๅ›žๆŒ‡ๅฎšๅญ•ๆœŸ็š„้ฃŸ็‰ฉๆŽจ่้‡"""
172
+ return cls.FOOD_PAGODA.get(trimester, cls.FOOD_PAGODA["ๅญ•ไธญๆœŸ"])
173
+
174
+ @classmethod
175
+ def get_core_principles(cls) -> list[str]:
176
+ """่ฟ”ๅ›žๅ…ญๆกๆ ธๅฟƒๅปบ่ฎฎ"""
177
+ return cls.CORE_PRINCIPLES
178
+
179
+ @classmethod
180
+ def format_for_prompt(cls, trimester: str) -> str:
181
+ """ๆ ผๅผๅŒ–ไธบ system prompt ๅฏ็”จ็š„ๆ–‡ๆœฌ"""
182
+ recs = cls.get_recommendations(trimester)
183
+ lines = [f"ใ€{trimester}ๅนณ่กก่†ณ้ฃŸๅฎๅก”ๆŽจ่้‡ใ€‘"]
184
+ for food, amount in recs.items():
185
+ lines.append(f" {food}: {amount}")
186
+ lines.append("")
187
+ lines.append("ใ€่†ณ้ฃŸๆŒ‡ๅ—ๅ…ญๆกๆ ธๅฟƒๅปบ่ฎฎใ€‘")
188
+ for p in cls.CORE_PRINCIPLES:
189
+ lines.append(f" {p}")
190
+ return "\n".join(lines)
191
+
192
+
193
+ # ============================================================
194
+ # 3. DRIs ่งฃๆžๅ™จ
195
+ # ============================================================
196
+ class DRIsParser:
197
+ """่งฃๆž่†ณ้ฃŸ่ฅๅ…ป็ด ๅ‚่€ƒๆ‘„ๅ…ฅ้‡๏ผŒๆไพ› RNI ๆŸฅ่ฏขๅ’Œๅฏนๆฏ”"""
198
+
199
+ # ๅ…ณ้”ฎ่ฅๅ…ป็ด  RNI ๆ•ฐๆฎ๏ผˆๆฅ่‡ชๅฎ˜ๆ–น DRIs ่กจ15-18๏ผ‰
200
+ # ๅ•ไฝ๏ผš่ƒฝ้‡(MJ)ใ€่›‹็™ฝ่ดจ(g)ใ€้’™(mg)ใ€้“(mg)ใ€้”Œ(mg)ใ€
201
+ # ็ปด็”Ÿ็ด A(ฮผg RAE)ใ€็ปด็”Ÿ็ด D(ฮผg)ใ€็ปด็”Ÿ็ด E(mg ฮฑ-TE)ใ€
202
+ # ็ปด็”Ÿ็ด B1(mg)ใ€็ปด็”Ÿ็ด B2(mg)ใ€ๅถ้…ธ(ฮผg DFE)ใ€็ข˜(ฮผg)
203
+ RNI_DATA = {
204
+ "ๅญ•ๆ—ฉๆœŸ": {
205
+ "่ƒฝ้‡(MJ)": 8.81, "่›‹็™ฝ่ดจ(g)": 65, "้’™(mg)": 800,
206
+ "้“(mg)": 20, "้”Œ(mg)": 9.5, "็ปด็”Ÿ็ด A(ฮผg RAE)": 770,
207
+ "็ปด็”Ÿ็ด D(ฮผg)": 10, "็ปด็”Ÿ็ด E(mg ฮฑ-TE)": 14,
208
+ "็ปด็”Ÿ็ด B1(mg)": 1.2, "็ปด็”Ÿ็ด B2(mg)": 1.2,
209
+ "ๅถ้…ธ(ฮผg DFE)": 600, "็ข˜(ฮผg)": 230,
210
+ },
211
+ "ๅญ•ไธญๆœŸ": {
212
+ "่ƒฝ้‡(MJ)": 9.84, "่›‹็™ฝ่ดจ(g)": 70, "้’™(mg)": 800,
213
+ "้“(mg)": 25, "้”Œ(mg)": 11, "็ปด็”Ÿ็ด A(ฮผg RAE)": 770,
214
+ "็ปด็”Ÿ็ด D(ฮผg)": 10, "็ปด็”Ÿ็ด E(mg ฮฑ-TE)": 14,
215
+ "็ปด็”Ÿ็ด B1(mg)": 1.4, "็ปด็”Ÿ็ด B2(mg)": 1.4,
216
+ "ๅถ้…ธ(ฮผg DFE)": 600, "็ข˜(ฮผg)": 230,
217
+ },
218
+ "ๅญ•ๆ™šๆœŸ": {
219
+ "่ƒฝ้‡(MJ)": 9.84, "่›‹็™ฝ่ดจ(g)": 85, "้’™(mg)": 800,
220
+ "้“(mg)": 29, "้”Œ(mg)": 11, "็ปด็”Ÿ็ด A(ฮผg RAE)": 770,
221
+ "็ปด็”Ÿ็ด D(ฮผg)": 10, "็ปด็”Ÿ็ด E(mg ฮฑ-TE)": 14,
222
+ "็ปด็”Ÿ็ด B1(mg)": 1.4, "็ปด็”Ÿ็ด B2(mg)": 1.4,
223
+ "ๅถ้…ธ(ฮผg DFE)": 600, "็ข˜(ฮผg)": 230,
224
+ },
225
+ "ๅ“บไนณๆœŸ": {
226
+ "่ƒฝ้‡(MJ)": 10.46, "่›‹็™ฝ่ดจ(g)": 80, "้’™(mg)": 1000,
227
+ "้“(mg)": 24, "้”Œ(mg)": 13.5, "็ปด็”Ÿ็ด A(ฮผg RAE)": 1300,
228
+ "็ปด็”Ÿ็ด D(ฮผg)": 10, "็ปด็”Ÿ็ด E(mg ฮฑ-TE)": 17,
229
+ "็ปด็”Ÿ็ด B1(mg)": 1.5, "็ปด็”Ÿ็ด B2(mg)": 1.5,
230
+ "ๅถ้…ธ(ฮผg DFE)": 550, "็ข˜(ฮผg)": 240,
231
+ },
232
+ }
233
+
234
+ # ่ฅๅ…ป็ด ๅˆ†็ฑป๏ผˆ็”จไบŽ็”Ÿๆˆๅปบ่ฎฎ๏ผ‰
235
+ NUTRIENT_CATEGORIES = {
236
+ "่ƒฝ้‡(MJ)": "ๅฎ้‡่ฅๅ…ป็ด ", "่›‹็™ฝ่ดจ(g)": "ๅฎ้‡่ฅๅ…ป็ด ",
237
+ "้’™(mg)": "็Ÿฟ็‰ฉ่ดจ", "้“(mg)": "็Ÿฟ็‰ฉ่ดจ", "้”Œ(mg)": "็Ÿฟ็‰ฉ่ดจ",
238
+ "็ปด็”Ÿ็ด A(ฮผg RAE)": "็ปด็”Ÿ็ด ", "็ปด็”Ÿ็ด D(ฮผg)": "็ปด็”Ÿ็ด ",
239
+ "็ปด็”Ÿ็ด E(mg ฮฑ-TE)": "็ปด็”Ÿ็ด ", "็ปด็”Ÿ็ด B1(mg)": "็ปด็”Ÿ็ด ",
240
+ "็ปด็”Ÿ็ด B2(mg)": "็ปด็”Ÿ็ด ", "ๅถ้…ธ(ฮผg DFE)": "็ปด็”Ÿ็ด ",
241
+ "็ข˜(ฮผg)": "็Ÿฟ็‰ฉ่ดจ",
242
+ }
243
+
244
+ # ๅฏŒๅซๅ„่ฅๅ…ป็ด ็š„้ฃŸ็‰ฉ๏ผˆ็”จไบŽ็”Ÿๆˆๅปบ่ฎฎ๏ผ‰
245
+ RICH_FOODS = {
246
+ "้’™(mg)": ["็‰›ๅฅถ", "้…ธๅฅถ", "่ฑ†่…", "่Š้บป", "ๅฐ้ฑผๅนฒ", "่ฅฟๅ…ฐ่Šฑ"],
247
+ "้“(mg)": ["็บข่‚‰", "ๅŠจ็‰ฉ่‚่„", "่ ่œ", "้ป‘ๆœจ่€ณ", "็บขๆžฃ", "็˜ฆ่‚‰"],
248
+ "ๅถ้…ธ(ฮผg DFE)": ["่ ่œ", "่ฅฟๅ…ฐ่Šฑ", "่Šฆ็ฌ‹", "็‰›่‚", "่ฑ†็ฑป", "ๆฉ™ๅญ"],
249
+ "่›‹็™ฝ่ดจ(g)": ["้ธก่›‹", "้ธก่‚‰", "้ฑผ่‚‰", "่ฑ†่…", "็‰›ๅฅถ", "่™พ"],
250
+ "็ปด็”Ÿ็ด D(ฮผg)": ["่›‹้ป„", "่‚่„", "ไธ‰ๆ–‡้ฑผ", "่˜‘่‡", "ๆ™’ๅคช้˜ณ"],
251
+ "้”Œ(mg)": ["็‰ก่›Ž", "็˜ฆ่‚‰", "ๅšๆžœ", "ๅ…จ่ฐท็‰ฉ", "่ฑ†็ฑป"],
252
+ "็ข˜(ฮผg)": ["ๆตทๅธฆ", "๏ฟฝ๏ฟฝ่œ", "็ข˜็›", "ๆตท้ฑผ", "่ด็ฑป"],
253
+ "็ปด็”Ÿ็ด A(ฮผg RAE)": ["่ƒก่ๅœ", "ๅ—็“œ", "่ ่œ", "่‚่„", "็บข่–ฏ"],
254
+ "็ปด็”Ÿ็ด B1(mg)": ["ๅ…จ่ฐท็‰ฉ", "็˜ฆ่‚‰", "่ฑ†็ฑป", "ๅšๆžœ"],
255
+ "็ปด็”Ÿ็ด B2(mg)": ["ๅฅถๅˆถๅ“", "้ธก่›‹", "็˜ฆ่‚‰", "็ปฟๅถ่”ฌ่œ"],
256
+ "็ปด็”Ÿ็ด E(mg ฮฑ-TE)": ["ๅšๆžœ", "ๆค็‰ฉๆฒน", "ๅ…จ่ฐท็‰ฉ", "็ปฟๅถ่”ฌ่œ"],
257
+ "่ƒฝ้‡(MJ)": ["ไธป้ฃŸ", "่‚‰็ฑป", "ๅšๆžœ", "ๆค็‰ฉๆฒน"],
258
+ }
259
+
260
+ @classmethod
261
+ def load(cls) -> dict:
262
+ """่ฏปๅ– md ๆ–‡ไปถ๏ผŒ่ฟ”ๅ›ž็ป“ๆž„ๅŒ–ๆ•ฐๆฎ๏ผˆๅ…ผๅฎนๆŽฅๅฃ๏ผ‰"""
263
+ return {"rni_data": cls.RNI_DATA}
264
+
265
+ @classmethod
266
+ def get_rni(cls, stage: str) -> dict:
267
+ """่ฟ”ๅ›žๆŒ‡ๅฎš้˜ถๆฎต็š„ RNI ๆ•ฐๆฎ"""
268
+ return cls.RNI_DATA.get(stage, cls.RNI_DATA["ๅญ•ไธญๆœŸ"])
269
+
270
+ @classmethod
271
+ def get_stages(cls) -> list[str]:
272
+ """่ฟ”ๅ›žๆ‰€ๆœ‰้˜ถๆฎตๅ็งฐ"""
273
+ return list(cls.RNI_DATA.keys())
274
+
275
+ @classmethod
276
+ def compare_with_intake(cls, stage: str, intake: dict) -> dict:
277
+ """
278
+ ๅฏนๆฏ”ๅฎž้™…ๆ‘„ๅ…ฅไธŽ RNI๏ผŒ่ฟ”ๅ›žๅทฎๅผ‚ๅˆ†ๆž
279
+
280
+ Args:
281
+ stage: ๅญ•ๆœŸ้˜ถๆฎต
282
+ intake: ๅฎž้™…ๆ‘„ๅ…ฅ้‡ๅญ—ๅ…ธ {่ฅๅ…ป็ด ๅ: ๆ•ฐๅ€ผ}
283
+
284
+ Returns:
285
+ {
286
+ "stage": stage,
287
+ "comparisons": [{nutrient, rni, intake, diff_pct, status}, ...],
288
+ "focus_nutrients": [...], # ๅทฎๅผ‚่ถ…่ฟ‡20%็š„้‡็‚นๅ…ณๆณจ
289
+ "summary": "่‡ช็„ถ่ฏญ่จ€ๆ€ป็ป“"
290
+ }
291
+ """
292
+ rni = cls.get_rni(stage)
293
+ comparisons = []
294
+ focus_nutrients = []
295
+
296
+ for nutrient, rni_value in rni.items():
297
+ actual = intake.get(nutrient, 0)
298
+ if actual == 0:
299
+ diff_pct = -100
300
+ status = "missing"
301
+ else:
302
+ diff_pct = round((actual - rni_value) / rni_value * 100, 1)
303
+ if diff_pct >= 0:
304
+ status = "sufficient"
305
+ elif diff_pct >= -20:
306
+ status = "slight_deficit"
307
+ else:
308
+ status = "deficit"
309
+
310
+ comparisons.append({
311
+ "nutrient": nutrient,
312
+ "category": cls.NUTRIENT_CATEGORIES.get(nutrient, "ๅ…ถไป–"),
313
+ "rni": rni_value,
314
+ "intake": actual,
315
+ "diff_pct": diff_pct,
316
+ "status": status,
317
+ })
318
+
319
+ if status in ("deficit", "missing"):
320
+ focus_nutrients.append(nutrient)
321
+
322
+ # ็”Ÿๆˆๆ€ป็ป“
323
+ summary_lines = []
324
+ if focus_nutrients:
325
+ summary_lines.append(f"โš ๏ธ ไปฅไธ‹่ฅๅ…ป็ด ๆ‘„ๅ…ฅไธ่ถณ๏ผˆๅทฎๅผ‚่ถ…่ฟ‡20%๏ผ‰๏ผš")
326
+ for n in focus_nutrients[:5]:
327
+ foods = cls.RICH_FOODS.get(n, [])
328
+ food_str = "ใ€".join(foods[:4]) if foods else "ๅคšๆ ทๅŒ–้ฅฎ้ฃŸ"
329
+ summary_lines.append(f" โ€ข {n}๏ผšๅปบ่ฎฎๅคšๅƒ {food_str}")
330
+ else:
331
+ summary_lines.append("โœ… ๅ„่ฅๅ…ป็ด ๆ‘„ๅ…ฅๅŸบๆœฌ่พพๆ ‡๏ผ")
332
+
333
+ return {
334
+ "stage": stage,
335
+ "comparisons": comparisons,
336
+ "focus_nutrients": focus_nutrients,
337
+ "summary": "\n".join(summary_lines),
338
+ }
339
+
340
+ @classmethod
341
+ def format_comparison_table(cls, comparisons: list[dict], max_rows: int = 8) -> str:
342
+ """ๆ ผๅผๅŒ–ไธบๆ–‡ๆœฌๅฏนๆฏ”่กจ"""
343
+ lines = [
344
+ "โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”",
345
+ "โ”‚ ่ฅๅ…ป็ด  RNI ๅฎž้™…ๆ‘„ๅ…ฅ ๅทฎๅผ‚ โ”‚",
346
+ "โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค",
347
+ ]
348
+ for c in comparisons[:max_rows]:
349
+ status_icon = "โœ…" if c["status"] == "sufficient" else ("โš ๏ธ" if c["status"] == "slight_deficit" else "โŒ")
350
+ diff_str = f"{c['diff_pct']:+.1f}%" if c["status"] != "missing" else "ๆ— ๆ•ฐๆฎ"
351
+ lines.append(
352
+ f"โ”‚ {status_icon} {c['nutrient']:<14s} {c['rni']:<8.1f} {c['intake']:<12.1f} {diff_str:<12s} โ”‚"
353
+ )
354
+ lines.append("โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜")
355
+ return "\n".join(lines)
356
+
357
+
358
+ # ============================================================
359
+ # 4. ็ปŸไธ€ๅŠ ่ฝฝๆŽฅๅฃ
360
+ # ============================================================
361
+ def load_all_standards() -> dict:
362
+ """ๅŠ ่ฝฝๆ‰€ๆœ‰่ฅๅ…ปๆ ‡ๅ‡†๏ผŒ่ฟ”ๅ›ž็ป“ๆž„ๅŒ–ๆ•ฐๆฎ"""
363
+ return {
364
+ "weight": WeightStandardParser.load(),
365
+ "dietary_guide": DietaryGuideParser.load(),
366
+ "dris": DRIsParser.load(),
367
+ }
368
+
369
+
370
+ def compile_standards_to_presets():
371
+ """ๅฐ†่ฅๅ…ปๆ ‡ๅ‡†็ผ–่ฏ‘ไธบ JSON ็ผ“ๅญ˜ๆ–‡ไปถ"""
372
+ PRESETS_DIR.mkdir(parents=True, exist_ok=True)
373
+ data = load_all_standards()
374
+ cache_path = PRESETS_DIR / "nutrition_standards.json"
375
+ with open(cache_path, 'w', encoding='utf-8') as f:
376
+ json.dump(data, f, ensure_ascii=False, indent=2)
377
+ return cache_path
plugins/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ """
2
+ PregoPal - Loop ๆ’ไปถๅŒ…
3
+ ======================
4
+ ๆ‰€ๆœ‰ๆ’ไปถ็ปงๆ‰ฟ base.LoopPlugin๏ผŒๆณจๅ†ŒๅˆฐไธๅŒ LoopStageใ€‚
5
+ """
plugins/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (303 Bytes). View file
 
plugins/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (286 Bytes). View file
 
plugins/__pycache__/base.cpython-311.pyc ADDED
Binary file (5.42 kB). View file
 
plugins/__pycache__/base.cpython-313.pyc ADDED
Binary file (4.53 kB). View file
 
plugins/__pycache__/briefing_generator.cpython-311.pyc ADDED
Binary file (5.01 kB). View file
 
plugins/__pycache__/briefing_generator.cpython-313.pyc ADDED
Binary file (4.58 kB). View file
 
plugins/__pycache__/diet_summary.cpython-311.pyc ADDED
Binary file (3.35 kB). View file
 
plugins/__pycache__/diet_summary.cpython-313.pyc ADDED
Binary file (3.08 kB). View file
 
plugins/__pycache__/dri_analysis.cpython-311.pyc ADDED
Binary file (3.21 kB). View file
 
plugins/__pycache__/dri_analysis.cpython-313.pyc ADDED
Binary file (2.98 kB). View file
 
plugins/__pycache__/family_memory.cpython-311.pyc ADDED
Binary file (2.27 kB). View file
 
plugins/__pycache__/family_memory.cpython-313.pyc ADDED
Binary file (2.04 kB). View file
 
plugins/__pycache__/family_quiz.cpython-311.pyc ADDED
Binary file (3.95 kB). View file
 
plugins/__pycache__/family_quiz.cpython-313.pyc ADDED
Binary file (3.69 kB). View file
 
plugins/__pycache__/preset_writer.cpython-311.pyc ADDED
Binary file (3.83 kB). View file
 
plugins/__pycache__/preset_writer.cpython-313.pyc ADDED
Binary file (3.51 kB). View file
 
plugins/__pycache__/three_day_summary.cpython-311.pyc ADDED
Binary file (5.7 kB). View file
 
plugins/__pycache__/three_day_summary.cpython-313.pyc ADDED
Binary file (5.11 kB). View file
 
plugins/__pycache__/weight_check.cpython-311.pyc ADDED
Binary file (2.23 kB). View file
 
plugins/__pycache__/weight_check.cpython-313.pyc ADDED
Binary file (2.06 kB). View file