修复重复处理+新消息不处理:全签名跳过+_seen_messages上限+模糊阈值0.80

1. 全文本签名提前跳过(关键)
   OCR输出与上轮完全一样→立即return,不跑去重循环
   99%场景OCR内容不变,之前却每次都跑模糊匹配→噪声导致漏网

2. _seen_messages上限500条,超了裁到300
   无限增长→新消息模糊匹配时被历史噪声误杀("新消息没处理")
   上限后新消息只和最近300条比,大幅降低误杀率

3. 模糊匹配阈值0.72→0.80
   短文本0.72太松,"你好"vs"你好啊"75%相似就被当成重复
   0.80要求80%重复才跳过,放行真新消息
This commit is contained in:
youpaishidifu
2026-07-26 14:11:37 +08:00
parent e9d9551e3d
commit f4c6243944
+17 -19
View File
@@ -518,7 +518,7 @@ class MessageMonitor:
return False
@staticmethod
def _fuzzy_duplicate(new_text: str, seen_set: set, threshold: float = 0.72) -> bool:
def _fuzzy_duplicate(new_text: str, seen_set: set, threshold: float = 0.80) -> bool:
"""检查 new_text 是否与 seen_set 中已有文本相似度超阈值。
OCR 输出有噪声(每次勖彐碎片、行首数字、尾部截断不同),精确匹配无法去重。
@@ -1418,6 +1418,13 @@ class MessageMonitor:
self._empty_reads[platform] = 0
# 4a. 全文本签名快速跳过 — OCR 输出与上轮完全相同 → 无变化,跳过
sig = "||".join([t.strip() for t in texts if t.strip()])
if sig == self._last_sig.get(platform, ""):
stale = self._stale_count.get(platform, 0) + 1
self._stale_count[platform] = stale
return
# 4. 用全局 _seen_messages 去重(跨平台、跨轮次防回环)
# 精确匹配 + 模糊匹配(OCR 噪声导致精确匹配失效)
seen = self._seen_messages
@@ -1434,7 +1441,7 @@ class MessageMonitor:
continue
# 模糊匹配:OCR 输出每次微小差异(勖彐碎片、行首数字、尾部截断)
# 精确匹配命中不了 → 用 difflib 相似度去重
if self._fuzzy_duplicate(ts, seen, threshold=0.72):
if self._fuzzy_duplicate(ts, seen, threshold=0.80):
logger.debug(f"[{platform}] 模糊重复跳过: {ts[:50]}")
continue
if self._is_system_message(ts):
@@ -1448,37 +1455,28 @@ class MessageMonitor:
continue
seen.add(ts)
new_items.append(ts)
# 不截断 _seen_messages — _replied_texts 已拦截回复回环,截断会误放历史消息
# 极端情况(>50万行)才手动清,几乎不会出现
# _seen_messages 上限 500 条,超了裁到 300
# 防止集合无限膨胀 → 新消息模糊匹配时被历史噪声误杀
if len(seen) > 500:
# 保留后 300 条(最新)
self._seen_messages = set(list(seen)[-300:])
# 单次 poll 最多处理 3 条新消息,防止系统消息海量涌入触发回环
MAX_NEW_ITEMS = 3
new_items = new_items[:MAX_NEW_ITEMS]
# 更新 last_texts 供其他逻辑参考(但去重不依赖它)
# 更新 last_texts 与签名
self._last_texts[platform] = list(texts)
self._last_sig[platform] = sig
self._stale_count[platform] = 0
if new_items:
# 有纯粹的新文本 → 逐一报告
sig = "||".join([t.strip() for t in texts if t.strip()])
self._last_sig[platform] = sig
self._stale_count[platform] = 0
for item in new_items:
self._last_msg[platform] = item
logger.info(f"[{platform}] 新消息: {item[:60]}")
if self._on_message:
self._on_message(platform, item)
else:
# 无新文本 → 用全签名判断是否内容变化(emoji 刷新等)
sig = "||".join([t.strip() for t in texts if t.strip()])
old_sig = self._last_sig.get(platform, "")
if sig != old_sig:
self._last_sig[platform] = sig
self._stale_count[platform] = 0
else:
# 相同签名 → 冻结计数
stale = self._stale_count.get(platform, 0) + 1
self._stale_count[platform] = stale
if platform == "qq":
if stale == 3:
logger.debug(f"[QQ] 冻结 #{stale},强制刷新")