From 09ea05fc7942e5e91287a0a14b3fc29538b93135 Mon Sep 17 00:00:00 2001 From: youpaishidifu Date: Sat, 8 Aug 2026 22:14:02 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20EasyOCR=E5=90=AF=E5=8A=A8=E5=BC=82?= =?UTF-8?q?=E5=B8=B8+=E8=B6=85=E6=97=B6=E4=BF=9D=E6=8A=A4+=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=90=85=E5=92=8C=E9=9A=94=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 修复负冷却时间bug:启动失败时若未设置冷却,现在设置30s冷却 2. EasyOCR worker添加超时保护:readtext()使用concurrent.futures包装,30s超时 3. Windows OCR消息搅和隔离:EasyOCR超时+Windows OCR多时间戳→返回空结果 4. 添加easyocr_worker_state.json到.gitignore --- .gitignore | 1 + easyocr_worker.py | 24 +++++++++++++++++++++--- monitor.py | 12 ++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 085e3fc..81f98e7 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,4 @@ test_*.txt _radical_*.txt unicode_radicals.md.bak easyocr_worker_state.json +easyocr_worker_state.json diff --git a/easyocr_worker.py b/easyocr_worker.py index 4b8f12a..8c8438f 100644 --- a/easyocr_worker.py +++ b/easyocr_worker.py @@ -286,8 +286,10 @@ def _init_reader(): return reader -def _process_image(img_b64: str, reader) -> str: - """解码 base64 图片 → EasyOCR 识别 → 返回空格拼接文本。""" +def _process_image(img_b64: str, reader, timeout: float = 30.0) -> str: + """解码 base64 图片 → EasyOCR 识别 → 返回空格拼接文本。 + timeout: 单张图片OCR超时秒数,防止GPU/CPU推理卡死。 + """ if reader is None: return "" raw = base64.b64decode(img_b64) @@ -296,7 +298,23 @@ def _process_image(img_b64: str, reader) -> str: if img.mode != "RGBA": img = img.convert("RGBA") img_np = np.array(img) - results = reader.readtext(img_np) + + # ⭐ 超时保护:用 concurrent.futures 包装 readtext,防止GPU推理卡死 + from concurrent.futures import ThreadPoolExecutor, TimeoutError as FuturesTimeoutError + with ThreadPoolExecutor(max_workers=1) as executor: + future = executor.submit(reader.readtext, img_np) + try: + results = future.result(timeout=timeout) + except FuturesTimeoutError: + sys.stderr.write(f"[easyocr_worker] readtext 超时({timeout}s),放弃本次OCR\n") + sys.stderr.flush() + _write_crash_log(f"{datetime.now()} [easyocr_worker] readtext 超时({timeout}s)") + return "" + except Exception as e: + sys.stderr.write(f"[easyocr_worker] readtext 异常: {e}\n") + sys.stderr.flush() + raise + return "\n".join([r[1] for r in results]).strip() diff --git a/monitor.py b/monitor.py index b5150ac..003e659 100644 --- a/monitor.py +++ b/monitor.py @@ -2030,6 +2030,9 @@ class MessageMonitor: # 重置计数器(冷却后重试重新计数) self._easyocr_consecutive_startup_failures = 0 else: + # ⭐ 短冷却:未达阈值时也设30s冷却,避免反复启动失败刷屏 + if self._easyocr_retry_until <= time.time(): + self._easyocr_retry_until = time.time() + 30 logger.debug(f"[ocr] EasyOCR 第{self._easyocr_consecutive_startup_failures}次启动失败," f"冷却({int(self._easyocr_retry_until - time.time())}s)") return None @@ -2421,6 +2424,15 @@ class MessageMonitor: wt = win_text[0] et = easy_text[0] + # ⭐ EasyOCR超时+Windows OCR混合消息检测:当EasyOCR超时且Windows OCR结果包含 + # 多个时间戳(表明是多条消息混合),返回空结果,避免消息搅和 + if not et and wt: + timestamps = re.findall(r'\d{1,2}:\d{1,2}', wt) + if len(timestamps) >= 2: + logger.warning(f"[{platform}] EasyOCR超时+Windows OCR检测到{len(timestamps)}个时间戳" + f"({timestamps[:3]}...),疑似消息混合,跳过本轮避免搅和") + return ("", "") + # 日志(原始输出逐行记录,用於長期對比兩引擎能力) if wt: for i, l in enumerate(wt.split('\n')):