fix: EasyOCR启动异常+超时保护+消息搅和隔离

1. 修复负冷却时间bug:启动失败时若未设置冷却,现在设置30s冷却
2. EasyOCR worker添加超时保护:readtext()使用concurrent.futures包装,30s超时
3. Windows OCR消息搅和隔离:EasyOCR超时+Windows OCR多时间戳→返回空结果
4. 添加easyocr_worker_state.json到.gitignore
This commit is contained in:
youpaishidifu
2026-08-08 22:14:02 +08:00
parent c300a1fd18
commit 09ea05fc79
3 changed files with 34 additions and 3 deletions
+1
View File
@@ -72,3 +72,4 @@ test_*.txt
_radical_*.txt
unicode_radicals.md.bak
easyocr_worker_state.json
easyocr_worker_state.json
+21 -3
View File
@@ -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()
+12
View File
@@ -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')):