fix: md行跳过改为单行模式,移除块延续避免误杀用户消息
This commit is contained in:
+91
-2
@@ -3028,8 +3028,16 @@ class MessageMonitor:
|
||||
ocr_lines = []
|
||||
for l in raw_text.split('\n'):
|
||||
l = re.sub(r'\s*(?:[A-Za-z0-9]~)+\s*$', '', l).strip()
|
||||
if l:
|
||||
ocr_lines.append(l)
|
||||
if not l:
|
||||
continue
|
||||
# ⭐ Task #1475: 单行 Markdown 跳过。
|
||||
# 正常用户从不手动打 markdown(# 标题、|表格|、**加粗** 等)。
|
||||
# 撞上 md 段落标记 → 跳过该行;没有 md 标记 → 正常收集。
|
||||
# 不做"块延续",下一行立即恢复,避免误杀紧随其后的用户消息。
|
||||
if self._is_markdown_line(l):
|
||||
logger.debug(f"[{platform}] OCR: 跳过Markdown行: {l[:60]!r}")
|
||||
continue
|
||||
ocr_lines.append(l)
|
||||
|
||||
# —— 连续行合并(修复 EasyOCR 逗号断行) ——
|
||||
# EasyOCR 对长消息在中文逗号","处拆行,导致前半句无时间戳被丢弃。
|
||||
@@ -4788,6 +4796,87 @@ class MessageMonitor:
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _is_markdown_line(line: str) -> bool:
|
||||
"""⭐ Task #1475: 检测单行是否为 Markdown 强特征行。
|
||||
|
||||
正常用户从不手动打 markdown。一旦某一行 OCR 文本命中以下强特征,
|
||||
即判定为 markdown 行,整行跳过,避免污染普通消息:
|
||||
- # 标题(## 文档 / ##直接跟汉字 / ###1. 数字标题)
|
||||
- | 表格行(首尾 | 或含 3+ 个 |)
|
||||
- **加粗** / 裸 ** / 反引号 ` 代码
|
||||
- <br> HTML 换行 / [text](url) 链接 / > 引用块
|
||||
- --- 或 === 水平分隔线
|
||||
- 编号列表 1. 2) 3、 (bot md 回复常见,用户日常不打)
|
||||
注意:群名片 [专业皮肤定制] 不含 ] 后的 ( ,不会误判为链接;
|
||||
纯 [xxx] 也不命中任何强特征,安全保留。
|
||||
"""
|
||||
if not line:
|
||||
return False
|
||||
s = line.strip()
|
||||
# # 标题(含空格/直接跟汉字/数字/内联#)
|
||||
if re.match(r'^#{1,6}(\s|\[|#|\u4e00-\u9fff|\d)', s):
|
||||
return True
|
||||
# | 表格行
|
||||
if re.match(r'^\|.+\|$', s) or s.count('|') >= 3:
|
||||
return True
|
||||
# **加粗** 或裸 ** 或反引号代码
|
||||
if '**' in s or '`' in s:
|
||||
return True
|
||||
# <br> HTML 换行标记
|
||||
if re.search(r'<\s*br\s*/?\s*>', s, re.IGNORECASE):
|
||||
return True
|
||||
# [text](url) 链接(群名片 [xxx] 后无 ( 不命中)
|
||||
if re.search(r'\[.+?\]\(', s):
|
||||
return True
|
||||
# > 引用块
|
||||
if re.match(r'^>\s', s):
|
||||
return True
|
||||
# --- 或 === 水平分隔线
|
||||
if re.match(r'^[-=]{3,}\s*$', s):
|
||||
return True
|
||||
# 编号列表项(1. 2) 3、)
|
||||
if re.match(r'^\d{1,3}[\.\)、]\s', s):
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _is_md_continuation(line: str) -> bool:
|
||||
"""⭐ Task #1475: 判断某行是否为 markdown 块被 OCR 拆出来的"内容延续行"。
|
||||
|
||||
当上一行是 markdown 特征行时,OCR 常把同一 md 块的内容拆成多行,
|
||||
带 ## 的头部被识别为 md 并跳过,但尾部纯文本行(如"你就换/个问题。没事/这个不影响")
|
||||
无 md 特征会逃逸。此函数识别这些延续行并跳过。
|
||||
|
||||
判定为"延续行"(返回 True)的条件:
|
||||
- 无问号(?/?)、无 @、不以吗/呢/么结尾(非明显提问)
|
||||
- 非群名片 [xxx] 开头(群名片代表新消息起点)
|
||||
- 非时间戳开头
|
||||
- 长度 < 20(短句,符合 md 内容碎片特征)
|
||||
否则视为明显用户消息,返回 False 退出 md 块。
|
||||
"""
|
||||
if not line:
|
||||
return True
|
||||
s = line.strip()
|
||||
# 明显用户消息特征 → 不是延续
|
||||
if '?' in s or '?' in s:
|
||||
return False
|
||||
if '@' in s:
|
||||
return False
|
||||
if s.endswith(('吗', '呢', '?', '?', '么')):
|
||||
return False
|
||||
# 群名片 [xxx] 开头 → 新消息起点,退出 md 块
|
||||
if re.match(r'^[\[【][^\]】]*[\]】]', s):
|
||||
return False
|
||||
# 时间戳开头 → 新消息起点
|
||||
if re.match(r'^\d{1,2}[::]', s):
|
||||
return False
|
||||
# 较长陈述句(>=20字)可能为真实消息,退出 md 块
|
||||
if len(s) >= 20:
|
||||
return False
|
||||
# 默认:短、无问号、无@、非群名片 → 视为 md 内容延续
|
||||
return True
|
||||
|
||||
def _split_and_denoise_segments(self, raw_text: str, platform: str) -> str:
|
||||
"""混合文本预分割 + 分段噪声隔离。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user