修复两个问题:
Task #1651: 1. OCR终止无响应修复 - 在_dual_engine的join循环中添加_stop_event检查 - 在ocr_read_qq和ocr_read_wechat的关键time.sleep前添加急停检查 - 确保急停时能立即退出OCR流程 2. 年月日消息过滤优化 - 修改ocr_text_has_fresh_timestamp方法 - 当所有日期都没有时间时,判定为表格日期,剥离后继续处理 - 当混合情况(部分有时间,部分无时间)时,剥离无时间的表格日期 - 只有年月日+时分的消息才会被丢弃 - 仅有年月日的表格消息会剥离后继续处理 测试验证: - 急停响应时间:0.101秒(< 0.5秒) - 年月日消息过滤:5个测试用例全部通过
This commit is contained in:
+35
-3
@@ -3176,14 +3176,14 @@ class MessageMonitor:
|
||||
_t_win.start()
|
||||
_t_easy.start()
|
||||
|
||||
# ⭐ 急停检查:join 期间轮询 _running,急停/停止后立即折返,不等 OCR 结果
|
||||
# ⭐ 急停检查:join 期间轮询 _stop_event 和 _running,急停/停止后立即折返,不等 OCR 结果
|
||||
_deadline = time.time() + _OCR_TIMEOUT
|
||||
while self._running and time.time() < _deadline:
|
||||
while (self._running and not self._stop_event.is_set()) and time.time() < _deadline:
|
||||
if not _t_win.is_alive() and not _t_easy.is_alive():
|
||||
break
|
||||
_t_win.join(0.05)
|
||||
_t_easy.join(0.05)
|
||||
if not self._running:
|
||||
if not self._running or self._stop_event.is_set():
|
||||
logger.debug(f"[{platform}] 双引擎 OCR 期间急停,丢弃未出结果的 OCR")
|
||||
|
||||
# 超时的线程还在跑?记录警告,不阻塞——daemon 线程随进程退出自动回收
|
||||
@@ -3285,6 +3285,9 @@ class MessageMonitor:
|
||||
return []
|
||||
time.sleep(0.1)
|
||||
return []
|
||||
# ⭐ Task #1651: 急停检查:sleep前检查,避免阻塞GUI
|
||||
if not self._running or self._stop_event.is_set():
|
||||
return []
|
||||
time.sleep(0.4)
|
||||
rect = win32gui.GetWindowRect(hwnd)
|
||||
if not rect:
|
||||
@@ -3300,6 +3303,9 @@ class MessageMonitor:
|
||||
if variant == "tim":
|
||||
win32gui.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_END, 0)
|
||||
win32gui.PostMessage(hwnd, win32con.WM_KEYUP, win32con.VK_END, 0)
|
||||
# ⭐ Task #1651: 急停检查
|
||||
if not self._running or self._stop_event.is_set():
|
||||
return []
|
||||
time.sleep(0.3)
|
||||
else:
|
||||
# 点一下消息面板区域设置焦点(QQ NT 默认焦点在会话列表,VK_END 只会滚会话列表)
|
||||
@@ -3310,6 +3316,9 @@ class MessageMonitor:
|
||||
win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lparam)
|
||||
win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, lparam)
|
||||
logger.debug(f"[qq] 点击消息面板({click_x},{click_y})设置焦点")
|
||||
# ⭐ Task #1651: 急停检查
|
||||
if not self._running or self._stop_event.is_set():
|
||||
return []
|
||||
time.sleep(0.15)
|
||||
except Exception as e:
|
||||
logger.debug(f"[qq] 点击消息面板失败: {e}")
|
||||
@@ -3320,12 +3329,18 @@ class MessageMonitor:
|
||||
# 方式A: keybd_event(窗口在前台时生效)
|
||||
ctypes.windll.user32.keybd_event(VK_CONTROL, 0, 0, 0)
|
||||
ctypes.windll.user32.keybd_event(VK_END, 0, 0, 0)
|
||||
# ⭐ Task #1651: 急停检查
|
||||
if not self._running or self._stop_event.is_set():
|
||||
return []
|
||||
time.sleep(0.05)
|
||||
ctypes.windll.user32.keybd_event(VK_END, 0, 2, 0)
|
||||
ctypes.windll.user32.keybd_event(VK_CONTROL, 0, 2, 0)
|
||||
# 方式B: PostMessage 兜底(keybd_event 可能被 TIM 忽略)
|
||||
win32gui.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_END, 0)
|
||||
win32gui.PostMessage(hwnd, win32con.WM_KEYUP, win32con.VK_END, 0)
|
||||
# ⭐ Task #1651: 急停检查
|
||||
if not self._running or self._stop_event.is_set():
|
||||
return []
|
||||
time.sleep(0.3)
|
||||
# TIM/QQ 窗口布局: ~5-30% 左栏, ~30-50% 会话列表(含文档预览), ~50-100% 消息面板
|
||||
# cap_left=25% 继续右移(用户反馈20%仍会捕捉到消息列表的时间戳,干扰消息判定)
|
||||
@@ -3528,6 +3543,9 @@ class MessageMonitor:
|
||||
return []
|
||||
time.sleep(0.1)
|
||||
return []
|
||||
# ⭐ Task #1651: 急停检查:sleep前检查,避免阻塞GUI
|
||||
if not self._running or self._stop_event.is_set():
|
||||
return []
|
||||
time.sleep(0.4) # 让 DWM 完成窗口激活的合成,防紧接 BitBlt 卡死
|
||||
|
||||
rect = win32gui.GetWindowRect(hwnd)
|
||||
@@ -6688,6 +6706,20 @@ class MessageMonitor:
|
||||
# 重新设置 dates 为空,走后续"无日期"逻辑
|
||||
raw_dates = []
|
||||
dates = []
|
||||
elif _dates_without_time > 0 and _dates_with_time > 0:
|
||||
# ⭐ Task #1651: 混合情况:部分日期有时间,部分无时间
|
||||
# 仅有时间戳的日期(年月日+时分)才视为消息时间,仅"年月日"的视为表格日期
|
||||
# 策略:剥离无时间的日期,保留有时间的日期,继续处理
|
||||
logger.debug(f"[ocr] 混合日期:{len(raw_dates)}个日期中有{_dates_with_time}个带时间,{_dates_without_time}个无时间,剥离无时间的表格日期")
|
||||
# 剥离无时间的日期(用空格替换)
|
||||
for _d_match in re.finditer(r'(\d{4}[/-]\d{1,2}[/-]\d{1,2}|\d{4}年\d{1,2}月\d{1,2}日)(?!\s*\d{1,2}:\d{1,2})', text):
|
||||
_date_to_remove = _d_match.group(0)
|
||||
text = text.replace(_date_to_remove, '')
|
||||
# 重新标准化和提取时间戳
|
||||
normalized = self._normalize_timestamps(text)
|
||||
timestamps = re.findall(r'\d{1,2}:\d{1,2}(?::\d{1,2})?', normalized)
|
||||
# 重新提取日期(只保留有时间的日期)
|
||||
raw_dates = re.findall(r'\d{4}[/-]\d{1,2}[/-]\d{1,2}|\d{4}年\d{1,2}月\d{1,2}日', text)
|
||||
raw_dates = [d.replace('-', '/').replace('年', '/').replace('月', '/').replace('日', '') for d in raw_dates]
|
||||
today = datetime.now().date()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user