|
|
@@ -0,0 +1,64 @@
|
|
|
+from fastapi import APIRouter
|
|
|
+from pydantic import BaseModel
|
|
|
+from typing import Optional, List
|
|
|
+from app.llm.client import get_llm
|
|
|
+from langchain_core.messages import SystemMessage, HumanMessage
|
|
|
+import logging
|
|
|
+import json
|
|
|
+
|
|
|
+logger = logging.getLogger(__name__)
|
|
|
+router = APIRouter(prefix="/api/v1", tags=["indicator_classify"])
|
|
|
+_llm = None
|
|
|
+
|
|
|
+
|
|
|
+def get_llm_instance():
|
|
|
+ global _llm
|
|
|
+ if _llm is None:
|
|
|
+ _llm = get_llm()
|
|
|
+ return _llm
|
|
|
+
|
|
|
+
|
|
|
+class ClassifyRequest(BaseModel):
|
|
|
+ source_type: str
|
|
|
+ raw_name: str
|
|
|
+ candidates: Optional[List[str]] = None
|
|
|
+
|
|
|
+
|
|
|
+class ClassifyResponse(BaseModel):
|
|
|
+ code: int = 200
|
|
|
+ message: str = "ok"
|
|
|
+ data: dict = {}
|
|
|
+
|
|
|
+
|
|
|
+SYSTEM_PROMPT = (
|
|
|
+ "你是健康报告指标归一化归类助手。给定一个报告中的原始指标/菌属/食材名称,"
|
|
|
+ "把它归类为统一指标字典中的一个标准定义。只输出 JSON:"
|
|
|
+ '{"code": "indicator.<类别>.<标准名>" | "bacteria.<标准名>" | "food.<标准名>", '
|
|
|
+ '"name": "标准显示名", "category": "分类"}。'
|
|
|
+ "若候选列表非空,优先从候选中选择语义最接近的标准 code。"
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+@router.post("/indicator/classify", response_model=ClassifyResponse)
|
|
|
+async def classify_indicator(req: ClassifyRequest):
|
|
|
+ logger.info("indicator_classify: source=%s raw=%s", req.source_type, req.raw_name)
|
|
|
+ llm = get_llm_instance()
|
|
|
+ prompt = f"来源类型: {req.source_type}\n原始名称: {req.raw_name}\n"
|
|
|
+ if req.candidates:
|
|
|
+ prompt += "候选标准定义: " + ", ".join(req.candidates) + "\n"
|
|
|
+ try:
|
|
|
+ messages = [
|
|
|
+ SystemMessage(content=SYSTEM_PROMPT),
|
|
|
+ HumanMessage(content=prompt),
|
|
|
+ ]
|
|
|
+ response = await llm.ainvoke(messages)
|
|
|
+ text = response.content.strip()
|
|
|
+ if "```json" in text:
|
|
|
+ text = text.split("```json")[1].split("```")[0].strip()
|
|
|
+ elif "```" in text:
|
|
|
+ text = text.split("```")[1].strip()
|
|
|
+ data = json.loads(text)
|
|
|
+ return ClassifyResponse(data=data)
|
|
|
+ except Exception as e:
|
|
|
+ logger.error("指标归类失败: %s", e, exc_info=True)
|
|
|
+ return ClassifyResponse(code=500, message=f"归类失败: {str(e)}", data={})
|