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