Files
whisper_voice/portable_build.py

87 lines
3.1 KiB
Python

"""
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([
"bootstrapper.py", # Entry point (Tiny Installer)
"--name=WhisperVoice", # EXE name
"--onefile", # Single EXE
"--noconsole", # No terminal window
"--clean", # Clean cache
# Bundle the app source to be extracted by bootstrapper
# The bootstrapper expects 'app_source' folder in bundled resources
"--add-data", f"src{os.pathsep}app_source/src",
"--add-data", f"main.py{os.pathsep}app_source",
"--add-data", f"requirements.txt{os.pathsep}app_source",
# Add assets
"--add-data", f"src/ui/qml{os.pathsep}app_source/src/ui/qml",
"--add-data", f"assets{os.pathsep}app_source/assets",
# No heavy collections!
# The bootstrapper uses internal pip to install everything.
# Exclude heavy modules to ensure this exe stays tiny
"--exclude-module", "faster_whisper",
"--exclude-module", "torch",
"--exclude-module", "PySide6",
"--exclude-module", "llama_cpp",
# Icon
# "--icon=icon.ico",
])
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()