mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-15 04:40:40 -07:00
* feat(windows): add native ROCm support for AMD GPUs Implements native ROCm architecture for Windows. - Adds backend build pipeline for voicebox-server-rocm.exe - Detects AMD GPUs dynamically and routes PyTorch allocations - Adds automatic download and update logic for ROCm dependencies - Refactors UI in GpuPage.tsx and GpuAcceleration.tsx to add AMD flows - Fixes 'Switch to CPU' lock on Windows via Tauri backend_override state - Resolves PyInstaller/rocm_sdk UnboundLocalError silent crashes - Resolves Numba/NumPy 2.x incompatibilities during Qwen3-TTS load - Resolves HF_HUB_OFFLINE Catch-22 for CustomVoice processor caching * fix(rocm): host libs archive under the app release tag, drop offline-load regression Align the ROCm libs download with the CUDA pattern: both the server core and the libs archive are published under the app-version release tag, with the libs content version encoded in the filename only. The previous code fetched libs from a separate rocm7.2-v1 tag, which disagreed with the download test. Also revert the unrelated Qwen CustomVoice changes that wrapped model loading in force_offline_if_cached (not imported — a NameError on load for every platform) and re-added a Base-model cache gate. The inference-path offline guard was deliberately removed previously. * feat(rocm): gate download on AMD detection and persist the backend variant The ROCm download section now only shows when the backend reports an AMD GPU on Windows (new supports_rocm health field, backed by the memoized is_amd_gpu_windows detection that was previously unused), or when ROCm is already downloaded/active. Make the backend override honor a pinned variant: set_backend_override persists the choice to disk so it survives an app restart, start_server reads it back, and a cuda/rocm pin now actually selects that variant instead of always preferring ROCm. A stale pin to a deleted backend self-heals to the default order rather than forcing CPU. Add the web no-op stub for the new method. * chore(rocm): drop incomplete vitest harness for the unused GpuAcceleration component GpuAcceleration.tsx is not routed anywhere (GpuPage is the live settings view), and the added vitest setup referenced testing-library/vitest deps that were not in the lockfile, breaking the web typecheck. Remove the dead component's test and its scaffolding to keep this PR scoped to the ROCm feature. * ci(rocm): add ROCm release-artifact pipeline Mirror the CUDA packaging path for ROCm so the runtime download has artifacts to fetch. scripts/package_rocm.py splits the PyInstaller --rocm onedir into voicebox-server-rocm.tar.gz (core) + rocm-libs-rocm7.2-v1.tar.gz (AMD runtime: HIP DLLs, rocBLAS Tensile data, MIOpen kernel DBs) + rocm-libs.json, matching the names services/rocm.py expects, both under the app-version release tag. The new build-rocm-windows job in release.yml builds on windows-latest/cp312 and lets build_binary.py --rocm pull the official AMD Radeon wheels. The file classifier can't be validated against a real AMD build on CI, so it has unit coverage (test_package_rocm.py) against a synthetic onedir layout. The prefixes/dir markers may need a tweak after the first real build on AMD hardware — the packager hard-fails loudly if it classifies zero ROCm files. --------- Co-authored-by: Jamie Pine <[email protected]>
86 lines
3.2 KiB
Python
86 lines
3.2 KiB
Python
"""
|
|
Runtime hook: repair rocm_sdk.find_libraries under PyInstaller.
|
|
|
|
rocm_sdk 7.2.x ships a find_libraries() with a latent bug: when the
|
|
backend package (_rocm_sdk_core / _rocm_sdk_libraries_{target}) cannot
|
|
be imported, the except clause records the miss but falls through to
|
|
`py_root = Path(py_module.__file__).parent`, where py_module was never
|
|
assigned. This surfaces as UnboundLocalError instead of the intended
|
|
ModuleNotFoundError, masking the real cause.
|
|
|
|
Frozen apps trip this because rocm_sdk imports the backend packages
|
|
dynamically via importlib, which PyInstaller's static analyzer cannot
|
|
see. We re-collect those packages in build_binary.py; this hook is
|
|
defense-in-depth: it replaces find_libraries with a corrected version
|
|
so any future missing-package case surfaces a readable error.
|
|
"""
|
|
|
|
|
|
def _patch_rocm_sdk():
|
|
try:
|
|
import rocm_sdk
|
|
from rocm_sdk import _dist_info
|
|
except ModuleNotFoundError as e:
|
|
if e.name not in {"rocm_sdk", "rocm_sdk._dist_info"}:
|
|
raise
|
|
return
|
|
|
|
import importlib
|
|
import platform
|
|
from pathlib import Path
|
|
|
|
def find_libraries(*shortnames):
|
|
paths = []
|
|
missing_extras = set()
|
|
is_windows = platform.system() == "Windows"
|
|
for shortname in shortnames:
|
|
try:
|
|
lib_entry = _dist_info.ALL_LIBRARIES[shortname]
|
|
except KeyError:
|
|
raise ModuleNotFoundError(f"Unknown rocm library '{shortname}'") from None
|
|
|
|
if is_windows and not lib_entry.dll_pattern:
|
|
continue
|
|
|
|
package = lib_entry.package
|
|
target_family = None
|
|
if package.is_target_specific:
|
|
target_family = _dist_info.determine_target_family()
|
|
py_package_name = package.get_py_package_name(target_family)
|
|
try:
|
|
py_module = importlib.import_module(py_package_name)
|
|
except ModuleNotFoundError as e:
|
|
if e.name != py_package_name:
|
|
raise
|
|
missing_extras.add(package.logical_name)
|
|
continue
|
|
|
|
py_root = Path(py_module.__file__).parent
|
|
if is_windows:
|
|
relpath = py_root / lib_entry.windows_relpath
|
|
entry_pattern = lib_entry.dll_pattern
|
|
else:
|
|
relpath = py_root / lib_entry.posix_relpath
|
|
entry_pattern = lib_entry.so_pattern
|
|
matching_paths = sorted(relpath.glob(entry_pattern))
|
|
if len(matching_paths) == 0:
|
|
raise FileNotFoundError(
|
|
f"Could not find rocm library '{shortname}' at path "
|
|
f"'{relpath},' no match for pattern '{entry_pattern}'"
|
|
)
|
|
paths.append(matching_paths[0])
|
|
|
|
if missing_extras:
|
|
raise ModuleNotFoundError(
|
|
f"Missing required rocm backend packages: "
|
|
f"{', '.join(sorted(missing_extras))}. The frozen build did "
|
|
f"not bundle _rocm_sdk_core / _rocm_sdk_libraries_<target>. "
|
|
f"Check build_binary.py --collect-all flags."
|
|
)
|
|
return paths
|
|
|
|
rocm_sdk.find_libraries = find_libraries
|
|
|
|
|
|
_patch_rocm_sdk()
|