- easyocr_worker.py: 初始化完成后输出{"ready":true}握手, 父进程不再把3-10s初始化计入10s请求超时
- monitor.py: _ensure_easyocr_subprocess重写 - 60s握手预算(daemon线程+Queue), stderr PIPE捕获崩溃原因, 崩溃/超时改30s冷却自动重试(不再永久broken)
- monitor.py: 删除markdown表格字符key偏旁库, 改U+2E80-U+2FDF码位范围判断, 修复"地图"/"太"等正常汉字被误判为偏旁丢弃
- monitor.py: _looks_fresh_content新鲜特征判断 - 旧时间戳但含疑问词/问句/句尾标点的消息放行, 不再整块丢弃
- 新增test_easyocr_handshake.py: 子进程握手+OCR往返回归测试(实测通过: 28s含初始化, 识别'你好世界测试123')
111 lines
3.4 KiB
Python
111 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""测试 easyocr_worker 子进程 ready 握手 + OCR 请求往返。
|
|
|
|
模拟 monitor.py 父进程行为:
|
|
1. 启动 easyocr_worker.py 子进程
|
|
2. 等待 {"ready": true} 握手(90s 预算,覆盖 3-10s torch+模型加载)
|
|
3. 发一张含中文的测试图,验证 OCR 结果
|
|
"""
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
import os
|
|
import base64
|
|
import io
|
|
import threading
|
|
from queue import Queue, Empty
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
|
|
def main():
|
|
# ── 1. 生成测试图(白底黑字中文) ──
|
|
img = Image.new("RGB", (500, 120), "white")
|
|
d = ImageDraw.Draw(img)
|
|
try:
|
|
font = ImageFont.truetype("C:/Windows/Fonts/msyh.ttc", 32)
|
|
except Exception:
|
|
font = ImageFont.load_default()
|
|
d.text((20, 40), "你好世界 测试123", fill="black", font=font)
|
|
buf = io.BytesIO()
|
|
img.save(buf, format="PNG")
|
|
img_b64 = base64.b64encode(buf.getvalue()).decode()
|
|
print(f"[test] 测试图生成 OK, b64长度={len(img_b64)}", flush=True)
|
|
|
|
worker_path = os.path.join(
|
|
os.path.dirname(os.path.abspath(__file__)), "easyocr_worker.py"
|
|
)
|
|
print(f"[test] worker路径: {worker_path}", flush=True)
|
|
|
|
# ── 2. 启动子进程 ──
|
|
proc = subprocess.Popen(
|
|
[sys.executable, "-u", worker_path],
|
|
stdin=subprocess.PIPE,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
text=True,
|
|
bufsize=1,
|
|
)
|
|
print(f"[test] 子进程已启动 pid={proc.pid}", flush=True)
|
|
|
|
def _read_line(pipe, q):
|
|
try:
|
|
q.put(pipe.readline())
|
|
except Exception as e:
|
|
q.put(f"__READ_ERR__:{e}")
|
|
|
|
# ── 3. 等待 ready 握手(90s 预算) ──
|
|
q = Queue()
|
|
t = threading.Thread(target=_read_line, args=(proc.stdout, q), daemon=True)
|
|
t.start()
|
|
try:
|
|
line = q.get(timeout=90)
|
|
except Empty:
|
|
print("[test] FAIL: ready 握手 90s 超时", flush=True)
|
|
proc.kill()
|
|
return 1
|
|
print(f"[test] 握手响应: {line.strip()!r}", flush=True)
|
|
try:
|
|
payload = json.loads(line)
|
|
assert payload.get("ready") is True, f"非 ready 响应: {line!r}"
|
|
except Exception as e:
|
|
err = proc.stderr.read()[:1500]
|
|
print(f"[test] FAIL: 握手解析异常 {e}, stderr={err!r}", flush=True)
|
|
proc.kill()
|
|
return 1
|
|
print("[test] PASS: ready 握手成功", flush=True)
|
|
|
|
# ── 4. 发送 OCR 请求 ──
|
|
proc.stdin.write(json.dumps({"img": img_b64}) + "\n")
|
|
proc.stdin.flush()
|
|
|
|
q2 = Queue()
|
|
t2 = threading.Thread(target=_read_line, args=(proc.stdout, q2), daemon=True)
|
|
t2.start()
|
|
try:
|
|
rline = q2.get(timeout=30)
|
|
except Empty:
|
|
print("[test] FAIL: OCR 请求 30s 超时", flush=True)
|
|
proc.kill()
|
|
return 1
|
|
print(f"[test] OCR 响应: {rline.strip()!r}", flush=True)
|
|
try:
|
|
res = json.loads(rline)
|
|
assert res.get("ok"), f"OCR 失败: {res}"
|
|
print(f"[test] OCR 文本: {res['text']!r}", flush=True)
|
|
assert "你好" in res["text"] or "测试" in res["text"], "识别结果缺中文"
|
|
except Exception as e:
|
|
print(f"[test] FAIL: OCR 结果异常 {e}", flush=True)
|
|
proc.kill()
|
|
return 1
|
|
|
|
# ── 5. 诊断信息 ──
|
|
proc.kill()
|
|
proc.wait(timeout=3)
|
|
print("[test] PASS: easyocr 子进程 ready 握手 + OCR 请求往返全部成功", flush=True)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|