# -*- mode: python ; coding: utf-8 -*- import os from pathlib import Path from PyInstaller.utils.hooks import collect_data_files, collect_submodules from PyInstaller.utils.win32.versioninfo import ( FixedFileInfo, StringFileInfo, StringStruct, StringTable, VarFileInfo, VarStruct, VSVersionInfo, ) project_root = Path(SPECPATH) app_version = os.environ.get("WECOM_BUILD_VERSION", "1.0.0").strip() or "1.0.0" app_name = f"ZhenAI-WeCom-Assistant-v{app_version}" # 完整的版本信息资源。没有它,EXE 在杀软启发式评分和 SmartScreen 提示里 # 就是一个"来历不明"的匿名程序;有了它至少提示里能显示发布者与产品名。 _version_parts = [int(p) for p in (app_version.split(".") + ["0", "0", "0"])[:4]] version_resource = VSVersionInfo( ffi=FixedFileInfo( filevers=tuple(_version_parts), prodvers=tuple(_version_parts), ), kids=[ StringFileInfo( [ StringTable( "080404b0", [ StringStruct("CompanyName", "甄养堂"), StringStruct("FileDescription", "甄AI客服 · 企业微信客服助手"), StringStruct("FileVersion", app_version), StringStruct("InternalName", app_name), StringStruct("LegalCopyright", "Copyright (C) 2026 甄养堂"), StringStruct("OriginalFilename", f"{app_name}.exe"), StringStruct("ProductName", "甄AI客服"), StringStruct("ProductVersion", app_version), ], ) ] ), VarFileInfo([VarStruct("Translation", [2052, 1200])]), ], ) hidden_imports = [ "app_version", "backend_client", "conversation_store", "dsh_agent", "gui_runtime", "mcp_bridge", "registration_store", "runtime_paths", "wechat_gui", "wechat_gui_qt", "PySide6.QtWebEngineCore", "PySide6.QtWebEngineWidgets", ] hidden_imports += collect_submodules("mcp") a = Analysis( [str(project_root / "app_main.py")], pathex=[str(project_root)], binaries=[], datas=[ (str(project_root / "edge_light_theme"), "edge_light_theme"), (str(project_root / "assets" / "brand"), "assets/brand"), (str(project_root / "dsh_desk.cordis.yml"), "."), ] # 昵称 OCR 的模型与配置:只收代码不收这些文件的话,打包后 RapidOCR # 初始化直接失败,会话身份静默退化。 + collect_data_files("rapidocr_onnxruntime"), hiddenimports=hidden_imports, hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=["PyQt5", "PyQt6", "PySide2"], noarchive=False, # 去掉 assert 与 __debug__ 分支;不动 docstring(有库在运行期读它)。 optimize=1, ) pyz = PYZ(a.pure) # 目录形态(onedir):单文件 EXE 每次冷启动都要把几百 MB 的 Qt WebEngine # 解压进临时目录再被杀毒软件逐个扫一遍,低配硬盘上一等就是几十秒。 # 目录形态零解压,冷启动只剩正常的模块加载。 exe = EXE( pyz, a.scripts, [], exclude_binaries=True, name=app_name, debug=False, bootloader_ignore_signals=False, strip=False, upx=False, console=False, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, icon=str(project_root / "assets" / "brand" / "zhenyangtang-icon.ico"), version=version_resource, ) coll = COLLECT( exe, a.binaries, a.datas, strip=False, upx=False, name=app_name, )