"""Build script to create a Windows executable with bundled Python environment. This script should be run ON WINDOWS, not cross-compiled from Linux. """ import shutil import subprocess import sys from pathlib import Path def main(): """Create a Windows executable bundle for Chronara.""" project_root = Path(__file__).parent.parent dist_dir = project_root / "dist-bundle" print("🔨 Chronara Windows Build Script") print("=" * 50) print("\n⚠️ NOTE: This script must be run on Windows!") print(" Cross-compilation from Linux is not supported.\n") if sys.platform != "win32": print("❌ This script must be run on Windows.") print(" Please run this on a Windows machine or in a Windows VM.") sys.exit(1) # Clean previous builds if dist_dir.exists(): print("Cleaning previous build...") shutil.rmtree(dist_dir) dist_dir.mkdir(exist_ok=True) # Step 1: Create Python bundle using PyInstaller print("\n📦 Creating Python bundle...") # Create a temporary spec file for PyInstaller spec_content = f""" # -*- mode: python ; coding: utf-8 -*- a = Analysis( ['{project_root / "src" / "backend" / "main.py"}'], pathex=['{project_root / "src"}'], binaries=[], datas=[ ('{project_root / "models" / "*.gguf"}', 'models'), ], hiddenimports=['uvicorn', 'fastapi', 'whisperx', 'llama_cpp'], hookspath=[], hooksconfig={{}}, runtime_hooks=[], excludes=[], noarchive=False, ) pyz = PYZ(a.pure) exe = EXE( pyz, a.scripts, a.binaries, a.datas, [], name='chronara-backend', debug=False, bootloader_ignore_signals=False, strip=False, upx=False, upx_exclude=[], runtime_tmpdir=None, console=True, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, ) """ spec_path = project_root / "chronara-backend.spec" spec_path.write_text(spec_content) try: subprocess.run([ sys.executable, "-m", "PyInstaller", str(spec_path), "--clean", "--noconfirm", "--distpath", str(dist_dir / "backend") ], check=True) except subprocess.CalledProcessError: print("⚠️ PyInstaller not found. Installing...") subprocess.run([sys.executable, "-m", "pip", "install", "pyinstaller"], check=True) subprocess.run([ sys.executable, "-m", "PyInstaller", str(spec_path), "--clean", "--noconfirm", "--distpath", str(dist_dir / "backend") ], check=True) # Clean up spec file spec_path.unlink() # Step 2: Build Tauri app (creates NSIS installer on Windows) print("\n🦀 Building Tauri app with NSIS installer...") subprocess.run( "pnpm tauri build", cwd=project_root, check=True, shell=True ) print("\n✅ Build complete!") print("\nWindows installer (.exe) location:") print(" src-tauri/target/release/bundle/nsis/Chronara_0.1.0_x64_en-US.exe") print("\nThis installer includes:") print(" - Tauri app with React frontend") print(" - Python backend (bundled)") print(" - Llama model files") print(" - All dependencies") if __name__ == "__main__": main()