修复OCR回复牛头不对马嘴+残留消息+EasyOCR崩溃捕获+360误报
1. knowledge_base.py: 检索排序惩罚标题-only/短正文段,降低heading bonus,奖励正文命中,避免纯标题/免责声明段排第一 2. auto_reply.py: 动作类查询要求正文命中才放行;拒绝纯标题/免责声明答案 3. monitor.py: 调试截图改存%LOCALAPPDATA%/windowmsgbot/ocr_debug避开源码目录(360); 收紧残留消息fresh gate(600s硬门); 启动即崩溃/请求崩溃时读取easyocr_crash.log写入主日志 4. easyocr_worker.py: 加faulthandler+sys.excepthook全局捕获,崩溃traceback落盘%LOCALAPPDATA%/windowmsgbot/easyocr_crash.log
This commit is contained in:
+30
-5
@@ -300,6 +300,24 @@ class KnowledgeBase:
|
||||
|
||||
combined_scores = 0.7 * tfidf_scores + 0.3 * keyword_scores
|
||||
|
||||
# 内容质量调整:惩罚标题-only/正文过短的 section,奖励正文含查询词的 section
|
||||
# 避免"# Sdf1系列登录插件使用说明"这种纯标题段因为标题词匹配就排第一
|
||||
for i, doc in enumerate(self.docs):
|
||||
body = doc.get("body", "")
|
||||
body_len = len(body.strip())
|
||||
heading = doc.get("heading", "")
|
||||
# 单层 # 标题且无实质正文 → 大幅降权
|
||||
if heading.startswith("# ") and body_len < 50:
|
||||
combined_scores[i] *= 0.2
|
||||
elif body_len < 30:
|
||||
combined_scores[i] *= 0.5
|
||||
# 正文含查询词 → 奖励(说明 section 真的在讲用户问的内容)
|
||||
body_hits = sum(1 for t in query_tokens_set if t in self._body_token_sets[i])
|
||||
if body_hits >= 2:
|
||||
combined_scores[i] *= 1.3
|
||||
elif body_hits >= 1:
|
||||
combined_scores[i] *= 1.1
|
||||
|
||||
# 短查询惩罚:分词数 ≤2 的短查询(如图标残片/短词)得分大幅降权
|
||||
# 防止 OCR 碎片中的高 IDF 词(如"下载")获得超过真实用户消息的分数
|
||||
n_tokens = len(tokens)
|
||||
@@ -413,19 +431,26 @@ class KnowledgeBase:
|
||||
heading = doc.get("heading", "")
|
||||
body = doc.get("body", doc.get("content", ""))
|
||||
h_tokens = set(t for t in jieba.cut(heading) if len(t) >= 2)
|
||||
# heading 包含查询关键词 → bonus(5.0 每命中词,足够翻转 TF-IDF 差距)
|
||||
# heading 包含查询关键词 → 适度 bonus(2.0 每命中词)
|
||||
heading_hits = len(query_tokens & h_tokens)
|
||||
bonus = heading_hits * 5.0
|
||||
# heading 包含查询连续短语 → 额外 bonus(如查询含"奖励配置"且 heading 含"奖励配置")
|
||||
bonus = heading_hits * 2.0
|
||||
# heading 包含查询连续短语 → 额外 bonus
|
||||
for qlen in range(min(len(query_stripped), 8), 3, -1):
|
||||
for start in range(len(query_stripped) - qlen + 1):
|
||||
phrase = query_stripped[start:start+qlen]
|
||||
if len(phrase) >= 4 and phrase in heading:
|
||||
bonus += 8.0
|
||||
bonus += 6.0
|
||||
break
|
||||
# body 包含查询连续短语 → 强 bonus(说明正文真的在讲用户问的内容)
|
||||
for qlen in range(min(len(query_stripped), 8), 3, -1):
|
||||
for start in range(len(query_stripped) - qlen + 1):
|
||||
phrase = query_stripped[start:start+qlen]
|
||||
if len(phrase) >= 4 and phrase in body:
|
||||
bonus += 10.0
|
||||
break
|
||||
# 文档头部惩罚:heading 是单层 # + 文档名(如 "# php管理员后端"),且无 body
|
||||
if heading.startswith("# ") and (not body or len(body) < 50):
|
||||
bonus -= 5.0
|
||||
bonus -= 15.0
|
||||
reranked.append((idx, doc, score + bonus))
|
||||
reranked.sort(key=lambda x: x[2], reverse=True)
|
||||
doc_sections = reranked
|
||||
|
||||
Reference in New Issue
Block a user