diet_tools.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. """
  2. 饮食场景 Mock 工具:营养查询、运动/睡眠摘要(可替换为真实 API)。
  3. """
  4. from __future__ import annotations
  5. import json
  6. from typing import Any, Dict, List
  7. # 便利店/外卖常见高蛋白选项(演示用)
  8. _NUTRITION_MOCK: Dict[str, Dict[str, Any]] = {
  9. "鸡蛋": {"protein_g_per_unit": 6.0, "unit": "1个(约50g)", "kcal_per_unit": 70},
  10. "水煮蛋": {"protein_g_per_unit": 6.0, "unit": "1个", "kcal_per_unit": 70},
  11. "希腊酸奶": {"protein_g_per_unit": 12.0, "unit": "100g", "kcal_per_unit": 95},
  12. "酸奶": {"protein_g_per_unit": 4.0, "unit": "100g", "kcal_per_unit": 85},
  13. "牛奶": {"protein_g_per_unit": 3.3, "unit": "100ml", "kcal_per_unit": 60},
  14. "豆浆": {"protein_g_per_unit": 3.6, "unit": "100ml", "kcal_per_unit": 40},
  15. "即食鸡胸肉": {"protein_g_per_unit": 24.0, "unit": "100g", "kcal_per_unit": 120},
  16. "鸡腿肉": {"protein_g_per_unit": 20.0, "unit": "100g", "kcal_per_unit": 180},
  17. "金枪鱼罐头": {"protein_g_per_unit": 22.0, "unit": "100g", "kcal_per_unit": 110},
  18. "蛋白棒": {"protein_g_per_unit": 15.0, "unit": "1根(约40g)", "kcal_per_unit": 180},
  19. "豆腐": {"protein_g_per_unit": 8.0, "unit": "100g", "kcal_per_unit": 80},
  20. "豆干": {"protein_g_per_unit": 16.0, "unit": "100g", "kcal_per_unit": 140},
  21. }
  22. def nutrition_lookup(query: str) -> Dict[str, Any]:
  23. """
  24. 按关键词匹配 mock 营养表;支持多个关键词逗号分隔。
  25. """
  26. q = (query or "").strip()
  27. if not q:
  28. return {"matches": [], "hint": "请提供食物名称关键词"}
  29. keys = [k.strip() for k in q.replace(",", ",").split(",") if k.strip()]
  30. if not keys:
  31. keys = [q]
  32. matches: List[Dict[str, Any]] = []
  33. for kw in keys:
  34. for name, meta in _NUTRITION_MOCK.items():
  35. if kw in name or name in kw:
  36. matches.append({"name": name, **meta})
  37. # 直接命中
  38. if kw in _NUTRITION_MOCK and not any(m["name"] == kw for m in matches):
  39. matches.append({"name": kw, **_NUTRITION_MOCK[kw]})
  40. # 去重按 name
  41. seen = set()
  42. uniq: List[Dict[str, Any]] = []
  43. for m in matches:
  44. if m["name"] not in seen:
  45. seen.add(m["name"])
  46. uniq.append(m)
  47. return {
  48. "query": q,
  49. "matches": uniq[:20],
  50. "source": "mock_nutrition_db",
  51. }
  52. def activity_sleep_summary(user_id: str) -> Dict[str, Any]:
  53. """
  54. Mock:可穿戴/手填摘要。后续可改为读 user_profiles 或外部 API。
  55. """
  56. _ = user_id
  57. return {
  58. "user_id": user_id,
  59. "date": "今日",
  60. "steps": 8200,
  61. "sleep_hours": 6.5,
  62. "sleep_quality": "一般",
  63. "evening_workout": True,
  64. "workout_type": "力量训练",
  65. "notes": "mock:连续感知数据可接手环/OpenAPI",
  66. "source": "mock_wearable",
  67. }
  68. def tools_spec() -> str:
  69. return json.dumps(
  70. [
  71. {
  72. "name": "nutrition_lookup",
  73. "description": "查询常见便利店/外卖食物蛋白质含量与份量单位",
  74. "parameters": {"query": "关键词,多个用英文逗号分隔"},
  75. },
  76. {
  77. "name": "activity_sleep_summary",
  78. "description": "获取用户今日步数、睡眠与晚间是否安排训练等摘要",
  79. "parameters": {"user_id": "用户 ID"},
  80. },
  81. ],
  82. ensure_ascii=False,
  83. indent=2,
  84. )
  85. def dispatch_tool(name: str, action_input: Dict[str, Any], user_id: str) -> Dict[str, Any]:
  86. if name == "nutrition_lookup":
  87. return nutrition_lookup(str(action_input.get("query", "")))
  88. if name == "activity_sleep_summary":
  89. uid = str(action_input.get("user_id") or user_id)
  90. return activity_sleep_summary(uid)
  91. return {"error": f"未知工具: {name}"}