# -*- mode: python ; coding: utf-8 -*- # WhisperVoice — Single-file portable bootstrapper # # This builds a TINY exe that contains only: # - The bootstrapper (downloads Python + deps on first run) # - The app source code (bundled as data, extracted to runtime/app/) # # NO heavy dependencies (torch, PySide6, etc.) are bundled. import os import glob block_cipher = None # ── Collect app source as data (goes into app_source/ inside the bundle) ── app_datas = [] # main.py app_datas.append(('main.py', 'app_source')) # requirements.txt app_datas.append(('requirements.txt', 'app_source')) # src/**/*.py (core, ui, utils — preserving directory structure) for py in glob.glob('src/**/*.py', recursive=True): dest = os.path.join('app_source', os.path.dirname(py)) app_datas.append((py, dest)) # src/ui/qml/** (QML files, shaders, SVGs, fonts, qmldir) qml_dir = os.path.join('src', 'ui', 'qml') for pattern in ('*.qml', '*.qsb', '*.frag', '*.svg', '*.ico', '*.png', 'qmldir', 'AUTHORS.txt', 'OFL.txt'): for f in glob.glob(os.path.join(qml_dir, pattern)): app_datas.append((f, os.path.join('app_source', qml_dir))) # Fonts for f in glob.glob(os.path.join(qml_dir, 'fonts', 'ttf', '*.ttf')): app_datas.append((f, os.path.join('app_source', qml_dir, 'fonts', 'ttf'))) # assets/ if os.path.exists(os.path.join('assets', 'icon.ico')): app_datas.append((os.path.join('assets', 'icon.ico'), os.path.join('app_source', 'assets'))) # ── Analysis — only the bootstrapper, NO heavy imports ──────────────────── a = Analysis( ['bootstrapper.py'], pathex=[], binaries=[], datas=app_datas, hiddenimports=[], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[ # Exclude everything heavy — the bootstrapper only uses stdlib 'torch', 'numpy', 'scipy', 'PySide6', 'shiboken6', 'faster_whisper', 'ctranslate2', 'llama_cpp', 'sounddevice', 'soundfile', 'keyboard', 'pyperclip', 'psutil', 'pynvml', 'pystray', 'PIL', 'Pillow', 'darkdetect', 'huggingface_hub', 'requests', 'tqdm', 'onnxruntime', 'av', 'tkinter', 'matplotlib', 'notebook', 'IPython', ], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, ) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) # ── Single-file EXE (--onefile) ────────────────────────────────────────── exe = EXE( pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='WhisperVoice', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=False, # No console — bootstrapper allocates one when needed disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, icon='assets/icon.ico', )