$ErrorActionPreference = "Stop" Write-Host "=== Whisper Dictation Builder ===" -ForegroundColor Cyan Write-Host "" $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition $RepoRoot = Resolve-Path "$ScriptDir/.." $DepsDir = "$RepoRoot/deps" $BuildDir = "$RepoRoot/build" $SdlVer = "2.28.5" $SdlDirName = "SDL2-$SdlVer" $SdlPath = "$DepsDir/$SdlDirName" # Detect available GPU backends $UseGPU = $false $GPUBackend = "none" Write-Host "[1/6] Detecting GPU capabilities..." -ForegroundColor Yellow # Check for NVIDIA GPU try { $NvidiaGpu = Get-WmiObject Win32_VideoController | Where-Object { $_.Name -like "*NVIDIA*" } if ($NvidiaGpu) { Write-Host " [OK] NVIDIA GPU detected: $($NvidiaGpu.Name)" -ForegroundColor Green # Check for CUDA $CudaPath = $env:CUDA_PATH if (!$CudaPath) { # Try to find latest CUDA version if CUDA_PATH not set $cudaDir = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA" if (Test-Path $cudaDir) { $versions = Get-ChildItem $cudaDir -Directory | Sort-Object Name -Descending if ($versions.Count -gt 0) { $CudaPath = $versions[0].FullName Write-Host " [INFO] Found CUDA at: $CudaPath" -ForegroundColor Cyan } } } if ($CudaPath -and (Test-Path "$CudaPath\bin\nvcc.exe")) { # Check CUDA version $nvccOutput = (& "$CudaPath\bin\nvcc.exe" --version 2>&1) -join "`n" if ($nvccOutput -match "release\s+(\d+)\.(\d+)") { $cudaMajor = [int]$matches[1] $cudaMinor = [int]$matches[2] if ($cudaMajor -ge 12) { Write-Host " [OK] CUDA $cudaMajor.$cudaMinor toolkit - EXCELLENT!" -ForegroundColor Green Write-Host " [OK] Full GPU acceleration enabled" -ForegroundColor Green $UseGPU = $true $GPUBackend = "cuda" } elseif ($cudaMajor -eq 11 -and $cudaMinor -ge 7) { Write-Host " [OK] CUDA $cudaMajor.$cudaMinor toolkit found" -ForegroundColor Yellow Write-Host " [WARN] CUDA 12.4+ recommended for MSVC 2022, will try anyway" -ForegroundColor Yellow $UseGPU = $true $GPUBackend = "cuda" } else { Write-Host " [WARN] CUDA $cudaMajor.$cudaMinor is too old (need 11.7+)" -ForegroundColor Yellow } } else { Write-Host " [WARN] Could not parse CUDA version from nvcc" -ForegroundColor Yellow } } else { Write-Host " [WARN] CUDA toolkit not found or nvcc.exe missing" -ForegroundColor Yellow Write-Host " [INFO] After installing CUDA 13.0, restart your terminal" -ForegroundColor Cyan } } } catch { Write-Host " [WARN] GPU detection error: $_" -ForegroundColor Yellow Write-Host " [INFO] Falling back to CPU-only" -ForegroundColor Gray } # Check for AMD GPU try { $AmdGpu = Get-WmiObject Win32_VideoController | Where-Object { $_.Name -like "*AMD*" -or $_.Name -like "*Radeon*" } if ($AmdGpu -and !$UseGPU) { Write-Host " [OK] AMD GPU detected: $($AmdGpu.Name)" -ForegroundColor Green Write-Host " [INFO] ROCm support available but requires manual setup" -ForegroundColor Cyan } } catch { # Ignore } # Check for Vulkan if (!$UseGPU) { $VulkanSDK = $env:VULKAN_SDK if ($VulkanSDK -and (Test-Path "$VulkanSDK")) { $UseGPU = $true $GPUBackend = "vulkan" Write-Host " [OK] Vulkan SDK found at: $VulkanSDK" -ForegroundColor Green } } if (!$UseGPU) { Write-Host " -> Building with optimized multi-core CPU" -ForegroundColor Cyan Write-Host " Using all $env:NUMBER_OF_PROCESSORS CPU threads for maximum performance" -ForegroundColor Gray Write-Host " (To enable GPU: Install CUDA 12.4+ or Vulkan SDK)" -ForegroundColor DarkGray } Write-Host "" # Setup SDL2 Write-Host "[2/6] Setting up SDL2..." -ForegroundColor Yellow if (-not (Test-Path "$SdlPath/cmake/sdl2-config.cmake")) { if (-not (Test-Path $DepsDir)) { New-Item -ItemType Directory -Path $DepsDir | Out-Null } $ZipFile = "$DepsDir/SDL2-devel-$SdlVer-VC.zip" $Url = "https://github.com/libsdl-org/SDL/releases/download/release-$SdlVer/SDL2-devel-$SdlVer-VC.zip" Write-Host " Downloading SDL2..." -NoNewline if (-not (Test-Path $ZipFile)) { Invoke-WebRequest -Uri $Url -OutFile $ZipFile } Write-Host " Done" -ForegroundColor Green Write-Host " Extracting..." -NoNewline Expand-Archive -Path $ZipFile -DestinationPath $DepsDir -Force Write-Host " Done" -ForegroundColor Green } else { Write-Host " [OK] SDL2 already configured" -ForegroundColor Green } Write-Host "" # Configure CMake Write-Host "[3/6] Configuring CMake..." -ForegroundColor Yellow Set-Location $RepoRoot $SdlPathResolved = Resolve-Path $SdlPath -ErrorAction SilentlyContinue if (-not $SdlPathResolved) { $SdlPathResolved = $SdlPath } # Convert to forward slashes for CMake $SdlDir = ($SdlPathResolved -replace '\\', '/') + '/cmake' $CMakeArgs = @( "-S", $RepoRoot, "-B", "build", "-DWHISPER_SDL2=ON", "-DSDL2_DIR=$SdlDir" ) # Add GPU backend flags if ($UseGPU) { if ($GPUBackend -eq "cuda") { Write-Host " Enabling CUDA backend..." -ForegroundColor Cyan $CMakeArgs += "-DGGML_CUDA=ON" # Explicitly set CUDA_PATH to avoid finding old versions if ($CudaPath) { $env:CUDA_PATH = $CudaPath $env:CUDA_HOME = $CudaPath # Force CMake to use this specific toolkit root $CMakeArgs += "-DCUDAToolkit_ROOT=$CudaPath" Write-Host " Setting CUDA_PATH to: $CudaPath" -ForegroundColor Cyan } } elseif ($GPUBackend -eq "vulkan") { Write-Host " Enabling Vulkan backend..." -ForegroundColor Cyan $CMakeArgs += "-DGGML_VULKAN=ON" } } else { Write-Host " Building CPU-only with all cores..." -ForegroundColor Cyan # Explicitly disable all GPU backends $CMakeArgs += "-DGGML_CUDA=OFF" $CMakeArgs += "-DGGML_VULKAN=OFF" $CMakeArgs += "-DGGML_METAL=OFF" $CMakeArgs += "-DGGML_HIPBLAS=OFF" } # Run CMake & cmake @CMakeArgs if ($LASTEXITCODE -ne 0) { Write-Host "" Write-Host "[WARN] CMake configuration had warnings, but continuing..." -ForegroundColor Yellow if ($UseGPU) { Write-Host " GPU backend may not be available. Will use CPU fallback." -ForegroundColor Yellow } } Write-Host "" # Build Write-Host "[4/6] Building win-dictation..." -ForegroundColor Yellow cmake --build build --config Release --target win-dictation -j $env:NUMBER_OF_PROCESSORS if ($LASTEXITCODE -ne 0) { Write-Host "" Write-Host "[ERROR] Build failed!" -ForegroundColor Red exit 1 } Write-Host " [OK] Build successful" -ForegroundColor Green Write-Host "" # Deploy DLLs Write-Host "[5/6] Deploying dependencies..." -ForegroundColor Yellow $BinDir = "$BuildDir/bin/Release" # Copy SDL2 $SdlDll = "$SdlPath/lib/x64/SDL2.dll" if (Test-Path $SdlDll) { Copy-Item -Path $SdlDll -Destination $BinDir -Force Write-Host " [OK] Copied SDL2.dll" -ForegroundColor Green } # Copy CUDA DLLs if needed if ($UseGPU -and $GPUBackend -eq "cuda") { Write-Host " Deploying CUDA runtime DLLs..." -ForegroundColor Cyan # Find CUDA installation $cudaPath = $env:CUDA_PATH if (!$cudaPath) { $cudaDir = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA" $versions = Get-ChildItem $cudaDir -Directory -ErrorAction SilentlyContinue | Sort-Object Name -Descending if ($versions.Count -gt 0) { $cudaPath = $versions[0].FullName } } if ($cudaPath) { # CUDA 13.0 / 12.x DLLs $CudaDlls = @("cudart64_*.dll", "cublas64_*.dll", "cublasLt64_*.dll", "cudnn64_*.dll", "cufft64_*.dll") foreach ($pattern in $CudaDlls) { # Check bin root $dll = Get-ChildItem "$cudaPath\bin\$pattern" -ErrorAction SilentlyContinue | Select-Object -First 1 # Check bin/x64 (CUDA 13 layout) if (!$dll) { $dll = Get-ChildItem "$cudaPath\bin\x64\$pattern" -ErrorAction SilentlyContinue | Select-Object -First 1 } if ($dll) { Copy-Item -Path $dll.FullName -Destination $BinDir -Force Write-Host " [OK] Copied $($dll.Name)" -ForegroundColor Green } } # Also copy from system if available (for CUDA 13) $systemCuda = "C:\Windows\System32\cudart64_*.dll" $sysDll = Get-ChildItem $systemCuda -ErrorAction SilentlyContinue | Select-Object -First 1 if ($sysDll -and !(Test-Path "$BinDir\cudart64_*.dll")) { Copy-Item -Path $sysDll.FullName -Destination $BinDir -Force Write-Host " [OK] Copied system $($sysDll.Name)" -ForegroundColor Green } } else { Write-Host " [WARN] Could not find CUDA installation for DLL deployment" -ForegroundColor Yellow } } # Copy ggml DLLs $GgmlDlls = Get-ChildItem "$BuildDir" -Recurse -Filter "ggml*.dll" -ErrorAction SilentlyContinue foreach ($dll in $GgmlDlls) { if ($dll.FullName -like "*Release*" -or $dll.FullName -like "*bin*") { Copy-Item -Path $dll.FullName -Destination $BinDir -Force -ErrorAction SilentlyContinue } } Write-Host "" # Download models Write-Host "[6/6] Checking Whisper models..." -ForegroundColor Yellow if (-not (Test-Path "$BinDir/models")) { New-Item -ItemType Directory -Path "$BinDir/models" | Out-Null } # Download tiny.en for CPU-only systems (faster, smaller) $TinyModelName = "ggml-tiny.en.bin" $TinyModelSrc = "$RepoRoot/models/$TinyModelName" $TinyModelDest = "$BinDir/models/$TinyModelName" if (-not (Test-Path $TinyModelSrc)) { Write-Host " Downloading tiny.en model (for CPU-only systems)..." -ForegroundColor Cyan $DownloadScript = "$RepoRoot/models/download-ggml-model.sh" if (Test-Path $DownloadScript) { # Try bash if available $bash = Get-Command bash -ErrorAction SilentlyContinue if ($bash) { & bash $DownloadScript tiny.en } else { # Direct download $TinyModelUrl = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin" Invoke-WebRequest -Uri $TinyModelUrl -OutFile $TinyModelSrc } } } if (Test-Path $TinyModelSrc) { Copy-Item -Path $TinyModelSrc -Destination $TinyModelDest -Force Write-Host " [OK] tiny.en model ready" -ForegroundColor Green } else { Write-Host " [WARN] Could not download tiny.en model" -ForegroundColor Yellow } # Download base.en for GPU systems (better accuracy) $BaseModelName = "ggml-base.en.bin" $BaseModelSrc = "$RepoRoot/models/$BaseModelName" $BaseModelDest = "$BinDir/models/$BaseModelName" if (-not (Test-Path $BaseModelSrc)) { Write-Host " Downloading base.en model (for GPU systems)..." -ForegroundColor Cyan $DownloadScript = "$RepoRoot/models/download-ggml-model.sh" if (Test-Path $DownloadScript) { # Try bash if available $bash = Get-Command bash -ErrorAction SilentlyContinue if ($bash) { & bash $DownloadScript base.en } else { # Direct download $BaseModelUrl = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin" Invoke-WebRequest -Uri $BaseModelUrl -OutFile $BaseModelSrc } } } if (Test-Path $BaseModelSrc) { Copy-Item -Path $BaseModelSrc -Destination $BaseModelDest -Force Write-Host " [OK] base.en model ready" -ForegroundColor Green } else { Write-Host " [WARN] Could not download base.en model" -ForegroundColor Yellow Write-Host " Please download manually from:" -ForegroundColor Yellow Write-Host " https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin" -ForegroundColor Gray Write-Host " And place it in: $BaseModelDest" -ForegroundColor Gray } Write-Host " [INFO] App will auto-select optimal model based on GPU availability" -ForegroundColor Cyan Write-Host "" Write-Host "=== Build Complete ===" -ForegroundColor Green Write-Host "" Write-Host "Configuration:" -ForegroundColor Cyan Write-Host " - GPU Backend: " -NoNewline if ($UseGPU) { Write-Host "$GPUBackend" -ForegroundColor Green } else { Write-Host "CPU-only" -ForegroundColor Yellow } Write-Host " - CPU Threads: $env:NUMBER_OF_PROCESSORS" -ForegroundColor Cyan Write-Host " - Model: base.en" -ForegroundColor Cyan Write-Host "" Write-Host "Run the application:" -ForegroundColor White Write-Host " $BinDir\win-dictation.exe" -ForegroundColor Yellow Write-Host "" Write-Host "Hotkey: Ctrl+Shift+R to toggle recording" -ForegroundColor Gray Write-Host ""