fix: 修复时间戳继承、补分DB检查、OCR急停、SequenceMatcher作用域问题 (Task #1661-1663)
- Task #1661: OCR时间戳丢失时无时间戳消息继承前驱时间戳新鲜度 - Task #1662: 补分逻辑三重DB检查,DB不存在时跳过补分 - Task #1663: OCR readline循环添加_stop_event检查,支持急停 - 修复SequenceMatcher局部导入导致的UnboundLocalError
This commit is contained in:
+49
-9
@@ -848,6 +848,20 @@ class MessageHistory:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def has_any_records_for_platform(self, platform: str) -> bool:
|
||||
"""检查该平台在DB中是否有任何消息记录(用于补分逻辑判断)"""
|
||||
self._ensure_ocr_staging_table()
|
||||
conn = self._get_conn()
|
||||
try:
|
||||
cursor = conn.execute(
|
||||
"SELECT COUNT(*) FROM ocr_staging WHERE platform=?",
|
||||
(platform,)
|
||||
)
|
||||
count = cursor.fetchone()[0]
|
||||
return count > 0
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
class MessageMonitor:
|
||||
"""多线程消息监控器"""
|
||||
@@ -2934,17 +2948,17 @@ class MessageMonitor:
|
||||
pass
|
||||
_t = threading.Thread(target=_read_worker, daemon=True)
|
||||
_t.start()
|
||||
# ⭐ 急停检查:轮询 _running,急停后立即放弃等待(丢弃未出结果的 OCR)
|
||||
# ⭐ 急停检查:轮询 _running 和 _stop_event,急停后立即放弃等待(丢弃未出结果的 OCR)
|
||||
_deadline = time.time() + timeout
|
||||
line = None
|
||||
while self._running and time.time() < _deadline:
|
||||
while self._running and not self._stop_event.is_set() and time.time() < _deadline:
|
||||
try:
|
||||
line = _q.get(timeout=0.05)
|
||||
break
|
||||
except _QueueEmpty:
|
||||
continue
|
||||
if line is None:
|
||||
if not self._running:
|
||||
if not self._running or self._stop_event.is_set():
|
||||
logger.debug("[ocr] EasyOCR 等待期间急停,丢弃未出结果的 OCR 请求")
|
||||
else:
|
||||
self._easyocr_consecutive_failures += 1
|
||||
@@ -7379,14 +7393,17 @@ class MessageMonitor:
|
||||
# 从文本中提取时间戳
|
||||
timestamps = re.findall(r'\d{1,2}:\d{1,2}(?::\d{1,2})?', text)
|
||||
if not timestamps:
|
||||
return 0.0
|
||||
# ⭐ Task #1661: 无时间戳返回特殊值-999.0,区分"无时间戳"与"有时间戳但较旧"
|
||||
# 调用方据此判断:无时间戳→不补分、视为陈旧消息
|
||||
return -999.0
|
||||
|
||||
# 取最后一个时间戳(通常是最新消息的时间戳)
|
||||
ts_str = timestamps[-1]
|
||||
age_seconds = self._timestamp_age_seconds(ts_str)
|
||||
|
||||
if age_seconds is None:
|
||||
return 0.0
|
||||
# 时间戳解析失败也视为无有效时间戳
|
||||
return -999.0
|
||||
|
||||
# 根据时间差给分(越接近得分越高)
|
||||
if age_seconds <= 300: # 5分钟内
|
||||
@@ -9836,12 +9853,28 @@ class MessageMonitor:
|
||||
new_items = []
|
||||
# ⭐ 时间戳新鲜度评分:在关键词打分和查重之前计算,作为加分项
|
||||
freshness_scores = {} # 存储每条消息的时间戳新鲜度分数
|
||||
# ⭐ Task #1661: 维护上一条带合法时间戳消息的新鲜度,供无时间戳消息继承
|
||||
# QQ/微信中用户连发多条消息时,仅首条带时间戳,后续紧邻消息无时间戳
|
||||
# 无时间戳消息继承前驱时间戳新鲜度 → 同批次消息共享时间上下文,避免误处理旧消息
|
||||
_last_ts_freshness = None # 上一条带合法时间戳消息的新鲜度分数
|
||||
_last_ts_text = None # 上一条带合法时间戳消息的文本(仅日志用)
|
||||
for t in texts:
|
||||
ts = t.strip()
|
||||
if not ts:
|
||||
continue
|
||||
# 计算时间戳新鲜度分数(作为后续综合得分的加分项)
|
||||
freshness_score = self._timestamp_freshness_score(ts)
|
||||
# ⭐ Task #1661: 无时间戳(-999.0) → 继承同批次紧邻前驱消息的时间戳新鲜度
|
||||
if freshness_score == -999.0:
|
||||
if _last_ts_freshness is not None:
|
||||
logger.debug(f"[{platform}] 无时间戳消息继承前驱时间戳新鲜度 "
|
||||
f"({_last_ts_text[:20]!r}→{ts[:20]!r}): {_last_ts_freshness:.1f}")
|
||||
freshness_score = _last_ts_freshness
|
||||
# else: 整批都无时间戳,保持-999.0(保守,不补分、扣10分过滤)
|
||||
else:
|
||||
# 有合法时间戳:更新前驱状态,供后续无时间戳消息继承
|
||||
_last_ts_freshness = freshness_score
|
||||
_last_ts_text = ts
|
||||
# 存储原始文本和新鲜度分数
|
||||
freshness_scores[ts] = freshness_score
|
||||
# === URL-only 兜底:无中文且含 URL → 碎片 ===
|
||||
@@ -10531,6 +10564,11 @@ class MessageMonitor:
|
||||
old_score = score
|
||||
score = max(score + 5.0, 5.0)
|
||||
logger.info(f"[{platform}] 时间戳新鲜度≥5直接放行(+5): {old_score:.1f}→{score:.1f}: {item[:50]}")
|
||||
elif freshness_score == -999.0:
|
||||
# ⭐ Task #1661: 无有效时间戳(OCR丢失或解析失败)
|
||||
# 不补分、直接扣分为负,避免旧消息因"DB无记录"误获补分
|
||||
score -= 10.0
|
||||
logger.info(f"[{platform}] 无有效时间戳(OCR丢失?)扣10分: {score:.1f}: {item[:50]}")
|
||||
elif freshness_score < 0:
|
||||
# 负分(超过1小时):扣10分
|
||||
score += freshness_score # 加上负分 = 扣分
|
||||
@@ -10540,11 +10578,14 @@ class MessageMonitor:
|
||||
if self._msg_history and self._msg_history.has_ocr_message_record(platform, cleaned_item):
|
||||
# DB有记录:不加分
|
||||
logger.info(f"[{platform}] 时间戳新鲜度<5且DB有记录,不加分: {item[:50]}")
|
||||
else:
|
||||
# DB无记录:补分到5(确保最终分数至少为5,不因负基础分而被丢弃)
|
||||
elif self._msg_history and self._msg_history.has_any_records_for_platform(platform):
|
||||
# DB存在但该消息无记录:补分到5(确保最终分数至少为5,不因负基础分而被丢弃)
|
||||
old_score = score
|
||||
score = max(score + 5.0, 5.0)
|
||||
logger.info(f"[{platform}] 时间戳新鲜度<5且DB无记录,补分到5: {old_score:.1f}→{score:.1f}: {item[:50]}")
|
||||
else:
|
||||
# ⭐ Task #1662: DB不存在或无记录时跳过,不加分(避免旧消息因补分逻辑被误处理)
|
||||
logger.info(f"[{platform}] 时间戳新鲜度<5且DB无记录/不存在,跳过补分: {item[:50]}")
|
||||
|
||||
# ⭐ 检查分数是否>0:分数<=0的消息不应被处理
|
||||
if score <= 0:
|
||||
@@ -10601,8 +10642,7 @@ class MessageMonitor:
|
||||
)
|
||||
_is_same_round_dup = True
|
||||
break
|
||||
# 高相似度匹配
|
||||
from difflib import SequenceMatcher
|
||||
# 高相似度匹配(SequenceMatcher 已在文件头全局导入)
|
||||
sim = SequenceMatcher(None, sk_cur, sk_prev).ratio()
|
||||
if sim >= 0.7:
|
||||
logger.info(
|
||||
|
||||
Reference in New Issue
Block a user