baodan/api/insurance/ppt/knowledge.py

124 lines
3.8 KiB
Python
Raw Normal View History

2026-07-23 13:10:50 +08:00
"""公司知识库模块 — 公司匹配和证据排序。"""
import re
from typing import Optional
def _normalize_loose(input_str: str) -> str:
"""模糊标准化:小写 + 去除括号/分隔符。"""
s = input_str.lower()
s = re.sub(r"[\s\-_·.()\[\]{}]", "", s)
s = s.replace("x", "")
return s
def _score_profile(input_str: str, aliases: list[str], tags: list[str]) -> int:
"""评分公司匹配度。"""
normalized = _normalize_loose(input_str)
score = 0
for alias in aliases:
if _normalize_loose(alias) in normalized or normalized in _normalize_loose(alias):
score += 4
for tag in tags:
if _normalize_loose(tag) in normalized:
score += 2
return score
def match_company_knowledge(
product_name: Optional[str] = None,
company_hint: Optional[str] = None,
forced_company_id: Optional[str] = None,
companies: list[dict] = None,
products: list[dict] = None,
) -> dict:
"""匹配公司知识库。
Args:
product_name: 产品名称
company_hint: 公司名称提示
forced_company_id: 强制指定公司 ID
companies: 公司配置列表
products: 产品配置列表
Returns:
CompanyKnowledgeMatch dict
"""
companies = companies or []
products = products or []
# 1. 强制指定
if forced_company_id:
company = next((c for c in companies if c.get("id") == forced_company_id), None)
if company:
return {
"companyId": company["id"],
"companyName": company.get("displayName", ""),
"evidenceFiles": [],
"confidence": 1.0,
"matchedBy": "company_forced",
}
# 2. 产品目录匹配
if product_name:
normalized = product_name.lower()
for prod in products:
aliases = prod.get("aliases", [])
if any(_normalize_loose(a) in normalized for a in aliases):
company_id = prod.get("companyId")
company = next((c for c in companies if c.get("id") == company_id), None)
if company:
return {
"companyId": company["id"],
"companyName": company.get("displayName", ""),
"evidenceFiles": [],
"confidence": 1.0,
"matchedBy": "product_catalog",
}
# 3. 别名/标签模糊匹配
best_match = None
best_score = 0
search_text = f"{product_name or ''} {company_hint or ''}"
for company in companies:
aliases = company.get("aliases", [])
tags = company.get("aliases", []) # 用别名作为标签
score = _score_profile(search_text, aliases, tags)
if score > best_score:
best_score = score
best_match = company
if best_match and best_score > 0:
confidence = min(0.95, 0.45 + best_score / 20)
return {
"companyId": best_match["id"],
"companyName": best_match.get("displayName", ""),
"evidenceFiles": [],
"confidence": confidence,
"matchedBy": "company_alias",
}
return {
"companyId": "",
"companyName": "",
"evidenceFiles": [],
"confidence": 0,
"matchedBy": "unknown",
}
def expected_company_id_for_product(
product_name: Optional[str],
products: list[dict] = None,
) -> Optional[str]:
"""通过产品名查找对应公司 ID。"""
if not product_name:
return None
products = products or []
normalized = product_name.lower()
for prod in products:
aliases = prod.get("aliases", [])
if any(_normalize_loose(a) in normalized for a in aliases):
return prod.get("companyId")
return None