修复重复处理+新消息不处理:全签名跳过+_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:
+17
-19
@@ -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},强制刷新")
|
||||
|
||||
Reference in New Issue
Block a user