修复过滤器4误判用户名@提及为回复残片:公共子串为用户名时豁免

This commit is contained in:
youpaishidifu
2026-08-12 14:57:22 +08:00
parent b74fd5deb0
commit 9d44b8b1d1
+58 -2
View File
@@ -3755,8 +3755,33 @@ class MessageMonitor:
if _is_ask and not _is_full_sub:
logger.debug(f"[{platform}] OCR 过滤: 疑似回复片段但为问句且非完全子串,视为用户提问放行 line={line[:60]!r}")
else:
logger.debug(f"[{platform}] OCR 过滤: 回复内容片段 line={line[:60]!r}")
continue
# ⭐ 用户名@提及豁免(2026-08-12):公共子串主要是用户名/昵称时,
# 且用户消息含中文内容,视为用户提问而非回复残片。
# 例:youpaishidifu关于我们 vs @youpaishidifu 你好 → 公共子串youpaishidifu是用户名
_cjk_line = ''.join(c for c in line if '\u4e00' <= c <= '\u9fff')
_has_cjk = len(_cjk_line) >= 2
if _has_cjk and not _is_full_sub:
_pub_is_username = False
for r in self._replied_texts:
if len(r) < 5:
continue
sm = difflib.SequenceMatcher(None, line, r)
lm = sm.find_longest_match(0, len(line), 0, len(r)).size
if lm >= 8:
match = sm.find_longest_match(0, len(line), 0, len(r))
pub_str = line[match.a:match.a + match.size]
pub_cjk = sum(1 for c in pub_str if '\u4e00' <= c <= '\u9fff')
if pub_cjk == 0:
_pub_is_username = True
break
if _pub_is_username:
logger.debug(f"[{platform}] OCR 过滤: 疑似回复片段但公共子串为用户名且消息含中文,视为用户提问放行 line={line[:60]!r}")
else:
logger.debug(f"[{platform}] OCR 过滤: 回复内容片段 line={line[:60]!r}")
continue
else:
logger.debug(f"[{platform}] OCR 过滤: 回复内容片段 line={line[:60]!r}")
continue
# ⭐ Task #1441: bot自身消息查库过滤
# 检查OCR读到的内容是否与数据库中bot回复的消息重合率≥90%
@@ -4748,6 +4773,37 @@ class MessageMonitor:
if _is_ask and not _is_full_sub:
logger.debug(f"[ocr] 过滤器4结果: 匹配成功但为问句且非完全子串,视为用户提问返回False")
return False
# ⭐ 用户名@提及豁免(2026-08-12):当公共子串主要是用户名/昵称(不含中文),
# 且用户消息的其余部分包含中文内容时,视为用户提问而非回复残片。
# 例:youpaishidifu关于我们 vs @youpaishidifu 你好 → 公共子串youpaishidifu是用户名,
# 剩余"关于我们"是用户实际提问,不应判为残片。
_has_cjk_in_text = len(t_cjk) >= 2 # 用户消息至少2个中文字符
if _has_cjk_in_text and not _is_full_sub:
# 检查公共子串是否主要是非中文(用户名/昵称)
# 找最长公共子串对应的r_norm片段
_pub_is_username = False
for r in self._replied_texts:
if len(r) < 5:
continue
r_norm = self._norm_frag(r)
if not r_norm:
continue
sm = difflib.SequenceMatcher(None, t_norm, r_norm)
lm = sm.find_longest_match(0, len(t_norm), 0, len(r_norm)).size
if lm >= 8:
# 提取公共子串在t_norm中的位置
match = sm.find_longest_match(0, len(t_norm), 0, len(r_norm))
pub_str = t_norm[match.a:match.a + match.size]
# 检查公共子串是否不含中文(即主要是用户名/昵称)
pub_cjk = sum(1 for c in pub_str if '\u4e00' <= c <= '\u9fff')
if pub_cjk == 0 and lm >= 8:
_pub_is_username = True
break
if _pub_is_username:
logger.debug(f"[ocr] 过滤器4结果: 匹配成功但公共子串为用户名且消息含中文,视为用户提问返回False")
return False
logger.debug(f"[ocr] 过滤器4结果: 文本匹配成功,返回True")
return True
logger.debug(f"[ocr] 过滤器4结果: 未匹配到已回复文本,返回False")