修复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:
+42
@@ -8341,6 +8341,7 @@ class MessageMonitor:
|
|||||||
- 段内出现 ≥2 个 bot 配置键词 + 冒号(值可空,OCR 常把值拆到下一行)
|
- 段内出现 ≥2 个 bot 配置键词 + 冒号(值可空,OCR 常把值拆到下一行)
|
||||||
- 或短段(≤30字)以单个 bot 配置键词 + 空冒号结尾(被截断的标签)
|
- 或短段(≤30字)以单个 bot 配置键词 + 空冒号结尾(被截断的标签)
|
||||||
排除含疑问词或 @提及 的真实用户问句。
|
排除含疑问词或 @提及 的真实用户问句。
|
||||||
|
⭐ Task #1685: 排除表格内容,避免误判表格中的"键:值"格式。
|
||||||
"""
|
"""
|
||||||
if not text:
|
if not text:
|
||||||
return False
|
return False
|
||||||
@@ -8354,6 +8355,17 @@ class MessageMonitor:
|
|||||||
if _has_question or _has_at:
|
if _has_question or _has_at:
|
||||||
return False
|
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 渲染插件配置/帮助面板使用的标签)──
|
# ── bot 配置键词表(bot 渲染插件配置/帮助面板使用的标签)──
|
||||||
_config_keys = (
|
_config_keys = (
|
||||||
'图标', '标题', '指令', '命令', '权限类型', '权限', '格子', '玩家', '商人',
|
'图标', '标题', '指令', '命令', '权限类型', '权限', '格子', '玩家', '商人',
|
||||||
@@ -8554,11 +8566,27 @@ class MessageMonitor:
|
|||||||
logger.debug(f"[ocr] 过滤器2结果: 空文本,返回False")
|
logger.debug(f"[ocr] 过滤器2结果: 空文本,返回False")
|
||||||
return 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: 配置文件格式检测(最粗暴方法)
|
# ⭐ Task #1592: 配置文件格式检测(最粗暴方法)
|
||||||
# 检测所有配置文件格式:key:value 对、JSON 对象等
|
# 检测所有配置文件格式:key:value 对、JSON 对象等
|
||||||
# 特征:无问号/疑问词,有明显的配置结构
|
# 特征:无问号/疑问词,有明显的配置结构
|
||||||
# 直接丢弃,不进入后续KB搜索
|
# 直接丢弃,不进入后续KB搜索
|
||||||
# 1. 检测JSON格式:包含大括号且是键值对
|
# 1. 检测JSON格式:包含大括号且是键值对
|
||||||
|
# ⭐ Task #1685: 跳过表格结构内容
|
||||||
|
if not _has_table_structure:
|
||||||
_json_match = re.search(r'\{[^}]+\}', text)
|
_json_match = re.search(r'\{[^}]+\}', text)
|
||||||
if _json_match:
|
if _json_match:
|
||||||
# 检查是否包含键值对(key: value 或 "key": "value")
|
# 检查是否包含键值对(key: value 或 "key": "value")
|
||||||
@@ -8573,7 +8601,11 @@ class MessageMonitor:
|
|||||||
else:
|
else:
|
||||||
logger.debug(f"[ocr] 过滤器2结果: 检测到JSON配置文件格式,返回True: {text!r}")
|
logger.debug(f"[ocr] 过滤器2结果: 检测到JSON配置文件格式,返回True: {text!r}")
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
logger.debug(f"[ocr] 过滤器2结果: 检测到表格结构,跳过JSON配置文件检测: {text[:80]!r}")
|
||||||
# 2. 检测key:value对格式:至少两个冒号分隔的键值对
|
# 2. 检测key:value对格式:至少两个冒号分隔的键值对
|
||||||
|
# ⭐ Task #1685: 跳过表格结构内容,避免误判表格中的"键:值"格式
|
||||||
|
if not _has_table_structure:
|
||||||
_colon_pattern = r'[\u4e00-\u9fff]{2,10}\s*[::]\s*\S+'
|
_colon_pattern = r'[\u4e00-\u9fff]{2,10}\s*[::]\s*\S+'
|
||||||
_colon_matches = re.findall(_colon_pattern, text)
|
_colon_matches = re.findall(_colon_pattern, text)
|
||||||
if len(_colon_matches) >= 2:
|
if len(_colon_matches) >= 2:
|
||||||
@@ -8599,6 +8631,8 @@ class MessageMonitor:
|
|||||||
# 纯配置文本,丢弃
|
# 纯配置文本,丢弃
|
||||||
logger.debug(f"[ocr] 过滤器2结果: 检测到多条配置文件格式({len(_colon_matches)}条key:value),返回True: {text!r}")
|
logger.debug(f"[ocr] 过滤器2结果: 检测到多条配置文件格式({len(_colon_matches)}条key:value),返回True: {text!r}")
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
logger.debug(f"[ocr] 过滤器2结果: 检测到表格结构,跳过key:value配置文件检测: {text[:80]!r}")
|
||||||
elif len(_colon_matches) == 1:
|
elif len(_colon_matches) == 1:
|
||||||
# 单条key:value,检查是否为完整的一条(无多余字符)
|
# 单条key:value,检查是否为完整的一条(无多余字符)
|
||||||
_colon_match = re.match(r'^[\u4e00-\u9fff]{2,10}\s*[::]\s*\S+$', text)
|
_colon_match = re.match(r'^[\u4e00-\u9fff]{2,10}\s*[::]\s*\S+$', text)
|
||||||
@@ -8625,6 +8659,8 @@ class MessageMonitor:
|
|||||||
logger.debug(f"[ocr] 过滤器2结果: 检测到单条配置文件格式(key: value),返回True: {text!r}")
|
logger.debug(f"[ocr] 过滤器2结果: 检测到单条配置文件格式(key: value),返回True: {text!r}")
|
||||||
return True
|
return True
|
||||||
# 3. 检测其他配置文件格式:等号分隔的键值对(如key=value)
|
# 3. 检测其他配置文件格式:等号分隔的键值对(如key=value)
|
||||||
|
# ⭐ Task #1685: 跳过表格结构内容
|
||||||
|
if not _has_table_structure:
|
||||||
_eq_pattern = r'[\u4e00-\u9fff]{2,10}\s*=\s*\S+'
|
_eq_pattern = r'[\u4e00-\u9fff]{2,10}\s*=\s*\S+'
|
||||||
_eq_matches = re.findall(_eq_pattern, text)
|
_eq_matches = re.findall(_eq_pattern, text)
|
||||||
if len(_eq_matches) >= 2:
|
if len(_eq_matches) >= 2:
|
||||||
@@ -8636,7 +8672,11 @@ class MessageMonitor:
|
|||||||
else:
|
else:
|
||||||
logger.debug(f"[ocr] 过滤器2结果: 检测到等号分隔的配置文件格式({len(_eq_matches)}条key=value),返回True: {text!r}")
|
logger.debug(f"[ocr] 过滤器2结果: 检测到等号分隔的配置文件格式({len(_eq_matches)}条key=value),返回True: {text!r}")
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
logger.debug(f"[ocr] 过滤器2结果: 检测到表格结构,跳过等号配置文件检测: {text[:80]!r}")
|
||||||
# 4. 检测YAML/INI格式:行首为key,后跟冒号或等号
|
# 4. 检测YAML/INI格式:行首为key,后跟冒号或等号
|
||||||
|
# ⭐ Task #1685: 跳过表格结构内容
|
||||||
|
if not _has_table_structure:
|
||||||
_yaml_ini_pattern = r'^[\u4e00-\u9fff]{2,10}\s*[:=]\s*\S+'
|
_yaml_ini_pattern = r'^[\u4e00-\u9fff]{2,10}\s*[:=]\s*\S+'
|
||||||
_yaml_ini_matches = re.findall(_yaml_ini_pattern, text, re.MULTILINE)
|
_yaml_ini_matches = re.findall(_yaml_ini_pattern, text, re.MULTILINE)
|
||||||
if len(_yaml_ini_matches) >= 2:
|
if len(_yaml_ini_matches) >= 2:
|
||||||
@@ -8648,6 +8688,8 @@ class MessageMonitor:
|
|||||||
else:
|
else:
|
||||||
logger.debug(f"[ocr] 过滤器2结果: 检测到YAML/INI配置文件格式({len(_yaml_ini_matches)}行),返回True: {text!r}")
|
logger.debug(f"[ocr] 过滤器2结果: 检测到YAML/INI配置文件格式({len(_yaml_ini_matches)}行),返回True: {text!r}")
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
logger.debug(f"[ocr] 过滤器2结果: 检测到表格结构,跳过YAML/INI配置文件检测: {text[:80]!r}")
|
||||||
|
|
||||||
# ⭐ 闲聊消息检测(2026-08-22 新增)
|
# ⭐ 闲聊消息检测(2026-08-22 新增)
|
||||||
# 特征:短文本 + 疑问词 + 无具体查询主题
|
# 特征:短文本 + 疑问词 + 无具体查询主题
|
||||||
|
|||||||
Reference in New Issue
Block a user