""" Portable Build Script for WhisperVoice. ======================================= Creates a single-file portable .exe using PyInstaller. All data (settings, models) will be stored next to the .exe at runtime. """ import os import shutil import PyInstaller.__main__ from pathlib import Path def build_portable(): # 1. Setup Paths project_root = Path(__file__).parent.absolute() dist_path = project_root / "dist" build_path = project_root / "build" # 2. Define Assets to bundle (into the .exe) # Format: (Source, Destination relative to bundle root) data_files = [ # QML files ("src/ui/qml/*.qml", "src/ui/qml"), ("src/ui/qml/*.svg", "src/ui/qml"), ("src/ui/qml/*.qsb", "src/ui/qml"), ("src/ui/qml/fonts/ttf/*.ttf", "src/ui/qml/fonts/ttf"), # Subprocess worker script (CRITICAL for transcription) ("src/core/transcribe_worker.py", "src/core"), ] # Convert to PyInstaller format "--add-data source;dest" (Windows uses ';') add_data_args = [] for src, dst in data_files: add_data_args.extend(["--add-data", f"{src}{os.pathsep}{dst}"]) # 3. Run PyInstaller print("šŸš€ Starting Portable Build...") print("ā³ This may take 5-10 minutes...") PyInstaller.__main__.run([ "main.py", # Entry point "--name=WhisperVoice", # EXE name "--onefile", # Single EXE (slower startup but portable) "--noconsole", # No terminal window "--clean", # Clean cache *add_data_args, # Bundled assets # Heavy libraries that need special collection "--collect-all", "faster_whisper", "--collect-all", "ctranslate2", "--collect-all", "PySide6", "--collect-all", "torch", "--collect-all", "numpy", # Hidden imports (modules imported dynamically) "--hidden-import", "keyboard", "--hidden-import", "pyperclip", "--hidden-import", "psutil", "--hidden-import", "pynvml", "--hidden-import", "sounddevice", "--hidden-import", "scipy", "--hidden-import", "scipy.signal", "--hidden-import", "huggingface_hub", "--hidden-import", "tokenizers", # Qt plugins "--hidden-import", "PySide6.QtQuickControls2", "--hidden-import", "PySide6.QtQuick.Controls", # Icon (convert to .ico for Windows) # "--icon=icon.ico", # Uncomment if you have a .ico file ]) print("\n" + "="*60) print("āœ… BUILD COMPLETE!") print("="*60) print(f"\nšŸ“ Output: {dist_path / 'WhisperVoice.exe'}") print("\nšŸ“‹ First run instructions:") print(" 1. Place WhisperVoice.exe in a folder (e.g., C:\\WhisperVoice\\)") print(" 2. Run it - it will create 'models' and 'settings.json' folders") print(" 3. The app will download the Whisper model on first transcription\n") print("šŸ’” TIP: Keep the .exe with its generated files for true portability!") if __name__ == "__main__": # Ensure we are in project root os.chdir(Path(__file__).parent) build_portable()