# whisper_local.spec # PyInstaller-Build-Konfiguration für whisper-local (Windows 64-bit, onedir) # # Ausführen: uv run pyinstaller whisper_local.spec --noconfirm # Oder via: .\build.ps1 import sys from pathlib import Path from PyInstaller.utils.hooks import collect_data_files block_cipher = None SP = Path(".venv/Lib/site-packages") # ── Binaries ────────────────────────────────────────────────────────────────── # ctranslate2: Haupt-DLL, CUDA (cudnn) und Intel OpenMP # DLLs landen in ctranslate2/, damit ctranslate2's os.add_dll_directory() greift binaries_list = [ (str(SP / "ctranslate2/ctranslate2.dll"), "ctranslate2"), (str(SP / "ctranslate2/cudnn64_9.dll"), "ctranslate2"), (str(SP / "ctranslate2/libiomp5md.dll"), "ctranslate2"), # pywin32: COM- und WinTypes-DLLs müssen neben der EXE liegen (str(SP / "pywin32_system32/pythoncom313.dll"), "."), (str(SP / "pywin32_system32/pywintypes313.dll"), "."), # sounddevice / PortAudio (str(SP / "_sounddevice_data/portaudio-binaries/libportaudio64bit.dll"), "_sounddevice_data/portaudio-binaries"), (str(SP / "_sounddevice_data/portaudio-binaries/libportaudio64bit-asio.dll"), "_sounddevice_data/portaudio-binaries"), # onnxruntime (für Silero VAD in faster-whisper) (str(SP / "onnxruntime/capi/onnxruntime.dll"), "onnxruntime/capi"), (str(SP / "onnxruntime/capi/onnxruntime_providers_shared.dll"), "onnxruntime/capi"), ] # av/FFmpeg: DLL-Namen enthalten Hashes — per Glob gesammelt av_libs_dir = SP / "av.libs" binaries_list += [(str(dll), "av.libs") for dll in av_libs_dir.glob("*.dll")] # ── Datas ───────────────────────────────────────────────────────────────────── datas_list = [ # Silero VAD ONNX-Modell (benötigt von faster-whisper) (str(SP / "faster_whisper/assets/silero_vad_v6.onnx"), "faster_whisper/assets"), # sv_ttk Theme (TCL-Skripte + PNG-Spritesheets) (str(SP / "sv_ttk/sv.tcl"), "sv_ttk"), (str(SP / "sv_ttk/theme"), "sv_ttk/theme"), # Beispiel-Konfiguration als Referenz ("config.example.toml", "."), ] # certifi CA-Bundle für HTTPS (huggingface_hub Modell-Download) datas_list += collect_data_files("certifi") # ── Hidden Imports ──────────────────────────────────────────────────────────── # Alle Module hinter sys.platform-Guards oder lazy imports (importlib, __import__) hidden_imports_list = [ # Eigene Windows-Backends (hinter sys.platform == "win32" Guards) "whisper_local.hotkey._pynput", "whisper_local.inserter._win32", "whisper_local.tray._tray", "whisper_local.tray._icon", "whisper_local.tray._settings", "whisper_local.tray._theme", # pynput: Backend wird per importlib dynamisch gewählt "pynput.keyboard._win32", "pynput.mouse._win32", "pynput._util", "pynput._util.win32", "pynput._util.win32_vks", # pywin32 "win32api", "win32con", "win32gui", "win32clipboard", "pywintypes", # pystray Windows-Backend + Utility-Unterpaket (relative imports) "pystray._win32", "pystray._util", "pystray._util.win32", # tkinter: lazy import in tray/_settings.py "tkinter", "tkinter.ttk", # sv_ttk und darkdetect "sv_ttk", "darkdetect", # onnxruntime Inference Collection "onnxruntime.capi.onnxruntime_inference_collection", # huggingface_hub für Modell-Download zur Laufzeit "huggingface_hub", "huggingface_hub.file_download", "huggingface_hub.utils", ] # ── Excludes ────────────────────────────────────────────────────────────────── excludes_list = [ # Linux-only (nicht installiert auf Windows) "evdev", "whisper_local.hotkey._evdev", "whisper_local.inserter._wayland", # Build- und Test-Infrastruktur "pytest", "pytest_asyncio", "hatchling", # Nicht benötigt im gebündelten Binary "unittest", "doctest", "pdb", ] # ── Analysis ────────────────────────────────────────────────────────────────── a = Analysis( ["whisper_local/__main__.py"], pathex=["."], binaries=binaries_list, datas=datas_list, hiddenimports=hidden_imports_list, hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=excludes_list, win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, ) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE( pyz, a.scripts, [], exclude_binaries=True, # onedir-Modus: DLLs bleiben separat name="whisper-local", debug=False, bootloader_ignore_signals=False, strip=False, upx=False, # UPX mit CUDA-DLLs deaktiviert console=False, # kein Konsolenfenster (Tray-App) disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, ) coll = COLLECT( exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=False, upx_exclude=[], name="whisper-local", )