fix: 修复中部孤立*导致用户查询被_is_noise_text误杀的问题
问题:OCR把bot的**小姐姐**识别成小姐姐*,单个*粘在昵称后, 导致'小姐姐*, 关于我们'(len≤10)被_is_noise_text判为残片丢弃,用户查询丢失。 根因: 1. _is_noise_text的逗号分段放行逻辑在elif分支,len≤10时永远不走逗号分段 2. 过滤管道无清理中部孤立*的机制(_strip_markdown_head只剥开头,_strip_markdown_tail只匹配**) 修复: 1. _is_noise_text:在len≤10分支的return True前增加逗号分段放行检查 - 短文本含逗号时,检查逗号后半部分是否含有效查询词(疑问词/动词/主语) - 后半部分有效→不丢弃,保留用户真实查询 2. 过滤管道增加孤立*清理步骤(正则: ([\u4e00-\u9fff])\*(?!\*)) - 清除中文字符旁的单个*(bot markdown加粗残留),不匹配**,不匹配英文场景 - 覆盖4个调用点:for循环管道、尾部过滤、逐行过滤、去重后过滤 3. 预分割噪声检测也增加*清理 commit: 4个过滤管道+预分割+2个辅助方法,共73行变更
This commit is contained in:
+73
-6
@@ -3510,6 +3510,14 @@ class MessageMonitor:
|
||||
if not _msg_bot:
|
||||
logger.debug(f"[ocr] stage[{i}] [filter/bot] bot旧回复整体剥离后为空,跳过: {buf.strip()[:60]!r}")
|
||||
else:
|
||||
# ⭐ 2026-08-21 清理 bot markdown 加粗残留:中文字符旁的孤立 *
|
||||
# OCR 把 bot 的 **小姐姐** 识别成 小姐姐*,单个 * 粘在昵称后,
|
||||
# 导致 _is_noise_text 误判为 OCR 残片丢弃整条消息。
|
||||
# 模式:中文*(*后非*)→ 删除 *;不匹配 **,不匹配英文场景(100*2)
|
||||
_msg_bot_before_star = _msg_bot
|
||||
_msg_bot = re.sub(r'([\u4e00-\u9fff])\*(?!\*)', r'\1', _msg_bot)
|
||||
if _msg_bot != _msg_bot_before_star:
|
||||
logger.info(f"[ocr] stage[{i}] [filter/star] 清理markdown加粗残留*: {_msg_bot_before_star[:60]!r} -> {_msg_bot[:60]!r}")
|
||||
# ⭐ 2026-08-19 新增:先剥【头部】md(bot md 列表项被 OCR 拼到用户消息前面,
|
||||
# 如 "- 关于我们" / "-关于我们")。_strip_markdown_tail 只剥尾部,
|
||||
# 对头部 md 无能为力(有空格→整段丢弃丢消息;无空格→漏检污染查库)。
|
||||
@@ -3584,6 +3592,11 @@ class MessageMonitor:
|
||||
if not _msg_bot:
|
||||
logger.debug(f"[ocr] stage[{i}] [filter/bot] 尾部bot旧回复整体剥离后为空,跳过: {buf.strip()[:60]!r}")
|
||||
else:
|
||||
# ⭐ 2026-08-21 清理 bot markdown 加粗残留(同 for 循环块)
|
||||
_msg_bot_before_star = _msg_bot
|
||||
_msg_bot = re.sub(r'([\u4e00-\u9fff])\*(?!\*)', r'\1', _msg_bot)
|
||||
if _msg_bot != _msg_bot_before_star:
|
||||
logger.info(f"[ocr] stage[{i}] [filter/star] 清理markdown加粗残留*(尾部): {_msg_bot_before_star[:60]!r} -> {_msg_bot[:60]!r}")
|
||||
# ⭐ 问句保护:若文本含问号且首段无问句,先分离尾部问句
|
||||
# 例: "php直登,是|,游戏里输,Jweb拿授权token,否|,那那个登录插件应该又去哪儿下载呢?"
|
||||
# _strip_markdown_tail 在首个 | 处切→只留"php直登,是"→问句丢失
|
||||
@@ -3944,6 +3957,12 @@ class MessageMonitor:
|
||||
logger.debug(f"[{platform}] OCR 过滤: YAML行 {line!r}")
|
||||
continue
|
||||
|
||||
# ⭐ 2026-08-21 清理 bot markdown 加粗残留(逐行过滤管道)
|
||||
line_before_star = line
|
||||
line = re.sub(r'([\u4e00-\u9fff])\*(?!\*)', r'\1', line)
|
||||
if line != line_before_star:
|
||||
logger.debug(f"[{platform}] OCR 过滤: 清理markdown加粗残留* line={line_before_star!r} -> {line!r}")
|
||||
|
||||
# —— md 尾巴剥离:末尾 markdown 内容切掉,保留用户原始提问 ——
|
||||
# ⭐ 2026-08-11:OCR 把 bot md 回复残片拼在用户消息尾部
|
||||
# (如 "群管理员...(头衔UI)...# #来测试# # @C418minecraf")。
|
||||
@@ -5859,6 +5878,11 @@ class MessageMonitor:
|
||||
if not text or not text.strip():
|
||||
return False
|
||||
t = text.strip()
|
||||
# ⭐ 2026-08-21 清理 bot markdown 加粗残留
|
||||
t_before_star = t
|
||||
t = re.sub(r'([\u4e00-\u9fff])\*(?!\*)', r'\1', t)
|
||||
if t != t_before_star:
|
||||
logger.debug(f"[ocr] _is_question_message: 清理markdown加粗残留*: {t_before_star[:60]!r} -> {t[:60]!r}")
|
||||
if not t.endswith(('?', '?')):
|
||||
return False
|
||||
if not re.search(r'[\u4e00-\u9fff]', t):
|
||||
@@ -6122,6 +6146,11 @@ class MessageMonitor:
|
||||
if not timestamps:
|
||||
# ⭐ 无可见时间戳:检查噪声文本
|
||||
logger.debug(f"[ocr] 无可见时间戳")
|
||||
# ⭐ 2026-08-21 清理 bot markdown 加粗残留(无时间戳分支)
|
||||
text_before_star = text
|
||||
text = re.sub(r'([\u4e00-\u9fff])\*(?!\*)', r'\1', text)
|
||||
if text != text_before_star:
|
||||
logger.info(f"[ocr] 清理markdown加粗残留*(无时间戳): {text_before_star[:60]!r} -> {text[:60]!r}")
|
||||
if self._is_noise_text(text):
|
||||
logger.debug(f"[ocr] 过滤器1结果: 无时间戳且为噪声文本,丢弃: {text[:80]!r}")
|
||||
return False
|
||||
@@ -6968,6 +6997,12 @@ class MessageMonitor:
|
||||
for i, seg in enumerate(segments):
|
||||
# ⭐ 2026-08-13: 先剥离bot旧回复,再检测噪声,防止混合文本被误判为噪声
|
||||
stripped_seg = self._strip_bot_reply_fragments(seg)
|
||||
# ⭐ 2026-08-21 清理 bot markdown 加粗残留(同 filter 管道)
|
||||
if stripped_seg:
|
||||
stripped_seg_before_star = stripped_seg
|
||||
stripped_seg = re.sub(r'([\u4e00-\u9fff])\*(?!\*)', r'\1', stripped_seg)
|
||||
if stripped_seg != stripped_seg_before_star:
|
||||
logger.debug(f"[{platform}] 预分割: 清理markdown加粗残留*: {stripped_seg_before_star[:60]!r} -> {stripped_seg[:60]!r}")
|
||||
is_noise = self._is_noise_text(stripped_seg) if stripped_seg else True
|
||||
if is_noise:
|
||||
noise_count += 1
|
||||
@@ -7115,12 +7150,39 @@ class MessageMonitor:
|
||||
_has_subject = any(s in text for s in ('我', '你', '他', '我们', '你们', '他们', '玩家', '用户', '管理员'))
|
||||
# 无疑问词 + 无动词 或 无疑问词 + 无主语 → 可能是残片
|
||||
if not _has_question_word and (not _has_verb or not _has_subject):
|
||||
# 额外防御:检查是否是常见用户问句模式
|
||||
_common_query = any(text.startswith(q) for q in ('怎么', '如何', '什么', '哪里', '哪个', '几', '多少', '为什么', '在哪', '如何'))
|
||||
_ends_with_question = text.rstrip().endswith(('?', '?', '!', '!'))
|
||||
if not _common_query and not _ends_with_question:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到OCR残片(无疑问词+无动词/主语),返回True: {text!r}")
|
||||
return True
|
||||
# ⭐ 修复(2026-08-21):短文本逗号分段放行
|
||||
# 原 elif 分支只在 len>10 时运行,短文本永远不走逗号分段。
|
||||
# 例:'小姐姐*, 关于我们'(len=10) → _has_verb=False → 误判残片→丢消息
|
||||
# 修复:len<=10 分支内也检查逗号分段,后半部分含有效查询→放行
|
||||
if ',' in text or ',' in text:
|
||||
_parts = re.split(r'[,,]', text)
|
||||
if len(_parts) >= 2:
|
||||
_second_part = _parts[-1].strip()
|
||||
_has_q2 = any(w in _second_part for w in ('吗', '呢', '多少', '怎么', '如何', '哪', '什么', '几', '?', '?'))
|
||||
_has_v2 = any(v in _second_part for v in ('怎么', '如何', '进行', '设置', '配置', '操作', '使用', '打开', '下载', '安装', '登录', '进入', '查看', '查询', '问', '找', '要', '可以', '能', '会', '请', '帮', '给', '有'))
|
||||
_has_s2 = any(s in _second_part for s in ('我', '你', '他', '我们', '你们', '他们', '玩家', '用户', '管理员'))
|
||||
if len(_second_part) >= 3 and (_has_q2 or _has_v2 or _has_s2):
|
||||
logger.debug(f"[ocr] 过滤器2结果: 短文本逗号分段放行(后半含有效查询): {text!r} -> {_second_part!r}")
|
||||
# 不return True,继续后续检查
|
||||
else:
|
||||
_common_query = any(text.startswith(q) for q in ('怎么', '如何', '什么', '哪里', '哪个', '几', '多少', '为什么', '在哪', '如何'))
|
||||
_ends_with_question = text.rstrip().endswith(('?', '?', '!', '!'))
|
||||
if not _common_query and not _ends_with_question:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到OCR残片(无疑问词+无动词/主语),返回True: {text!r}")
|
||||
return True
|
||||
else:
|
||||
_common_query = any(text.startswith(q) for q in ('怎么', '如何', '什么', '哪里', '哪个', '几', '多少', '为什么', '在哪', '如何'))
|
||||
_ends_with_question = text.rstrip().endswith(('?', '?', '!', '!'))
|
||||
if not _common_query and not _ends_with_question:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到OCR残片(无疑问词+无动词/主语),返回True: {text!r}")
|
||||
return True
|
||||
else:
|
||||
# 额外防御:检查是否是常见用户问句模式
|
||||
_common_query = any(text.startswith(q) for q in ('怎么', '如何', '什么', '哪里', '哪个', '几', '多少', '为什么', '在哪', '如何'))
|
||||
_ends_with_question = text.rstrip().endswith(('?', '?', '!', '!'))
|
||||
if not _common_query and not _ends_with_question:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到OCR残片(无疑问词+无动词/主语),返回True: {text!r}")
|
||||
return True
|
||||
elif ',' in text or ',' in text:
|
||||
# 逗号分隔的混合文本:检查后半部分是否为正常查询
|
||||
# 例:'个桓温,关于我们' → 前半是残片,后半是正常查询
|
||||
@@ -8442,6 +8504,11 @@ class MessageMonitor:
|
||||
continue
|
||||
if self._is_system_message(ts):
|
||||
continue
|
||||
# ⭐ 2026-08-21 清理 bot markdown 加粗残留(去重后过滤管道)
|
||||
ts_before_star = ts
|
||||
ts = re.sub(r'([\u4e00-\u9fff])\*(?!\*)', r'\1', ts)
|
||||
if ts != ts_before_star:
|
||||
logger.info(f"[{platform}] 清理markdown加粗残留*: {ts_before_star[:60]!r} -> {ts[:60]!r}")
|
||||
# Markdown 文档过滤:bot 回复以 md 格式为主(#标题、[链接](url)、-列表项),
|
||||
# 用户日常对话不用 md 语法。拦截 md 格式文本避免 bot 旧回复被重新处理。
|
||||
# ⭐ 2026-08-11 先剥 md 尾巴再判:md 在末尾→切小尾巴留用户提问;
|
||||
|
||||
Reference in New Issue
Block a user