| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- from app.models.health_plan import PlanTask, HealthPlanSection, HealthPlanResponse
- from app.api.adapter import _parse_plan_response, _fallback_extract_tasks
- 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]
- def test_parse_plan_response_valid():
- answer = '{"overview":"o","sections":[{"key":"diet","title":"t","content":"c","items":[],"tasks":[{"action_type":"diet","title":"少油少盐","dimension":"body","frequency":"daily"}]}],"abnormal_indicators":[]}'
- res = _parse_plan_response(answer)
- assert res["success"] is True
- assert res["data"]["sections"][0]["tasks"][0]["action_type"] == "diet"
- def test_parse_plan_response_invalid_action_falls_back():
- # LLM 输出含非法 action_type("cook"),校验失败但可被 fallback 处理
- answer = '{"overview":"o","sections":[{"key":"diet","title":"t","content":"1. 少油少盐\\n2. 多吃蔬菜\\n3. 纯原理描述无动作","items":[],"tasks":[{"action_type":"cook","title":"做饭","dimension":"body"}]}],"abnormal_indicators":[]}'
- res = _parse_plan_response(answer)
- # fallback 从 content 提取动作行
- assert res["success"] is True
- tasks = res["data"]["sections"][0].get("tasks", [])
- assert len(tasks) >= 2
- def test_parse_plan_response_no_json():
- res = _parse_plan_response("这是纯文本没有 JSON")
- assert res["success"] is False
- def test_fallback_skips_when_tasks_exist():
- parsed = {"sections": [{"key": "diet", "title": "t", "content": "1. 少油少盐", "tasks": [{"action_type": "diet", "title": "已有", "dimension": "body"}]}]}
- assert _fallback_extract_tasks(parsed) is None
- def test_regenerate_tasks_validation_filter():
- raw_tasks = [
- {"action_type": "diet", "title": "少油少盐", "dimension": "body", "frequency": "daily"},
- {"action_type": "cook", "title": "非法", "dimension": "body"}, # 非法 action,应被丢弃
- ]
- valid = []
- for t in raw_tasks:
- try:
- valid.append(PlanTask.model_validate(t).model_dump())
- except Exception:
- continue
- assert len(valid) == 1
- assert valid[0]["action_type"] == "diet"
|