fix: 修复OCR捕捉含年月日消息导致后续消息丢失的问题 (Task #1652/#1653)

问题:当上面一条消息有年月日时,下面的消息会丢失目标定位,需通过表情包/图片才能重新加入消息队列
根因:_ocr_text_has_fresh_timestamp对整个文本块检查,任何部分含历史日期都会导致整段文本被丢弃
修复:
1. 新增_strip_historical_date_lines辅助方法,按行分割文本并智能剥离历史日期行
2. 修改_process_ocr_output中的时间戳新鲜性检查逻辑
3. 当检测到历史日期时,先尝试剥离旧消息行,保留新鲜消息继续处理
4. 仅含日期无时间的表格日期:剥离日期但保留行内容
5. 含日期+时间的历史消息行:完全剥离
6. 无日期的行:完整保留
This commit is contained in:
youpaishidifu
2026-08-31 11:57:51 +08:00
parent 5b9b0ff7ac
commit 4f61ee3aac
+67 -12
View File
@@ -3773,10 +3773,24 @@ class MessageMonitor:
if not raw_text:
return []
if not self._ocr_text_has_fresh_timestamp(raw_text, platform):
# ⭐ 2026-08-24 新逻辑:_ocr_text_has_fresh_timestamp 返回 False 表示
# 检测到清晰年月日(历史消息),应丢弃整段文本
logger.debug(f"[{platform}] OCR 有清晰年月日(历史消息),丢弃整段: {raw_text[:80]!r}")
return []
# ⭐ 2026-08-30 Task #1652 修复:尝试剥离历史日期行,保留新鲜消息
# 根因:_ocr_text_has_fresh_timestamp 对整个文本块检查,任何部分含历史日期都会
# 导致整段文本被丢弃,即使其中包含新鲜消息(如"2026/8/30 23:29:35"下方的新查询)
# 解决:按行分割,剥离含日期+时间的行(历史消息),保留无日期或仅含表格日期的行
logger.debug(f"[{platform}] OCR 时间戳新鲜性检查失败,尝试剥离历史日期行...")
salvaged_text = self._strip_historical_date_lines(raw_text, platform)
if not salvaged_text:
logger.debug(f"[{platform}] 剥离历史日期行后无剩余文本,丢弃整段: {raw_text[:80]!r}")
return []
# 对剥离后的文本重新检查新鲜性
if not self._ocr_text_has_fresh_timestamp(salvaged_text, platform):
logger.debug(f"[{platform}] 剥离历史日期行后仍无新鲜消息,丢弃: {salvaged_text[:80]!r}")
return []
# 使用剥离后的文本继续处理
logger.debug(f"[{platform}] 剥离历史日期行后有新鲜消息,继续处理: {salvaged_text[:80]!r}")
raw_text = salvaged_text
# —— 行切割 + 尾标清理 ——
ocr_lines = []
@@ -6994,9 +7008,10 @@ class MessageMonitor:
# 纯英文/数字/符号,可能是UI噪声,丢弃
logger.debug(f"[ocr] 过滤器1结果: 无时间戳且无中文字符,丢弃: {stripped[:80]!r}")
return False
# 用户消息挨着bot消息判断:最近一次bot回复在60秒内(放宽窗口)
last_bot_time = self._msg_history.last_bot_reply_time(platform)
if last_bot_time > 0 and time.time() - last_bot_time <= 60:
# 用户消息挨着bot消息判断:最近一次bot回复在60秒内(放宽窗口)
last_bot_time = self._msg_history.last_bot_reply_time(platform)
if last_bot_time > 0 and time.time() - last_bot_time <= 60:
# 用户消息挨着bot消息
if not self._msg_history.is_user_message_replied(platform, stripped, time.time()):
# 数据库无记录,无条件放行
@@ -7006,11 +7021,11 @@ class MessageMonitor:
# 数据库有记录,整段丢弃
logger.debug(f"[ocr] 过滤器1结果: 无时间戳且用户消息挨着bot消息但有记录,丢弃: {stripped[:80]!r}")
return False
# ⭐ 无时间戳消息:放行交给DB查重处理(避免连续聊天时时间戳被覆盖误杀用户消息)
# 无论消息长短,只要包含中文字符且非噪声,都放行
# DB查重会自动过滤掉已经回复过的消息
logger.info(f"[ocr] 过滤器1结果: 无时间戳但为中文消息,交由DB查重: {stripped[:80]!r}")
return True
# ⭐ 无时间戳消息:放行交给DB查重处理(避免连续聊天时时间戳被覆盖误杀用户消息)
# 无论消息长短,只要包含中文字符且非噪声,都放行
# DB查重会自动过滤掉已经回复过的消息
logger.info(f"[ocr] 过滤器1结果: 无时间戳但为中文消息,交由DB查重: {stripped[:80]!r}")
return True
# 有新鲜时间戳 → 确定有新消息
for ts in timestamps:
try:
@@ -7034,6 +7049,46 @@ class MessageMonitor:
logger.debug(f"[ocr] 过滤器1结果: 无新鲜时间戳(全部>300s){_age_info},丢弃: {text[:80]!r}")
return False
def _strip_historical_date_lines(self, text: str, platform: str = "unknown") -> str:
"""剥离含历史日期的行,保留可能的新鲜消息。
当 _ocr_text_has_fresh_timestamp 返回 False 时调用,尝试按行分割文本,
识别并剥离含过去日期(年月日+时分)的行,保留其余部分。
返回剥离后的文本;若无剩余内容则返回空字符串。
"""
if not text:
return ""
lines = text.split('\n')
salvaged = []
for line in lines:
# 检查行是否包含日期模式
date_pattern = r'\d{4}[/-]\d{1,2}[/-]\d{1,2}|\d{4}年\d{1,2}月\d{1,2}日'
if re.search(date_pattern, line):
# 检查日期是否附带时间(年月日+时分 = 真消息)
time_pattern = r'(\d{4}[/-]\d{1,2}[/-]\d{1,2}|\d{4}年\d{1,2}月\d{1,2}日)\s*\d{1,2}:\d{1,2}'
if re.search(time_pattern, line):
# 含日期+时间 = 历史消息行,剥离
logger.debug(f"[{platform}] 剥离含过去日期+时间行: {line[:60]!r}")
continue
else:
# 仅有日期无时间 = 表格日期,剥离日期但保留行其余部分
cleaned = re.sub(date_pattern, '', line).strip()
if cleaned:
logger.debug(f"[{platform}] 剥离表格日期后保留: {cleaned[:60]!r}")
salvaged.append(cleaned)
else:
logger.debug(f"[{platform}] 表格日期行为空,丢弃: {line[:60]!r}")
continue
# 无日期模式,保留整行
salvaged.append(line)
if not salvaged:
return ""
return '\n'.join(salvaged)
# 未来时间戳容忍偏差(秒):同日内时间戳比系统时间晚超过此值 = 未到来,直接丢弃。
# 容忍偏差与 max_age 持平(300s):OCR/聊天服务器时钟与系统时钟存在秒级差异,
# 刚到的消息时间戳可能比系统时间晚几秒(如 14:41:00 消息在 14:40:58 被捕获),