Browse Source

feat(langgraph): 健康方案 tasks 模型(PlanTask + section.tasks)

iwt 3 weeks ago
parent
commit
fa81258582
2 changed files with 51 additions and 2 deletions
  1. 11 2
      cfc-langgraph/app/models/health_plan.py
  2. 40 0
      cfc-langgraph/tests/test_health_plan.py

+ 11 - 2
cfc-langgraph/app/models/health_plan.py

@@ -1,5 +1,5 @@
 from pydantic import BaseModel
-from typing import Optional, List
+from typing import Literal, Optional, List
 
 
 class HealthPlanGenerateRequest(BaseModel):
@@ -9,15 +9,24 @@ class HealthPlanGenerateRequest(BaseModel):
     family_id: Optional[int] = None
 
 
+class PlanTask(BaseModel):
+    action_type: Literal["buy", "read", "exercise", "checkin", "diet", "activity"]
+    title: str
+    dimension: Literal["body", "mind", "wisdom", "action", "wealth"]
+    frequency: Literal["once", "daily"] = "daily"
+    notes: Optional[str] = None
+
+
 class HealthPlanSection(BaseModel):
     key: str  # "nutrition" | "diet" | "exercise"
     title: str
     content: str  # markdown text
     items: List[dict] = []  # structured items for UI rendering
+    tasks: List[PlanTask] = []  # machine-readable task intents
 
 
 class HealthPlanResponse(BaseModel):
     overview: str = ""
     sections: List[HealthPlanSection] = []
     abnormal_indicators: List[dict] = []
-    knowledge_sources: List[dict] = []
+    knowledge_sources: List[dict] = []

+ 40 - 0
cfc-langgraph/tests/test_health_plan.py

@@ -0,0 +1,40 @@
+from app.models.health_plan import PlanTask, HealthPlanSection, HealthPlanResponse
+
+
+def test_plan_task_valid():
+    t = PlanTask(action_type="buy", title="购买维生素D3", dimension="wealth", frequency="once")
+    assert t.frequency == "once"
+    assert t.notes is None
+
+
+def test_plan_task_default_frequency_daily():
+    t = PlanTask(action_type="exercise", title="每周跑步3次", dimension="body")
+    assert t.frequency == "daily"
+
+
+def test_plan_task_invalid_action_type():
+    import pytest
+    from pydantic import ValidationError
+    with pytest.raises(ValidationError):
+        PlanTask(action_type="cook", title="做饭", dimension="body")
+
+
+def test_plan_task_invalid_dimension():
+    import pytest
+    from pydantic import ValidationError
+    with pytest.raises(ValidationError):
+        PlanTask(action_type="diet", title="少油少盐", dimension="earth")
+
+
+def test_plan_response_with_tasks():
+    resp = HealthPlanResponse(
+        overview="总览",
+        sections=[HealthPlanSection(
+            key="nutrition", title="营养补充", content="## 建议",
+            tasks=[PlanTask(action_type="buy", title="购买鱼油", dimension="wealth", frequency="once")]
+        )]
+    )
+    assert resp.sections[0].tasks[0].action_type == "buy"
+    # 序列化后 tasks 字段存在
+    data = resp.model_dump()
+    assert "tasks" in data["sections"][0]