indicator_classify.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. from fastapi import APIRouter
  2. from pydantic import BaseModel
  3. from typing import Optional, List
  4. from app.llm.client import get_llm
  5. from langchain_core.messages import SystemMessage, HumanMessage
  6. import logging
  7. import json
  8. logger = logging.getLogger(__name__)
  9. router = APIRouter(prefix="/api/v1", tags=["indicator_classify"])
  10. _llm = None
  11. def get_llm_instance():
  12. global _llm
  13. if _llm is None:
  14. _llm = get_llm()
  15. return _llm
  16. class ClassifyRequest(BaseModel):
  17. source_type: str
  18. raw_name: str
  19. candidates: Optional[List[str]] = None
  20. class ClassifyResponse(BaseModel):
  21. code: int = 200
  22. message: str = "ok"
  23. data: dict = {}
  24. SYSTEM_PROMPT = (
  25. "你是健康报告指标归一化归类助手。给定一个报告中的原始指标/菌属/食材名称,"
  26. "把它归类为统一指标字典中的一个标准定义。只输出 JSON:"
  27. '{"code": "indicator.<类别>.<标准名>" | "bacteria.<标准名>" | "food.<标准名>", '
  28. '"name": "标准显示名", "category": "分类"}。'
  29. "若候选列表非空,优先从候选中选择语义最接近的标准 code。"
  30. )
  31. @router.post("/indicator/classify", response_model=ClassifyResponse)
  32. async def classify_indicator(req: ClassifyRequest):
  33. logger.info("indicator_classify: source=%s raw=%s", req.source_type, req.raw_name)
  34. llm = get_llm_instance()
  35. prompt = f"来源类型: {req.source_type}\n原始名称: {req.raw_name}\n"
  36. if req.candidates:
  37. prompt += "候选标准定义: " + ", ".join(req.candidates) + "\n"
  38. try:
  39. messages = [
  40. SystemMessage(content=SYSTEM_PROMPT),
  41. HumanMessage(content=prompt),
  42. ]
  43. response = await llm.ainvoke(messages)
  44. text = response.content.strip()
  45. if "```json" in text:
  46. text = text.split("```json")[1].split("```")[0].strip()
  47. elif "```" in text:
  48. text = text.split("```")[1].strip()
  49. data = json.loads(text)
  50. return ClassifyResponse(data=data)
  51. except Exception as e:
  52. logger.error("指标归类失败: %s", e, exc_info=True)
  53. return ClassifyResponse(code=500, message=f"归类失败: {str(e)}", data={})