Files
post-ocr/build_exe.py
let5sne.win10 86cb704eae fix: 解决打包后三个运行时问题
- rthook_paddle.py: stub paddle.utils.cpp_extension,避免Cython缺文件崩溃
- build_exe.py: 显式收集paddle DLLs(mklml.dll等)
- ocr_offline.py: 非ASCII路径自动复制模型到临时目录,绕过PaddlePaddle C++路径限制

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 20:31:28 +08:00

110 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
打包脚本 - 将桌面程序打包成可离线分发的目录包
使用方法: python build_exe.py [--debug]
产出: dist/信封信息提取系统/
├── 信封信息提取系统.exe
├── _internal/ (运行时依赖)
└── models/ (OCR 模型,需提前通过 prepare_models.py 准备)
"""
import os
import subprocess
import sys
import shutil
from pathlib import Path
PROJECT_ROOT = Path(__file__).parent
DIST_NAME = "信封信息提取系统"
# paddle DLLs 所在目录mklml.dll 等不会被 PyInstaller 自动收集)
import paddle as _paddle
PADDLE_LIBS = str(Path(_paddle.__file__).parent / "libs")
def build(debug=False):
"""使用 PyInstaller 打包onedir 模式)"""
print("正在打包,请稍候...")
print(f"工作目录: {PROJECT_ROOT}")
print(f"模式: {'调试(带控制台)' if debug else '正式(无控制台)'}")
print("-" * 50)
cmd = [
sys.executable,
"-m", "PyInstaller",
f"--name={DIST_NAME}",
"--onedir",
"--noconfirm",
"--paths=src",
# --- hidden imports ---
"--hidden-import=cv2",
"--hidden-import=PIL",
"--hidden-import=processor",
"--hidden-import=ocr_offline",
"--hidden-import=paddleocr",
"--hidden-import=paddle",
# --- paddle DLLsmklml.dll 等不会被自动收集) ---
f"--add-binary={PADDLE_LIBS}/*.dll{os.pathsep}paddle/libs",
# --- runtime hook: stub 掉 paddle 开发模块,避免 Cython 缺文件崩溃 ---
"--runtime-hook=rthook_paddle.py",
# --- 收集 paddleocr 全部数据(模型配置、字典等) ---
"--collect-all=paddleocr",
# --- 元数据(部分库在运行时通过 importlib.metadata 查版本) ---
"--copy-metadata=paddlepaddle",
"--copy-metadata=paddleocr",
]
if not debug:
cmd.append("--windowed")
else:
cmd.append("--console")
cmd.append("src/desktop.py")
try:
subprocess.run(cmd, check=True, cwd=str(PROJECT_ROOT))
except subprocess.CalledProcessError as e:
print("-" * 50)
print(f"打包失败: {e}")
sys.exit(1)
except FileNotFoundError:
print("-" * 50)
print("错误: 未找到 PyInstaller请先安装: pip install pyinstaller")
sys.exit(1)
print("-" * 50)
# 复制 models/ 到输出目录(与 exe 同级)
dist_dir = PROJECT_ROOT / "dist" / DIST_NAME
models_src = PROJECT_ROOT / "models"
models_dst = dist_dir / "models"
if models_src.exists() and any(models_src.rglob("*.pdmodel")):
print(f"复制离线模型: {models_src} -> {models_dst}")
if models_dst.exists():
shutil.rmtree(models_dst)
shutil.copytree(models_src, models_dst)
else:
print("⚠️ 未找到离线模型。请先执行:")
print(" python scripts/prepare_models.py --models-dir models")
print(" 然后重新打包,或手动将 models/ 放到 dist 目录中。")
# 统计大小
exe_path = dist_dir / f"{DIST_NAME}.exe"
if exe_path.exists():
folder_size = sum(
f.stat().st_size for f in dist_dir.rglob("*") if f.is_file()
) / 1024 / 1024
print(f"\n打包完成!")
print(f"输出目录: {dist_dir}")
print(f"总大小: {folder_size:.1f} MB")
print(f"\n分发方式: 将 {dist_dir.name}/ 整个文件夹打成 zip 即可。")
else:
print("警告: 未找到输出的 exe 文件")
if __name__ == "__main__":
debug = "--debug" in sys.argv
build(debug=debug)