health_plan.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. from pydantic import BaseModel
  2. from typing import Literal, Optional, List, Dict, Any
  3. class HealthPlanGenerateRequest(BaseModel):
  4. member_ids: Optional[str] = None
  5. dimensions: Optional[str] = None
  6. goal: str = ""
  7. family_id: Optional[int] = None
  8. class PlanTask(BaseModel):
  9. action_type: Literal["buy", "read", "exercise", "checkin", "diet", "activity"]
  10. title: str
  11. dimension: Literal["body", "mind", "wisdom", "action", "wealth"]
  12. frequency: Literal["once", "daily"] = "daily"
  13. notes: Optional[str] = None
  14. class HealthPlanSection(BaseModel):
  15. key: str # "nutrition" | "diet" | "exercise"
  16. title: str
  17. content: str # markdown text
  18. items: List[dict] = [] # structured items for UI rendering
  19. tasks: List[PlanTask] = [] # machine-readable task intents
  20. class HealthPlanResponse(BaseModel):
  21. """单成员方案 / 兼容旧结构(扁平 sections)。
  22. 多成员(common+individual)请使用 MultiMemberPlanResponse。
  23. 本类保留以向后兼容单人方案路径(len(member_ids) <= 1)。
  24. """
  25. overview: str = ""
  26. sections: List[HealthPlanSection] = []
  27. abnormal_indicators: List[dict] = []
  28. knowledge_sources: List[dict] = []
  29. class PlanPart(BaseModel):
  30. """方案的一个逻辑部分:可承载共性(common)或个性(individual)。"""
  31. overview: str = ""
  32. sections: List[HealthPlanSection] = []
  33. abnormal_indicators: List[dict] = []
  34. knowledge_sources: List[dict] = []
  35. class MultiMemberPlanResponse(BaseModel):
  36. """多人方案:共性 + 各成员个性。
  37. - common: 适用于全体成员的共性方案部分
  38. - individual: 按 member_id 分组的个性方案部分
  39. """
  40. common: PlanPart = PlanPart()
  41. individual: Dict[str, PlanPart] = {}
  42. def build_rendered_content(self, member_names: Dict[str, str]) -> str:
  43. """把 common+individual 组合渲染为 Markdown 文本(供 planContent 使用)。
  44. member_names: {memberId: 成员名},用于在标题里标注个性部分归属。
  45. """
  46. out: List[str] = []
  47. out.append("# 健康方案\n\n")
  48. common = self.common
  49. out.append("## 共性方案\n")
  50. if common.overview:
  51. out.append("### 方案概述\n\n" + common.overview + "\n\n")
  52. for sec in common.sections:
  53. out.append(f"## {sec.title}\n\n{sec.content}\n\n")
  54. if common.abnormal_indicators:
  55. out.append("## 共性异常指标\n")
  56. for ind in common.abnormal_indicators:
  57. out.append(f"- {ind.get('member','?')} - {ind.get('indicator','')}: {ind.get('value','')} {ind.get('unit','')}")
  58. if self.individual:
  59. out.append("\n---\n\n# 个性方案\n")
  60. for mid, part in self.individual.items():
  61. name = member_names.get(mid, f"成员{mid}")
  62. out.append(f"\n## {name} 个性方案\n")
  63. if part.overview:
  64. out.append("### 概述\n\n" + part.overview + "\n")
  65. for sec in part.sections:
  66. out.append(f"### {sec.title}\n\n{sec.content}\n")
  67. if part.abnormal_indicators:
  68. out.append("### 异常指标\n")
  69. for ind in part.abnormal_indicators:
  70. out.append(f"- {ind.get('member','?')} - {ind.get('indicator','')}: {ind.get('value','')} {ind.get('unit','')}")
  71. return "".join(out)