Files
voicebox/backend/utils/hf_offline_patch.py
James Pine 3187344f01 add model loading status, effects preset dropdown, clean up UI
Backend:
- Generation service reports 'loading_model' status only when model
  is not yet in memory, then 'generating' once inference starts
- Migrate hf_offline_patch.py from print() to logging module
- Update ADDING_TTS_ENGINES.md for post-refactor file paths

Frontend:
- HistoryTable shows 'Loading model...' vs 'Generating...' based on step
- FloatingGenerateBox: replace instruct toggle + inline effects editor
  with an effects preset dropdown (third dropdown after language and engine)
- Instruct UI removed for now (form field preserved for future models)
- Remove focus ring from Select component globally
2026-03-16 02:58:41 -07:00

89 lines
3.1 KiB
Python

"""Monkey-patch huggingface_hub to force offline mode with cached models.
Prevents mlx_audio from making network requests when models are already
downloaded. Must be imported BEFORE mlx_audio.
"""
import logging
import os
from pathlib import Path
from typing import Optional, Union
logger = logging.getLogger(__name__)
def patch_huggingface_hub_offline():
"""Monkey-patch huggingface_hub to force offline mode."""
try:
import huggingface_hub # noqa: F401 -- need the package loaded
from huggingface_hub import constants as hf_constants
from huggingface_hub.file_download import _try_to_load_from_cache
original_try_load = _try_to_load_from_cache
def _patched_try_to_load_from_cache(
repo_id: str,
filename: str,
cache_dir: Union[str, Path, None] = None,
revision: Optional[str] = None,
repo_type: Optional[str] = None,
):
result = original_try_load(
repo_id=repo_id,
filename=filename,
cache_dir=cache_dir,
revision=revision,
repo_type=repo_type,
)
if result is None:
cache_path = Path(hf_constants.HF_HUB_CACHE) / f"models--{repo_id.replace('/', '--')}"
logger.debug("file not cached: %s/%s (expected at %s)", repo_id, filename, cache_path)
else:
logger.debug("cache hit: %s/%s", repo_id, filename)
return result
import huggingface_hub.file_download as fd
fd._try_to_load_from_cache = _patched_try_to_load_from_cache
logger.debug("huggingface_hub patched for offline mode")
except ImportError:
logger.debug("huggingface_hub not available, skipping offline patch")
except Exception:
logger.exception("failed to patch huggingface_hub for offline mode")
def ensure_original_qwen_config_cached():
"""Symlink the original Qwen repo cache to the MLX community version.
mlx_audio may try to fetch config from the original Qwen repo. If only
the MLX community variant is cached, create a symlink so the cache lookup
succeeds without a network request.
"""
try:
from huggingface_hub import constants as hf_constants
except ImportError:
return
original_repo = "Qwen/Qwen3-TTS-12Hz-1.7B-Base"
mlx_repo = "mlx-community/Qwen3-TTS-12Hz-1.7B-Base-bf16"
cache_dir = Path(hf_constants.HF_HUB_CACHE)
original_path = cache_dir / f"models--{original_repo.replace('/', '--')}"
mlx_path = cache_dir / f"models--{mlx_repo.replace('/', '--')}"
if not original_path.exists() and mlx_path.exists():
try:
original_path.parent.mkdir(parents=True, exist_ok=True)
original_path.symlink_to(mlx_path, target_is_directory=True)
logger.info("created cache symlink: %s -> %s", original_repo, mlx_repo)
except Exception:
logger.warning("could not create cache symlink for %s", original_repo, exc_info=True)
if os.environ.get("VOICEBOX_OFFLINE_PATCH", "1") != "0":
patch_huggingface_hub_offline()
ensure_original_qwen_config_cached()