修复OCR时间戳丢弃策略:无年月日消息放行给DB查重
根因:QQ当天消息不显示日期,历史消息才显示"年/月/日 时:分"。 原逻辑对无时间戳消息放行,但对有时间戳无日期的消息过期就丢弃, 导致当天消息"12:36:05"被错误丢弃。 修复:_ocr_text_has_fresh_timestamp方法重写日期检查逻辑: 1. 有清晰年月日(四位年+月+日)→ 丢弃历史消息 2. 有不清晰年月日 → 用本地时间辅助判断时间戳是否过期 3. 无年月日 → 放行给下游DB查重(当天消息不带日期) 调用方简化:_ocr_text_has_fresh_timestamp返回False时直接丢弃。
This commit is contained in:
+79
-40
@@ -3428,17 +3428,10 @@ class MessageMonitor:
|
||||
if not raw_text:
|
||||
return []
|
||||
if not self._ocr_text_has_fresh_timestamp(raw_text, platform):
|
||||
# ⭐ 过去日期时间戳全部过期 → 整段丢弃(昨天的旧消息不应被当作新消息)
|
||||
# 区分:无时间戳(可放行,可能是短句) vs 过去日期时间戳过期(应丢弃)
|
||||
if self._has_past_date_timestamp(raw_text):
|
||||
logger.debug(f"[{platform}] OCR 过去日期时间戳全部过期,丢弃整段: {raw_text[:80]!r}")
|
||||
return []
|
||||
if re.search(r'[\u4e00-\u9fff]', raw_text):
|
||||
# 含中文 → 放行交下游过滤(关键词打分+DB查重+碎片过滤会拦截历史/噪声)
|
||||
logger.debug(f"[{platform}] OCR 无新鲜时间戳但含中文,放行交下游过滤: {raw_text[:80]!r}")
|
||||
else:
|
||||
logger.debug(f"[{platform}] OCR 无新鲜时间戳且无中文(UI噪声),丢弃: {raw_text[:80]!r}")
|
||||
return []
|
||||
# ⭐ 2026-08-24 新逻辑:_ocr_text_has_fresh_timestamp 返回 False 表示
|
||||
# 检测到清晰年月日(历史消息),应丢弃整段文本
|
||||
logger.debug(f"[{platform}] OCR 有清晰年月日(历史消息),丢弃整段: {raw_text[:80]!r}")
|
||||
return []
|
||||
|
||||
# —— 行切割 + 尾标清理 ——
|
||||
ocr_lines = []
|
||||
@@ -6364,32 +6357,85 @@ class MessageMonitor:
|
||||
break
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
# ⭐ 2026-08-15 修复:日期新鲜度检查(修正为辅助检查)
|
||||
# 原逻辑:如果文本包含日期信息,必须至少有一个日期是今天,否则拒绝
|
||||
# 问题:公告表格包含历史日期(如2026/8/14昨天),但用户最新消息是今天的
|
||||
# 修正:日期检查仅作为辅助验证,不能因为历史日期拒绝新鲜消息
|
||||
# - 有时戳:优先检查时间戳新鲜度(第二道关卡)
|
||||
# - 有日期+无今天日期:仍需检查时间戳,不能直接拒绝
|
||||
has_today_date = False
|
||||
# ⭐ 2026-08-24 新逻辑:OCR时间戳作为丢弃依据仅当清晰可见的年月日过期
|
||||
# - 有清晰年月日(无论今天还是过去)→ 整段丢弃(历史消息)
|
||||
# - 无年月日(只有时间)→ 放行给下游DB查重(当天消息不带日期)
|
||||
# - 年月日不清晰(如两位年份)→ 用本地时间辅助判断
|
||||
# 根因:QQ当天消息不显示日期,历史消息才显示"年/月/日 时:分"
|
||||
if dates:
|
||||
# 有日期信息:检查是否清晰(四位年+月+日)
|
||||
clear_date = False
|
||||
unclear_date = False
|
||||
for date_str in dates:
|
||||
try:
|
||||
parts = date_str.split('/')
|
||||
if len(parts) != 3:
|
||||
continue
|
||||
parts = date_str.split('/')
|
||||
if len(parts) == 3:
|
||||
y, m, d = int(parts[0]), int(parts[1]), int(parts[2])
|
||||
date_obj = datetime(y, m, d).date()
|
||||
if date_obj == today:
|
||||
has_today_date = True
|
||||
logger.debug(f"[ocr] 检测到今日日期: {date_str}")
|
||||
# 清晰日期:四位年+月+日完整
|
||||
if y >= 1000 and 1 <= m <= 12 and 1 <= d <= 31:
|
||||
clear_date = True
|
||||
break
|
||||
elif date_obj < today:
|
||||
logger.debug(f"[ocr] 检测到历史日期: {date_str} (距今{(today - date_obj).days}天)")
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
if not has_today_date:
|
||||
logger.debug(f"[ocr] 警告: 所有日期都非今日({dates}),但继续检查时间戳...")
|
||||
# 不直接拒绝,继续检查时间戳
|
||||
else:
|
||||
unclear_date = True
|
||||
if clear_date:
|
||||
# 清晰年月日:历史消息特征 → 整段丢弃
|
||||
logger.debug(f"[ocr] 过滤器1结果: 检测到清晰年月日,丢弃历史消息: {text[:80]!r}")
|
||||
return False
|
||||
elif unclear_date:
|
||||
# 年月日不清晰:用本地时间辅助判断时间戳是否过期
|
||||
logger.debug(f"[ocr] 检测到不清晰年月日,用本地时间辅助判断")
|
||||
# 如果有时间戳,检查时间戳是否过期(用本地时间比较)
|
||||
if timestamps:
|
||||
for ts in timestamps:
|
||||
try:
|
||||
if not self._is_timestamp_old(ts, 300):
|
||||
logger.debug(f"[ocr] 过滤器1结果: 不清晰日期+新鲜时间戳{ts}(≤300s),放行")
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
# 所有时间戳都过期 → 丢弃
|
||||
logger.debug(f"[ocr] 过滤器1结果: 不清晰日期+时间戳全过期,丢弃: {text[:80]!r}")
|
||||
return False
|
||||
# 无时间戳:放行给下游
|
||||
logger.debug(f"[ocr] 过滤器1结果: 不清晰日期+无时间戳,放行")
|
||||
return True
|
||||
# ⭐ 无日期信息:放行给下游DB查重(当天消息不带日期)
|
||||
if not dates:
|
||||
logger.debug(f"[ocr] 过滤器1结果: 无日期信息,放行给下游DB查重")
|
||||
# 如果有时间戳,检查时间戳新鲜度(可选,用于快速放行)
|
||||
if timestamps:
|
||||
for ts in timestamps:
|
||||
try:
|
||||
if not self._is_timestamp_old(ts, 300):
|
||||
logger.debug(f"[ocr] 过滤器1结果: 无日期+新鲜时间戳{ts}(≤300s),放行")
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
# 时间戳过期但无日期:仍放行给DB查重(可能是当天消息,OCR时间戳不准确)
|
||||
logger.debug(f"[ocr] 过滤器1结果: 无日期+时间戳过期,但放行给DB查重")
|
||||
return True
|
||||
# 无时间戳:需要检查噪声和中文字符(UI噪声应丢弃)
|
||||
logger.debug(f"[ocr] 无日期+无时间戳,检查噪声和中文字符")
|
||||
# 清理 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
|
||||
# 检查是否为纯中文或中英文混合消息(排除噪声)
|
||||
stripped = text.strip()
|
||||
if not stripped:
|
||||
return False
|
||||
# 检查是否包含中文字符(用户消息特征)
|
||||
has_chinese = re.search(r'[\u4e00-\u9fff]', stripped)
|
||||
if not has_chinese:
|
||||
# 纯英文/数字/符号,可能是UI噪声,丢弃
|
||||
logger.debug(f"[ocr] 过滤器1结果: 无日期+无时间戳+无中文字符,丢弃: {stripped[:80]!r}")
|
||||
return False
|
||||
# 放行给下游DB查重
|
||||
logger.debug(f"[ocr] 过滤器1结果: 无日期+无时间戳+中文消息,放行给下游DB查重")
|
||||
return True
|
||||
if not timestamps:
|
||||
# ⭐ 无可见时间戳:检查噪声文本
|
||||
logger.debug(f"[ocr] 无可见时间戳")
|
||||
@@ -6430,13 +6476,6 @@ class MessageMonitor:
|
||||
logger.info(f"[ocr] 过滤器1结果: 无时间戳但为中文消息,交由DB查重: {stripped[:80]!r}")
|
||||
self._msg_history.record_user_message(platform, stripped)
|
||||
return True
|
||||
# 如果检测到过去日期(昨天或更早),时间戳肯定是过去的
|
||||
# 无论时间戳是否看起来"新鲜"(如21:55:31),日期是昨天的 → 整段丢弃
|
||||
# 根因:_is_timestamp_old只比较时间部分HH:MM:SS,不考虑日期差异
|
||||
# 昨天21:55:31 vs 今天21:55:31差86400秒,但时间部分相同 → 误判为≤300s
|
||||
if has_past_date:
|
||||
logger.debug(f"[ocr] 过滤器1结果: 检测到过去日期(昨天或更早),整段丢弃: {text[:80]!r}")
|
||||
return False
|
||||
# 有新鲜时间戳 → 确定有新消息
|
||||
for ts in timestamps:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user