修复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:
youpaishidifu
2026-08-01 21:21:05 +08:00
parent 9ff019df00
commit 0405e42a90
4 changed files with 225 additions and 46 deletions
+30 -5
View File
@@ -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