multimodal_agent.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import httpx
  2. from typing import Optional
  3. from app.config import settings
  4. import logging
  5. logger = logging.getLogger(__name__)
  6. class TongueDiagnosisAgent:
  7. """舌诊分析 Agent
  8. 当前实现: 代理到 Dify Workflow (多模态最成熟)
  9. 后续可替换: 直接调用多模态 LLM API
  10. """
  11. def __init__(self):
  12. self.dify_base = settings.dify_base_url or ""
  13. self.dify_api_key = settings.dify_tongue_api_key or ""
  14. async def diagnose(
  15. self,
  16. image_url: str,
  17. user_id: int,
  18. additional_context: Optional[dict] = None,
  19. ) -> dict:
  20. """舌诊分析: 调用 Dify Workflow 或直接 LLM"""
  21. if self.dify_base and self.dify_api_key:
  22. return await self._via_dify(image_url, user_id, additional_context)
  23. else:
  24. return await self._via_llm(image_url)
  25. async def _via_dify(
  26. self, image_url: str, user_id: int, context: Optional[dict]
  27. ) -> dict:
  28. """通过 Dify Workflow 执行舌诊"""
  29. url = f"{self.dify_base}/workflows/run"
  30. headers = {
  31. "Authorization": f"Bearer {self.dify_api_key}",
  32. "Content-Type": "application/json",
  33. }
  34. inputs = {"tongue_image": {"type": "image", "url": image_url}}
  35. if context:
  36. inputs.update(context)
  37. body = {
  38. "inputs": inputs,
  39. "user": str(user_id),
  40. "response_mode": "blocking",
  41. }
  42. try:
  43. async with httpx.AsyncClient(timeout=30) as client:
  44. resp = await client.post(url, json=body, headers=headers)
  45. data = resp.json()
  46. if "data" in data and "outputs" in data["data"]:
  47. return data["data"]["outputs"]
  48. except Exception as e:
  49. logger.warning("Dify 舌诊失败: %s", e)
  50. return self._mock_result()
  51. async def _via_llm(self, image_url: str) -> dict:
  52. """直接调用多模态 LLM (预留)"""
  53. logger.warning("多模态 LLM 未配置, 返回模拟数据")
  54. return self._mock_result()
  55. def _mock_result(self) -> dict:
  56. return {
  57. "overall_assessment": "舌象基本正常, 舌质淡红, 苔薄白, 提示脾胃功能尚可。",
  58. "indicators": [
  59. {"code": "tongue_color", "value": "淡红"},
  60. {"code": "coating_color", "value": "薄白"},
  61. {"code": "coating_texture", "value": "润"},
  62. {"code": "fissure", "value": "无"},
  63. {"code": "teeth_mark", "value": "轻"},
  64. {"code": "sublingual_vein", "value": "正常"},
  65. {"code": "constitution", "value": "平和质"},
  66. ],
  67. }