| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- 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={})
|