Files
msgbot/test_easyocr_handshake.py
T
youpaishidifu ba0e6e2450 修复3个OCR问题: easyocr子进程ready握手+60s初始化预算, 偏旁过滤改Unicode范围判断, 新旧消息按新鲜特征放行
- 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')
2026-08-01 13:00:57 +08:00

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())