PregoPal / modules /diet_logger.py
J.B-Lin
CLine 界面初版
0f2d3d7
Raw
History Blame Contribute Delete
5.38 kB
"""
PregoPal - 饮食记录模块
========================
记录孕妇的饮食习惯,同时保存为 JSON(结构化)+ Markdown(可读)。
数据流向:
MiniCPM-o 回复 (含 [DIET_RECORD] 标记) → 正则解析 → JSON + Markdown
当前:手动表单输入
后续:AI 对话中自动提取 [DIET_RECORD] 标记
"""
import json
import datetime
import hashlib
import re
from pathlib import Path
from config import DIET_LOG_FILE, LOGS_DIR, DIET_LOG_SCHEMA_VERSION
class DietLogger:
"""记录孕妇的饮食习惯并保存为 Markdown"""
def __init__(self):
self.log_file = DIET_LOG_FILE
self.logs = self._load_logs()
def _load_logs(self):
"""加载饮食记录"""
if self.log_file.exists():
with open(self.log_file, 'r', encoding='utf-8') as f:
return json.load(f)
return {"schema_version": DIET_LOG_SCHEMA_VERSION, "records": []}
def _save_logs(self):
"""保存饮食记录"""
with open(self.log_file, 'w', encoding='utf-8') as f:
json.dump(self.logs, f, ensure_ascii=False, indent=2)
def add_record(self, member_name: str, member_relation: str, date: str,
meals: dict, mood: str = "", notes: str = ""):
"""添加一条饮食记录"""
record = {
"id": hashlib.md5(f"{date}_{member_name}_{datetime.datetime.now()}".encode()).hexdigest()[:8],
"member_name": member_name,
"member_relation": member_relation,
"date": date,
"meals": meals,
"mood": mood,
"notes": notes,
"extensions": {}, # 预留扩展字段
"created_at": datetime.datetime.now().isoformat()
}
self.logs["records"].append(record)
self._save_logs()
# 同时生成 Markdown 文件
md_path = self._generate_markdown(record)
return record, md_path
def _generate_markdown(self, record: dict) -> Path:
"""生成 Markdown 格式的饮食日志"""
date_str = record["date"]
md_filename = LOGS_DIR / f"饮食日志_{date_str}.md"
content = f"""# 🥗 孕期饮食日志
## 📋 基本信息
- **日期**: {date_str}
- **记录人**: {record['member_relation']} - {record['member_name']}
- **记录时间**: {record['created_at'][:19]}
## 🍽️ 今日饮食记录
"""
for meal_time, food in record["meals"].items():
content += f"### {meal_time}\n- {food}\n\n"
if record["mood"]:
content += f"## 😊 今日心情\n{record['mood']}\n\n"
if record["notes"]:
content += f"## 📝 备注\n{record['notes']}\n\n"
content += """---
*由 PregoPal 自动生成*
"""
with open(md_filename, 'w', encoding='utf-8') as f:
f.write(content)
return md_filename
def get_recent_records(self, days: int = 7) -> list:
"""获取最近几天的记录"""
today = datetime.date.today()
cutoff = today - datetime.timedelta(days=days)
recent = []
for r in self.logs["records"]:
try:
record_date = datetime.date.fromisoformat(r["date"])
if record_date >= cutoff:
recent.append(r)
except ValueError:
continue
return sorted(recent, key=lambda x: x["date"], reverse=True)
def get_all_markdown_files(self) -> list:
"""获取所有 Markdown 日志文件"""
return sorted(LOGS_DIR.glob("*.md"), reverse=True)
# ============================================================
# [DIET_RECORD] 标记解析(后续 AI 版本使用)
# ============================================================
@staticmethod
def parse_diet_record(text: str) -> dict | None:
"""
从 AI 回复中解析 [DIET_RECORD] 标记
Args:
text: AI 模型的回复文本
Returns:
解析出的饮食记录字典,或 None(未找到标记)
示例输入:
[DIET_RECORD]
日期: 2026-06-07
早餐: 全麦面包+鸡蛋+牛奶
午餐: 清蒸鱼+糙米饭+炒时蔬
晚餐:
加餐: 酸奶+坚果
心情: 挺好
备注:
[/DIET_RECORD]
"""
pattern = r'\[DIET_RECORD\](.*?)\[/DIET_RECORD\]'
match = re.search(pattern, text, re.DOTALL)
if not match:
return None
content = match.group(1).strip()
record = {"meals": {}, "mood": "", "notes": ""}
for line in content.split('\n'):
line = line.strip()
if not line:
continue
if ':' in line:
key, value = line.split(':', 1)
key = key.strip()
value = value.strip()
if key == '日期':
record['date'] = value
elif key == '心情':
record['mood'] = value
elif key == '备注':
record['notes'] = value
elif key in ['早餐', '午餐', '晚餐', '加餐']:
if value: # 只记录非空值
record['meals'][key] = value
return record if record['meals'] else None