@
修复3个问题: 1. EasyOCR OOM降级CPU+重启恢复重检内存:_init_easyocr和_ensure_easyocr_subprocess添加内存检测,<2GB强制CPU;start()添加full_restart参数,用户手动启用时重置OOM计数重新评估GPU/CPU 2. PyInstaller exe闪退:spec入口改main.py,main.py添加EASYOCR_WORKER环境变量检测跳转worker逻辑;build.bat只清理build/build和dist不删spec/hooks 3. QQ OCR _processed_path未定义:补充ts和_processed_path变量定义 @
This commit is contained in:
@@ -216,7 +216,8 @@ class MsgBotApp(ctk.CTk):
|
||||
self._log("⚠ 知识库未加载,请先设置知识库路径")
|
||||
self._toggle_btn.deselect()
|
||||
return
|
||||
self.monitor.start()
|
||||
# 用户手动点击启用 → 彻底重启(重新检测内存,尝试恢复GPU)
|
||||
self.monitor.start(full_restart=True)
|
||||
self._status_label.configure(text="▶ 运行中", text_color="#2ecc71")
|
||||
self._log("✅ 消息监控已启动")
|
||||
else:
|
||||
|
||||
@@ -5,6 +5,14 @@ import os
|
||||
import sys
|
||||
import signal
|
||||
|
||||
# ── Worker 模式检测:PyInstaller 打包后,exe 被调用来运行 worker 脚本时,
|
||||
# 通过环境变量区分,避免 bootloader 执行 main() 导致闪退 ──
|
||||
if os.environ.get("EASYOCR_WORKER") == "1":
|
||||
# 直接执行 worker 逻辑,跳过 GUI 初始化
|
||||
import easyocr_worker
|
||||
easyocr_worker._main()
|
||||
sys.exit(0)
|
||||
|
||||
# 确保在项目目录
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
+45
-3
@@ -402,7 +402,13 @@ class MessageMonitor:
|
||||
def set_emergency_callback(self, cb: Callable[[], None]):
|
||||
self._emergency_stop_callback = cb
|
||||
|
||||
def start(self):
|
||||
def start(self, full_restart: bool = False):
|
||||
"""启动监控。
|
||||
|
||||
Args:
|
||||
full_restart: True=彻底重启(进程级,重新检测内存恢复GPU)
|
||||
False=急停/手动停止恢复(软重启,不重新检测内存)
|
||||
"""
|
||||
if self._running:
|
||||
return
|
||||
self._running = True
|
||||
@@ -413,7 +419,16 @@ class MessageMonitor:
|
||||
self._easyocr_retry_until = 0.0 # 清除崩溃冷却
|
||||
self._easyocr_call_count = 0
|
||||
self._easyocr_consecutive_failures = 0 # ⭐ 清除连续超时计数(stop/急停后不残留)
|
||||
self._easyocr_cuda_oom_count = 0 # 重启后重新评估 GPU/CPU
|
||||
|
||||
# ⭐ 彻底重启时重新检测内存,尝试恢复GPU模式
|
||||
# 急停/手动停止恢复时保持上次状态,不重新检测
|
||||
if full_restart:
|
||||
self._easyocr_cuda_oom_count = 0 # 重新评估 GPU/CPU
|
||||
logger.info("[ocr] 彻底重启:重新检测内存,尝试恢复GPU模式")
|
||||
else:
|
||||
# 急停/手动停止恢复:保持上次的降级状态(如果上次因OOM降级CPU,这次仍用CPU)
|
||||
logger.info(f"[ocr] 软重启:保持上次EasyOCR状态(cuda_oom_count={self._easyocr_cuda_oom_count})")
|
||||
|
||||
self._easyocr_proc = None # 确保 clean state
|
||||
# ⭐ OCR 状态清零:截图hash/垃圾计数/引擎选择/冷却等,确保重启不残留上一轮状态
|
||||
# (上次 CUDA 报错降级 CPU 的计数、超时计数、截图指纹都从头开始)
|
||||
@@ -1240,7 +1255,19 @@ class MessageMonitor:
|
||||
# 限制 torch 线程数,避免 MKL/OpenMP 在多线程环境段错误
|
||||
import torch
|
||||
torch.set_num_threads(1)
|
||||
|
||||
# 检测可用内存,决定是否使用GPU
|
||||
use_gpu = torch.cuda.is_available()
|
||||
if use_gpu:
|
||||
mem = psutil.virtual_memory()
|
||||
available_gb = mem.available / (1024**3)
|
||||
# 可用内存 < 2GB 时强制降级CPU,防止OOM崩溃
|
||||
if available_gb < 2.0:
|
||||
logger.warning(f"[ocr] 可用内存不足({available_gb:.1f}GB < 2GB),EasyOCR 降级CPU模式")
|
||||
use_gpu = False
|
||||
else:
|
||||
logger.info(f"[ocr] 可用内存充足({available_gb:.1f}GB),尝试GPU模式")
|
||||
|
||||
self._easyocr_reader = _easyocr.Reader(['ch_sim', 'en'], gpu=use_gpu)
|
||||
if use_gpu:
|
||||
logger.info("[ocr] EasyOCR 就绪(GPU 模式)")
|
||||
@@ -1310,10 +1337,23 @@ class MessageMonitor:
|
||||
_worker_env = dict(os.environ)
|
||||
# ⭐ CUDA_LAUNCH_BLOCKING=1: CUDA 操作同步化,access violation 时只杀子进程不冻整机
|
||||
_worker_env["CUDA_LAUNCH_BLOCKING"] = "1"
|
||||
if self._easyocr_cuda_oom_count >= 2:
|
||||
# ⭐ EASYOCR_WORKER=1: 让 main.py 检测到 worker 模式,跳过 GUI 初始化
|
||||
_worker_env["EASYOCR_WORKER"] = "1"
|
||||
|
||||
# 内存检测:可用内存 < 2GB 时强制CPU模式,防止OOM崩溃
|
||||
try:
|
||||
mem = psutil.virtual_memory()
|
||||
available_gb = mem.available / (1024**3)
|
||||
if available_gb < 2.0:
|
||||
_worker_env["EASYOCR_FORCE_CPU"] = "1"
|
||||
logger.warning(f"[ocr] 可用内存不足({available_gb:.1f}GB),EasyOCR 子进程强制CPU模式")
|
||||
elif self._easyocr_cuda_oom_count >= 2:
|
||||
# ⭐ 连续 CUDA OOM/kernel error → 强制 CPU 模式启动(显存不足时防冻结)
|
||||
_worker_env["EASYOCR_FORCE_CPU"] = "1"
|
||||
logger.warning("[ocr] EasyOCR 连续CUDA错误≥2次,本次强制 CPU 模式启动 worker")
|
||||
except Exception:
|
||||
pass # 获取内存失败不阻断
|
||||
|
||||
self._easyocr_proc = subprocess.Popen(
|
||||
[sys.executable, '-u', worker_path],
|
||||
stdin=subprocess.PIPE,
|
||||
@@ -1867,6 +1907,8 @@ class MessageMonitor:
|
||||
# 保存OCR处理后的图片(JPG格式)用于肉眼对比
|
||||
try:
|
||||
debug_dir = _get_ocr_processed_dir("qq")
|
||||
ts = time.strftime("%Y%m%d_%H%M%S")
|
||||
_processed_path = os.path.join(debug_dir, f"ocr_processed_qq_{ts}.jpg")
|
||||
# 转换为RGB模式保存JPG(不支持RGBA)
|
||||
if im.mode == 'RGBA':
|
||||
im_rgb = im.convert('RGB')
|
||||
|
||||
Reference in New Issue
Block a user