baodan/api/insurance/ppt/knowledge.py

124 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""公司知识库模块 — 公司匹配和证据排序。"""
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