修复EasyOCR CUDA OOM冻结+时间戳day=0崩溃+OCR图片分目录img/raw+processed

- 冻结根因: CUDA OOM后worker不退出, 损坏context持续占显存, 父进程不杀子进程
  反复发图→线程堆积+显存耗尽→桌面冻结
- worker: readtext CUDA/kernel错误→立即退出释放显存(faulerhandler已有兜底)
- 父进程: 收到CUDA错误→立即杀子进程+30s冷却; 连续2次CUDA错误→EASYOCR_FORCE_CPU=1
  强制CPU模式启动(显存不足降级防冻结)
- 时间戳day=0崩溃: _is_timestamp_old跨午夜用replace(day-1), 每月1号day=1→day=0
  抛ValueError day is out of range for month→微信OCR整轮失败; 改用timedelta(days=±1)
- OCR调试图片回源码目录: img/raw(原图PNG) + img/processed(处理后JPG) 分目录存储
- 崩溃日志回源码根 easyocr_crash.log (不写%LOCALAPPDATA%)
- _clean_old_ocr_debug 默认 keep=20 (回退上一轮激进keep=6)
- .gitignore: 忽略 img/ 与 worker_stderr/stdout.txt
This commit is contained in:
youpaishidifu
2026-08-01 22:23:55 +08:00
parent 0405e42a90
commit 4ae189e82f
3 changed files with 76 additions and 42 deletions
+12 -10
View File
@@ -18,18 +18,12 @@ import os
import traceback
from datetime import datetime
# ── 崩溃日志文件:写入 %LOCALAPPDATA%/windowmsgbot/,避开源码目录(防 360 误报 + 父进程方便取) ──
# ── 崩溃日志文件:写入源码目录根(easyocr_crash.log),统一管理、便于父进程读取 ──
def _get_crash_log_path() -> str:
try:
local = os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA")
base = os.path.join(local, "windowmsgbot") if local \
else os.path.join(os.path.expanduser("~"), "windowmsgbot")
except Exception:
base = os.path.dirname(os.path.abspath(__file__))
try:
os.makedirs(base, exist_ok=True)
except Exception:
pass
base = "."
return os.path.join(base, "easyocr_crash.log")
CRASH_LOG = _get_crash_log_path()
@@ -81,10 +75,12 @@ except Exception as e:
def _init_reader():
"""初始化 EasyOCR reader(GPU 优先)。"""
"""初始化 EasyOCR reader(GPU 优先,父进程可强制 CPU)。"""
try:
import torch
use_gpu = torch.cuda.is_available()
# 父进程 EASYOCR_FORCE_CPU=1 → 强制 CPU(显存反复 OOM 时降级,防冻结)
_force_cpu = os.environ.get("EASYOCR_FORCE_CPU") == "1"
use_gpu = (not _force_cpu) and torch.cuda.is_available()
except Exception:
use_gpu = False
@@ -152,6 +148,12 @@ def _main():
sys.stdout.write(out + "\n")
sys.stdout.flush()
except Exception as e:
estr = str(e)
# ⭐ CUDA OOM / kernel error:GPU context 已损坏,继续跑只会反复卡死占显存
# → 立即退出进程释放显存,父进程检测到 stdout 关闭后自动重启/降级 CPU
if "cuda" in estr.lower() or "out of memory" in estr.lower():
_write_crash_log(f"{datetime.now()} [easyocr_worker] CUDA 错误,主动退出释放显存: {estr[:200]}")
_flush_exit(f"CUDA 错误,主动退出释放显存: {estr[:200]}")
out = json.dumps({"ok": False, "error": str(e)}, ensure_ascii=False)
sys.stdout.write(out + "\n")
sys.stdout.flush()