Compare commits

...

2 Commits

Author SHA1 Message Date
wess09
b95ef734ef fix 2026-05-12 21:55:27 +08:00
wess09
73123f9027 feat: implement new configuration system, i18n support, OCR benchmarking, and update dependencies 2026-05-12 21:49:18 +08:00
15 changed files with 74 additions and 41 deletions

View File

@ -468,7 +468,8 @@
"option": [
"auto",
"cpu",
"gpu"
"gpu",
"ane"
]
},
"ScreenshotInterval": {

View File

@ -163,7 +163,7 @@ Error:
Optimization:
OcrDevice:
value: auto
option: [auto, cpu, gpu]
option: [auto, cpu, gpu, ane]
ScreenshotInterval: 0.3
CombatScreenshotInterval: 1.0
TaskHoardingDuration: 0

View File

@ -1,5 +1,7 @@
import copy
import operator
import platform
import sys
import threading
from datetime import datetime, timedelta
@ -186,7 +188,12 @@ class AzurLaneConfig(ConfigUpdater, ManualConfig, GeneratedConfig, ConfigWatcher
def ocr_device(self) -> str:
val = self.Optimization_OcrDevice
if val == 'auto':
if sys.platform == 'darwin' and platform.machine() == 'arm64':
return 'ane'
return 'gpu' if is_good_gpu() else 'cpu'
if val == 'ane' and sys.platform != 'darwin':
logger.warning("当前系统非 macOS不使用 Apple Neural Engine")
return 'cpu'
return val
@property

View File

@ -113,7 +113,7 @@ class GeneratedConfig:
Error_LlmModel = 'Nvidia/qwen/qwen2.5-coder-32b-instruct'
# Group `Optimization`
Optimization_OcrDevice = 'auto' # auto, cpu, gpu
Optimization_OcrDevice = 'auto' # auto, cpu, gpu, ane
Optimization_ScreenshotInterval = 0.3
Optimization_CombatScreenshotInterval = 1.0
Optimization_TaskHoardingDuration = 0

View File

@ -609,9 +609,10 @@
"OcrDevice": {
"name": "Optimization.OcrDevice.name",
"help": "Optimization.OcrDevice.help",
"auto": "auto",
"cpu": "cpu",
"gpu": "gpu"
"auto": "Auto",
"cpu": "CPU",
"gpu": "GPU",
"ane": "ANE (Apple)"
},
"ScreenshotInterval": {
"name": "Slow Down Screenshot Speed to X Seconds per Frame",

View File

@ -607,11 +607,12 @@
"help": ""
},
"OcrDevice": {
"name": "Optimization.OcrDevice.name",
"help": "Optimization.OcrDevice.help",
"auto": "auto",
"cpu": "cpu",
"gpu": "gpu"
"name": "OCR设备选择",
"help": "",
"auto": "自動",
"cpu": "CPU",
"gpu": "GPU",
"ane": "ANE (Apple)"
},
"ScreenshotInterval": {
"name": "スクリーンショット速度をX秒に1枚に減速",

View File

@ -608,10 +608,11 @@
},
"OcrDevice": {
"name": "OCR设备",
"help": "选择OCR设备不推荐任何没有独立显卡的用户使用GPU除非你知道自己在做什么\n非Windows系统目前不支持GPU\n自动选择显存超过1G时使用GPU否则使用CPU",
"help": "选择OCR设备不推荐任何没有独立显卡的用户使用GPU除非你知道自己在做什么\nGPU 仅用于 Windows DirectMLANE 仅用于 macOS Apple Neural Engine\n自动选择Apple Silicon Mac 使用 ANEWindows 显存超过1G时使用GPU否则使用CPU",
"auto": "自动选择",
"cpu": "CPU",
"gpu": "GPU"
"gpu": "GPU",
"ane": "ANE (Apple)"
},
"ScreenshotInterval": {
"name": "放慢截图速度至 X 秒一张",

View File

@ -608,10 +608,11 @@
},
"OcrDevice": {
"name": "OCR设备选择 (´・ω・`)",
"help": "OCR跑在CPU或GPU上。没独显别选GPU喵。自动显存>1G用GPU否则CPU。非Windows无GPU。",
"help": "OCR跑在CPU/GPU/ANE上。GPU仅用于Windows DirectMLANE仅用于macOS Apple Neural Engine。自动Apple Silicon Mac用ANEWindows显存>1G用GPU否则CPU。",
"auto": "自动判断 (`・ω・´)",
"cpu": "CPU喵",
"gpu": "GPU喵"
"gpu": "GPU喵",
"ane": "ANE (Apple)喵"
},
"ScreenshotInterval": {
"name": "放慢截图至 X 秒一张 (´-ω-`)zzz",

View File

@ -610,8 +610,9 @@
"name": "Optimization.OcrDevice.name",
"help": "Optimization.OcrDevice.help",
"auto": "auto",
"cpu": "cpu",
"gpu": "gpu"
"cpu": "CPU",
"gpu": "GPU",
"ane": "ANE (Apple)"
},
"ScreenshotInterval": {
"name": "放慢截圖速度至 X 秒一張",

View File

@ -1,23 +1,33 @@
import os
import platform
import shutil
import sys
import time
import cv2
from rich.table import Table
from rich.text import Text
from module.daemon.daemon_base import DaemonBase
from module.config.config import AzurLaneConfig
from module.exception import RequestHumanTakeover
from module.logger import logger
from module.ocr.al_ocr import AlOcr
class OcrBenchmark(DaemonBase):
class OcrBenchmark:
# Each entry: (model_name, dataset_prefix, subfolder_name)
BENCHMARKS = [
('en', 'sets_num', 'sets_num'),
('cn', 'sets_zhcn', 'sets_zhcn'),
]
def __init__(self, config, device=None, task=None):
if isinstance(config, AzurLaneConfig):
self.config = config
if task is not None:
self.config.init_task(task)
else:
self.config = AzurLaneConfig(config, task=task)
def _find_archive(self, prefix):
for ext in ['.zip', '.tar', '.tar.xz', '.tar.gz']:
path = f'module/daemon/{prefix}{ext}'
@ -54,12 +64,14 @@ class OcrBenchmark(DaemonBase):
if avg_ms < 300.0: return 'Very Slow', 'red'
return 'Ultra Slow', 'bold red'
def _run_single(self, model_name, dataset_prefix, subfolder, use_gpu=None):
def _run_single(self, model_name, dataset_prefix, subfolder, use_gpu=None, ocr_device=None):
logger.hr(f'Benchmark: {model_name.upper()} model | dataset: {dataset_prefix}', level=2)
# --- Dynamic GPU config ---
if use_gpu is not None:
self.config.override(Optimization_OcrDevice='gpu' if use_gpu else 'cpu')
# --- Dynamic OCR device config ---
if ocr_device is None and use_gpu is not None:
ocr_device = 'gpu' if use_gpu else 'cpu'
if ocr_device is not None:
self.config.override(Optimization_OcrDevice=ocr_device)
from module.ocr.al_ocr import reset_ocr_model
reset_ocr_model()
@ -215,17 +227,22 @@ class OcrBenchmark(DaemonBase):
def run_simple_ocr_benchmark(self):
"""
Returns:
str: 'gpu' if accuracy is 100% on a simple test set, else 'cpu'.
str: Best OCR device for this machine.
"""
logger.hr('Simple OCR Benchmark', level=1)
logger.info('Testing OCR with GPU...')
res = self._run_single('en', 'sets_num', 'sets_num', use_gpu=True)
if sys.platform == 'darwin' and platform.machine() == 'arm64':
logger.info('Testing OCR with ANE...')
device = 'ane'
else:
logger.info('Testing OCR with GPU...')
device = 'gpu'
res = self._run_single('en', 'sets_num', 'sets_num', ocr_device=device)
if res and res['accuracy'] >= 100.0:
logger.info('OCR accuracy is 100% with GPU, use GPU.')
return 'gpu'
logger.info(f'OCR accuracy is 100% with {device.upper()}, use {device.upper()}.')
return device
else:
logger.info('OCR accuracy is not 100% with GPU or test failed, fallback to CPU.')
logger.info(f'OCR accuracy is not 100% with {device.upper()} or test failed, fallback to CPU.')
return 'cpu'
@ -235,4 +252,4 @@ def run_ocr_benchmark(config):
return True
except RequestHumanTakeover:
logger.critical('错误 请求人类接管')
return False
return False

View File

@ -111,6 +111,7 @@ class RecOnlyOCR(RapidOCR):
self.use_rec = cfg.Global.use_rec
cfg.Rec.engine_cfg = cfg.EngineConfig[cfg.Rec.engine_type.value]
cfg.Rec.font_path = cfg.Global.font_path
cfg.Rec.model_root_dir = cfg.Global.get("model_root_dir", os.getcwd())
self.text_rec = TextRecognizer(cfg.Rec)
self.load_img = LoadImage()
@ -124,7 +125,9 @@ class RecOnlyOCR(RapidOCR):
def _create_ocr(model_path, rec_keys_path, ocr_version):
use_gpu = config.ocr_device == 'gpu'
ocr_device = config.ocr_device
use_dml = os.name == 'nt' and ocr_device == 'gpu'
use_coreml = ocr_device == 'ane'
params = {
"Global.use_det": False,
"Global.use_cls": False,
@ -133,7 +136,9 @@ def _create_ocr(model_path, rec_keys_path, ocr_version):
"Rec.ocr_version": ocr_version,
"Rec.model_path": model_path,
"Rec.rec_keys_path": rec_keys_path,
"EngineConfig.onnxruntime.use_dml": use_gpu,
"EngineConfig.onnxruntime.use_dml": use_dml,
"EngineConfig.onnxruntime.use_coreml": use_coreml,
"EngineConfig.onnxruntime.coreml_ep_cfg.MLComputeUnits": "CPUAndNeuralEngine",
}
return RecOnlyOCR(params=params)

View File

@ -31,8 +31,8 @@ typing_extensions>=4.8.0
pydantic>=2.5.0
rapidocr
onnxruntime-directml>=1.24.4; sys_platform == "win32"
onnxruntime>=1.24.4; sys_platform == "linux"
onnxruntime @ https://files.pythonhosted.org/packages/fb/aa/04530bd38e31e26970fa1212346d76cf81705dc16a8ee5e6f4fb24634c11/onnxruntime-1.25.1-cp314-cp314-macosx_14_0_arm64.whl; sys_platform == "darwin" and platform_machine == "arm64"
onnxruntime==1.26.0; sys_platform == "linux"
onnxruntime @ https://files.pythonhosted.org/packages/40/89/17546c1c20f6bfc3ae41c22152378a26edfea918af3129e2139dcd7c99f3/onnxruntime-1.26.0-cp314-cp314-macosx_14_0_arm64.whl; sys_platform == "darwin" and platform_machine == "arm64"
watchdog>=2.0.0
numba
pip

View File

@ -1,5 +1,5 @@
# This file was autogenerated by uv via the following command:
# uv pip compile requirements-in.txt --python-platform linux --python-version 3.14 --annotation-style=line --no-emit-index-url --output-file requirements-linux.txt
# uv pip compile requirements-in.txt --annotation-style=line --python-platform linux --python-version 3.14 --output-file requirements-linux.txt
adbutils==0.11.0 # via uiautomator2, -r requirements-in.txt
aiofiles==23.1.0 # via -r requirements-in.txt
annotated-types==0.7.0 # via pydantic
@ -52,13 +52,12 @@ lxml==6.1.0 # via uiautomator2
lz4==4.4.5 # via -r requirements-in.txt
matplotlib==3.10.8 # via -r requirements-in.txt
mcp==1.23.0 # via -r requirements-in.txt
mpmath==1.3.0 # via sympy
msgpack==1.0.4 # via zerorpc
numba==0.64.0 # via -r requirements-in.txt
numpy==2.4.3 # via contourpy, imageio, matplotlib, numba, onnxruntime, opencv-python, rapidocr, scipy, shapely, -r requirements-in.txt
omegaconf==2.3.0 # via rapidocr
onepush==1.2.0 # via -r requirements-in.txt
onnxruntime==1.24.4 # via -r requirements-in.txt
onnxruntime==1.26.0 # via -r requirements-in.txt
openai==2.30.0 # via -r requirements-in.txt
opencv-python==4.13.0.92 # via rapidocr, -r requirements-in.txt
packaging==20.9 # via deprecation, matplotlib, onnxruntime, uiautomator2
@ -99,7 +98,6 @@ six==1.16.0 # via adbutils, python-dateutil, rapidocr, retrying, u
sniffio==1.3.0 # via openai
sse-starlette==3.0.3 # via mcp, -r requirements-in.txt
starlette==0.49.1 # via mcp, -r requirements-in.txt
sympy==1.14.0 # via onnxruntime
tornado==6.5.5 # via pywebio
tqdm==4.67.3 # via openai, rapidocr
typing-extensions==4.15.0 # via mcp, openai, pydantic, pydantic-core, typing-inspection, -r requirements-in.txt

View File

@ -1,5 +1,5 @@
# This file was autogenerated by uv via the following command:
# uv pip compile requirements-in.txt --annotation-style=line --python-platform aarch64-apple-darwin --python-version 3.14 --output-file requirements-macos.txt
# uv pip compile requirements-in.txt --annotation-style=line --python-platform macos --python-version 3.14 --output-file requirements-macos.txt
adbutils==0.16.2 # via uiautomator2, -r requirements-in.txt
aiofiles==25.1.0 # via -r requirements-in.txt
annotated-types==0.7.0 # via pydantic
@ -56,7 +56,7 @@ numba==0.65.0 # via -r requirements-in.txt
numpy==2.4.4 # via contourpy, imageio, matplotlib, numba, onnxruntime, opencv-python, rapidocr, scipy, shapely, -r requirements-in.txt
omegaconf==2.3.0 # via rapidocr
onepush==1.8.0 # via -r requirements-in.txt
onnxruntime @ https://files.pythonhosted.org/packages/fb/aa/04530bd38e31e26970fa1212346d76cf81705dc16a8ee5e6f4fb24634c11/onnxruntime-1.25.1-cp314-cp314-macosx_14_0_arm64.whl # via -r requirements-in.txt
onnxruntime @ https://files.pythonhosted.org/packages/40/89/17546c1c20f6bfc3ae41c22152378a26edfea918af3129e2139dcd7c99f3/onnxruntime-1.26.0-cp314-cp314-macosx_14_0_arm64.whl # via -r requirements-in.txt
openai==2.31.0 # via -r requirements-in.txt
opencv-python==4.13.0.92 # via rapidocr, -r requirements-in.txt
packaging==20.9 # via deprecation, matplotlib, onnxruntime, uiautomator2

View File

@ -1,5 +1,5 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --annotation-style=line --no-emit-index-url --output-file=requirements.txt --resolver=backtracking requirements-in.txt
# uv pip compile requirements-in.txt --annotation-style=line --python-platform windows --python-version 3.14 --output-file requirements.txt
adbutils==0.11.0 # via uiautomator2, -r requirements-in.txt
aiofiles==23.1.0 # via -r requirements-in.txt
annotated-types==0.7.0 # via pydantic