修复OCR消息合并导致配置文件过滤器误伤用户消息的问题 (Task #1685)
1. 问题:OCR把多个消息拼接成一个整体,包含表格内容 - 表格内容中的'服主: youpaishidifu'被正则表达式匹配为'键:值'格式 - _is_noise_text检测到'多条配置文件格式(2条key:value)',返回True - 导致用户消息被丢弃,引起消息丢失 2. 修复: - 在_is_noise_text函数中添加表格内容特征检查 - 如果文本包含表格结构特征('|'分隔符、多行表格),则跳过配置文件检测 - 在_is_config_fragment函数中添加表格内容特征检查 - 避免误判表格内容为配置碎片 3. 测试: - 验证表格内容不再被误判为配置文件格式 - 验证纯配置文件仍能被正确检测 - 验证用户消息不受影响
This commit is contained in:
+103
-61
@@ -8341,6 +8341,7 @@ class MessageMonitor:
|
||||
- 段内出现 ≥2 个 bot 配置键词 + 冒号(值可空,OCR 常把值拆到下一行)
|
||||
- 或短段(≤30字)以单个 bot 配置键词 + 空冒号结尾(被截断的标签)
|
||||
排除含疑问词或 @提及 的真实用户问句。
|
||||
⭐ Task #1685: 排除表格内容,避免误判表格中的"键:值"格式。
|
||||
"""
|
||||
if not text:
|
||||
return False
|
||||
@@ -8354,6 +8355,17 @@ class MessageMonitor:
|
||||
if _has_question or _has_at:
|
||||
return False
|
||||
|
||||
# ── Task #1685: 排除表格内容 ──
|
||||
# 表格内容中的"|"分隔符是特征,不应被误判为配置碎片
|
||||
_has_table_structure = '|' in text and text.count('|') >= 2
|
||||
if _has_table_structure:
|
||||
_lines = text.split('\n')
|
||||
_table_lines = [line for line in _lines if '|' in line]
|
||||
if len(_table_lines) >= 2:
|
||||
# 包含多行表格结构,不是配置碎片
|
||||
logger.debug(f"[ocr] 预分割: 检测到表格结构({len(_table_lines)}行),不是配置碎片: {_s[:60]!r}")
|
||||
return False
|
||||
|
||||
# ── bot 配置键词表(bot 渲染插件配置/帮助面板使用的标签)──
|
||||
_config_keys = (
|
||||
'图标', '标题', '指令', '命令', '权限类型', '权限', '格子', '玩家', '商人',
|
||||
@@ -8554,51 +8566,73 @@ class MessageMonitor:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 空文本,返回False")
|
||||
return False
|
||||
|
||||
# ⭐ Task #1685: 表格内容特征检查(在配置文件检测之前)
|
||||
# OCR可能把多个消息拼接成一个整体,包含表格内容
|
||||
# 表格内容中的"键:值"格式不应被误判为配置文件
|
||||
# 特征:包含"|"分隔符(Markdown表格格式)
|
||||
_has_table_structure = '|' in text and text.count('|') >= 2
|
||||
if _has_table_structure:
|
||||
# 检查是否为表格结构:包含多行"|"分隔的内容
|
||||
_lines = text.split('\n')
|
||||
_table_lines = [line for line in _lines if '|' in line]
|
||||
if len(_table_lines) >= 2:
|
||||
# 包含多行表格结构,跳过配置文件检测
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到表格结构({len(_table_lines)}行),跳过配置文件检测: {text[:80]!r}")
|
||||
# 继续后续其他噪声检测,但不进行配置文件格式检测
|
||||
|
||||
# ⭐ Task #1592: 配置文件格式检测(最粗暴方法)
|
||||
# 检测所有配置文件格式:key:value 对、JSON 对象等
|
||||
# 特征:无问号/疑问词,有明显的配置结构
|
||||
# 直接丢弃,不进入后续KB搜索
|
||||
# 1. 检测JSON格式:包含大括号且是键值对
|
||||
_json_match = re.search(r'\{[^}]+\}', text)
|
||||
if _json_match:
|
||||
# 检查是否包含键值对(key: value 或 "key": "value")
|
||||
_json_content = _json_match.group(0)
|
||||
_kv_pattern = re.search(r'["\']?\w+["\']?\s*[::]\s*["\']?[^"\']+["\']?', _json_content)
|
||||
if _kv_pattern:
|
||||
# ⭐ Task #1595: 检查用户消息特征
|
||||
_has_user_msg_feature = '@' in text and bool(re.search(r'@\w+', text))
|
||||
_has_user_msg_feature |= any(q in text for q in ['?', '?', '吗', '呢', '多少', '怎么', '如何', '哪', '什么', '几'])
|
||||
if _has_user_msg_feature:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到JSON但含用户消息特征,继续检查: {text[:80]!r}")
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到JSON配置文件格式,返回True: {text!r}")
|
||||
return True
|
||||
# ⭐ Task #1685: 跳过表格结构内容
|
||||
if not _has_table_structure:
|
||||
_json_match = re.search(r'\{[^}]+\}', text)
|
||||
if _json_match:
|
||||
# 检查是否包含键值对(key: value 或 "key": "value")
|
||||
_json_content = _json_match.group(0)
|
||||
_kv_pattern = re.search(r'["\']?\w+["\']?\s*[::]\s*["\']?[^"\']+["\']?', _json_content)
|
||||
if _kv_pattern:
|
||||
# ⭐ Task #1595: 检查用户消息特征
|
||||
_has_user_msg_feature = '@' in text and bool(re.search(r'@\w+', text))
|
||||
_has_user_msg_feature |= any(q in text for q in ['?', '?', '吗', '呢', '多少', '怎么', '如何', '哪', '什么', '几'])
|
||||
if _has_user_msg_feature:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到JSON但含用户消息特征,继续检查: {text[:80]!r}")
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到JSON配置文件格式,返回True: {text!r}")
|
||||
return True
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到表格结构,跳过JSON配置文件检测: {text[:80]!r}")
|
||||
# 2. 检测key:value对格式:至少两个冒号分隔的键值对
|
||||
_colon_pattern = r'[\u4e00-\u9fff]{2,10}\s*[::]\s*\S+'
|
||||
_colon_matches = re.findall(_colon_pattern, text)
|
||||
if len(_colon_matches) >= 2:
|
||||
# ⭐ Task #1595 修复:配置面板+用户消息混排场景
|
||||
# OCR可能把"配置面板 + 用户消息 + UI时间戳"拼成一行
|
||||
# 例:"图标:potato标题:自杀...近期公告游戏专用<>有人@利17:36:25"
|
||||
# 如果直接丢弃整段,会误杀其中的用户消息
|
||||
# 检查是否有用户消息特征(@提及、疑问词、明确提问)
|
||||
_has_user_msg_feature = False
|
||||
# 特征1: @提及(用户@他人或@机器人)
|
||||
if '@' in text and re.search(r'@\w+', text):
|
||||
_has_user_msg_feature = True
|
||||
# 特征2: 疑问词(吗呢多少怎么如何哪什么几)
|
||||
if any(q in text for q in ['?', '?', '吗', '呢', '多少', '怎么', '如何', '哪', '什么', '几']):
|
||||
_has_user_msg_feature = True
|
||||
# 特征3: 明确的查询意图词(查/问/看/有/在哪/如何/怎么)
|
||||
if re.search(r'[查问看].*(?:插件|功能|命令|模式|系统|公告|信息)', text):
|
||||
_has_user_msg_feature = True
|
||||
if _has_user_msg_feature:
|
||||
# 包含用户消息特征,不丢弃,继续后续检查
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到多条key:value但含用户消息特征(@提及/疑问词),继续检查: {text[:80]!r}")
|
||||
else:
|
||||
# 纯配置文本,丢弃
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到多条配置文件格式({len(_colon_matches)}条key:value),返回True: {text!r}")
|
||||
return True
|
||||
# ⭐ Task #1685: 跳过表格结构内容,避免误判表格中的"键:值"格式
|
||||
if not _has_table_structure:
|
||||
_colon_pattern = r'[\u4e00-\u9fff]{2,10}\s*[::]\s*\S+'
|
||||
_colon_matches = re.findall(_colon_pattern, text)
|
||||
if len(_colon_matches) >= 2:
|
||||
# ⭐ Task #1595 修复:配置面板+用户消息混排场景
|
||||
# OCR可能把"配置面板 + 用户消息 + UI时间戳"拼成一行
|
||||
# 例:"图标:potato标题:自杀...近期公告游戏专用<>有人@利17:36:25"
|
||||
# 如果直接丢弃整段,会误杀其中的用户消息
|
||||
# 检查是否有用户消息特征(@提及、疑问词、明确提问)
|
||||
_has_user_msg_feature = False
|
||||
# 特征1: @提及(用户@他人或@机器人)
|
||||
if '@' in text and re.search(r'@\w+', text):
|
||||
_has_user_msg_feature = True
|
||||
# 特征2: 疑问词(吗呢多少怎么如何哪什么几)
|
||||
if any(q in text for q in ['?', '?', '吗', '呢', '多少', '怎么', '如何', '哪', '什么', '几']):
|
||||
_has_user_msg_feature = True
|
||||
# 特征3: 明确的查询意图词(查/问/看/有/在哪/如何/怎么)
|
||||
if re.search(r'[查问看].*(?:插件|功能|命令|模式|系统|公告|信息)', text):
|
||||
_has_user_msg_feature = True
|
||||
if _has_user_msg_feature:
|
||||
# 包含用户消息特征,不丢弃,继续后续检查
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到多条key:value但含用户消息特征(@提及/疑问词),继续检查: {text[:80]!r}")
|
||||
else:
|
||||
# 纯配置文本,丢弃
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到多条配置文件格式({len(_colon_matches)}条key:value),返回True: {text!r}")
|
||||
return True
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到表格结构,跳过key:value配置文件检测: {text[:80]!r}")
|
||||
elif len(_colon_matches) == 1:
|
||||
# 单条key:value,检查是否为完整的一条(无多余字符)
|
||||
_colon_match = re.match(r'^[\u4e00-\u9fff]{2,10}\s*[::]\s*\S+$', text)
|
||||
@@ -8625,29 +8659,37 @@ class MessageMonitor:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到单条配置文件格式(key: value),返回True: {text!r}")
|
||||
return True
|
||||
# 3. 检测其他配置文件格式:等号分隔的键值对(如key=value)
|
||||
_eq_pattern = r'[\u4e00-\u9fff]{2,10}\s*=\s*\S+'
|
||||
_eq_matches = re.findall(_eq_pattern, text)
|
||||
if len(_eq_matches) >= 2:
|
||||
# ⭐ Task #1595: 检查用户消息特征
|
||||
_has_user_msg_feature = '@' in text and bool(re.search(r'@\w+', text))
|
||||
_has_user_msg_feature |= any(q in text for q in ['?', '?', '吗', '呢', '多少', '怎么', '如何', '哪', '什么', '几'])
|
||||
if _has_user_msg_feature:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到等号配置但含用户消息特征,继续检查: {text[:80]!r}")
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到等号分隔的配置文件格式({len(_eq_matches)}条key=value),返回True: {text!r}")
|
||||
return True
|
||||
# ⭐ Task #1685: 跳过表格结构内容
|
||||
if not _has_table_structure:
|
||||
_eq_pattern = r'[\u4e00-\u9fff]{2,10}\s*=\s*\S+'
|
||||
_eq_matches = re.findall(_eq_pattern, text)
|
||||
if len(_eq_matches) >= 2:
|
||||
# ⭐ Task #1595: 检查用户消息特征
|
||||
_has_user_msg_feature = '@' in text and bool(re.search(r'@\w+', text))
|
||||
_has_user_msg_feature |= any(q in text for q in ['?', '?', '吗', '呢', '多少', '怎么', '如何', '哪', '什么', '几'])
|
||||
if _has_user_msg_feature:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到等号配置但含用户消息特征,继续检查: {text[:80]!r}")
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到等号分隔的配置文件格式({len(_eq_matches)}条key=value),返回True: {text!r}")
|
||||
return True
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到表格结构,跳过等号配置文件检测: {text[:80]!r}")
|
||||
# 4. 检测YAML/INI格式:行首为key,后跟冒号或等号
|
||||
_yaml_ini_pattern = r'^[\u4e00-\u9fff]{2,10}\s*[:=]\s*\S+'
|
||||
_yaml_ini_matches = re.findall(_yaml_ini_pattern, text, re.MULTILINE)
|
||||
if len(_yaml_ini_matches) >= 2:
|
||||
# ⭐ Task #1595: 检查用户消息特征
|
||||
_has_user_msg_feature = '@' in text and bool(re.search(r'@\w+', text))
|
||||
_has_user_msg_feature |= any(q in text for q in ['?', '?', '吗', '呢', '多少', '怎么', '如何', '哪', '什么', '几'])
|
||||
if _has_user_msg_feature:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到YAML/INI但含用户消息特征,继续检查: {text[:80]!r}")
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到YAML/INI配置文件格式({len(_yaml_ini_matches)}行),返回True: {text!r}")
|
||||
return True
|
||||
# ⭐ Task #1685: 跳过表格结构内容
|
||||
if not _has_table_structure:
|
||||
_yaml_ini_pattern = r'^[\u4e00-\u9fff]{2,10}\s*[:=]\s*\S+'
|
||||
_yaml_ini_matches = re.findall(_yaml_ini_pattern, text, re.MULTILINE)
|
||||
if len(_yaml_ini_matches) >= 2:
|
||||
# ⭐ Task #1595: 检查用户消息特征
|
||||
_has_user_msg_feature = '@' in text and bool(re.search(r'@\w+', text))
|
||||
_has_user_msg_feature |= any(q in text for q in ['?', '?', '吗', '呢', '多少', '怎么', '如何', '哪', '什么', '几'])
|
||||
if _has_user_msg_feature:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到YAML/INI但含用户消息特征,继续检查: {text[:80]!r}")
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到YAML/INI配置文件格式({len(_yaml_ini_matches)}行),返回True: {text!r}")
|
||||
return True
|
||||
else:
|
||||
logger.debug(f"[ocr] 过滤器2结果: 检测到表格结构,跳过YAML/INI配置文件检测: {text[:80]!r}")
|
||||
|
||||
# ⭐ 闲聊消息检测(2026-08-22 新增)
|
||||
# 特征:短文本 + 疑问词 + 无具体查询主题
|
||||
|
||||
Reference in New Issue
Block a user