From 9beb9d7fec4b324e612f0d92b84e4ca5ec52a2a6 Mon Sep 17 00:00:00 2001 From: James Pine Date: Fri, 13 Mar 2026 01:01:49 -0700 Subject: [PATCH] fix: install chatterbox-tts with --no-deps to avoid numpy pin conflict chatterbox-tts 0.1.6 pins numpy<1.26 and torch==2.6 which are incompatible with Python 3.12+. Install with --no-deps and list its sub-dependencies explicitly in requirements.txt. Also removes HFProgressTracker from chatterbox backend to avoid 'generator didn't stop after throw()' errors from tqdm patching. --- Makefile | 1 + backend/backends/chatterbox_backend.py | 115 ++++++++++++------------- backend/requirements.txt | 13 ++- justfile | 2 + 4 files changed, 70 insertions(+), 61 deletions(-) diff --git a/Makefile b/Makefile index 3ff4080c..38918613 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ setup-python: $(VENV)/bin/activate ## Set up Python virtual environment and depe @echo -e "$(BLUE)Installing Python dependencies...$(NC)" $(PIP) install --upgrade pip $(PIP) install -r $(BACKEND_DIR)/requirements.txt + $(PIP) install --no-deps chatterbox-tts @if [ "$$(uname -m)" = "arm64" ] && [ "$$(uname)" = "Darwin" ]; then \ echo -e "$(BLUE)Detected Apple Silicon - installing MLX dependencies...$(NC)"; \ $(PIP) install -r $(BACKEND_DIR)/requirements-mlx.txt; \ diff --git a/backend/backends/chatterbox_backend.py b/backend/backends/chatterbox_backend.py index 84eb8365..9078f686 100644 --- a/backend/backends/chatterbox_backend.py +++ b/backend/backends/chatterbox_backend.py @@ -18,7 +18,6 @@ import numpy as np from . import TTSBackend from ..utils.audio import normalize_audio, load_audio from ..utils.progress import get_progress_manager -from ..utils.hf_progress import HFProgressTracker, create_hf_progress_callback from ..utils.tasks import get_task_manager logger = logging.getLogger(__name__) @@ -110,63 +109,59 @@ class ChatterboxTTSBackend: is_cached = self._is_model_cached() - try: - progress_callback = create_hf_progress_callback(model_name, progress_manager) - tracker = HFProgressTracker(progress_callback, filter_non_downloads=is_cached) + if not is_cached: + task_manager.start_download(model_name) + progress_manager.update_progress( + model_name=model_name, + current=0, + total=0, + filename="Downloading Chatterbox model...", + status="downloading", + ) - if not is_cached: - task_manager.start_download(model_name) - progress_manager.update_progress( - model_name=model_name, - current=0, - total=0, - filename="Downloading Chatterbox model...", - status="downloading", + try: + device = self._get_device() + self._device = device + + logger.info(f"Loading Chatterbox Multilingual TTS on {device}...") + + import torch + from chatterbox.mtl_tts import ChatterboxMultilingualTTS + + # Monkey-patch torch.load for CPU loading. The model's .pt files + # were saved on CUDA; from_pretrained() doesn't pass map_location + # so loading on CPU fails without this. + if device == "cpu": + _orig_torch_load = torch.load + + def _patched_load(*args, **kwargs): + kwargs.setdefault("map_location", "cpu") + return _orig_torch_load(*args, **kwargs) + + with ChatterboxTTSBackend._load_lock: + torch.load = _patched_load + try: + self.model = ChatterboxMultilingualTTS.from_pretrained( + device=device, + ) + finally: + torch.load = _orig_torch_load + else: + self.model = ChatterboxMultilingualTTS.from_pretrained( + device=device, ) - with tracker.patch_download(): - device = self._get_device() - self._device = device - - logger.info(f"Loading Chatterbox Multilingual TTS on {device}...") - - import torch - from chatterbox.mtl_tts import ChatterboxMultilingualTTS - - # Monkey-patch torch.load for CPU loading. The model's .pt files - # were saved on CUDA; from_pretrained() doesn't pass map_location - # so loading on CPU fails without this. - if device == "cpu": - _orig_torch_load = torch.load - - def _patched_load(*args, **kwargs): - kwargs.setdefault("map_location", "cpu") - return _orig_torch_load(*args, **kwargs) - - with ChatterboxTTSBackend._load_lock: - torch.load = _patched_load - try: - self.model = ChatterboxMultilingualTTS.from_pretrained( - device=device, - ) - finally: - torch.load = _orig_torch_load - else: - self.model = ChatterboxMultilingualTTS.from_pretrained( - device=device, - ) - - # Fix: transformers >= 4.36 defaults LlamaModel to sdpa attention - # which doesn't support output_attentions=True (needed by - # Chatterbox's AlignmentStreamAnalyzer). Force eager attention. - t3_tfmr = self.model.t3.tfmr - if hasattr(t3_tfmr, "config") and hasattr( - t3_tfmr.config, "_attn_implementation" - ): - t3_tfmr.config._attn_implementation = "eager" - for layer in getattr(t3_tfmr, "layers", []): - if hasattr(layer, "self_attn"): - layer.self_attn._attn_implementation = "eager" + # Fix: transformers >= 4.36 defaults LlamaModel to sdpa attention + # which doesn't support output_attentions=True (needed by + # Chatterbox's AlignmentStreamAnalyzer). Force eager attention. + t3_tfmr = self.model.t3.tfmr + if hasattr(t3_tfmr, "config") and hasattr( + t3_tfmr.config, "_attn_implementation" + ): + t3_tfmr.config._attn_implementation = "eager" + for layer in getattr(t3_tfmr, "layers", []): + if hasattr(layer, "self_attn"): + layer.self_attn._attn_implementation = "eager" if not is_cached: progress_manager.mark_complete(model_name) @@ -179,13 +174,15 @@ class ChatterboxTTSBackend: "chatterbox-tts package not found. " "Install with: pip install chatterbox-tts" ) - progress_manager.mark_error(model_name, str(e)) - task_manager.error_download(model_name, str(e)) + if not is_cached: + progress_manager.mark_error(model_name, str(e)) + task_manager.error_download(model_name, str(e)) raise except Exception as e: logger.error(f"Failed to load Chatterbox: {e}") - progress_manager.mark_error(model_name, str(e)) - task_manager.error_download(model_name, str(e)) + if not is_cached: + progress_manager.mark_error(model_name, str(e)) + task_manager.error_download(model_name, str(e)) raise def unload_model(self) -> None: diff --git a/backend/requirements.txt b/backend/requirements.txt index 53e9e6d3..10574711 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -21,8 +21,17 @@ qwen-tts>=0.0.5 linacodec @ git+https://github.com/ysharma3501/LinaCodec.git Zipvoice @ git+https://github.com/ysharma3501/LuxTTS.git -# Chatterbox TTS (multilingual voice cloning, includes Hebrew) -chatterbox-tts>=0.1.0 +# Chatterbox TTS sub-dependencies (chatterbox-tts itself is installed +# --no-deps in the setup script because it pins numpy<1.26 / torch==2.6 +# which are incompatible with Python 3.12+) +conformer>=0.3.2 +diffusers>=0.29.0 +omegaconf +pykakasi +resemble-perth>=1.0.1 +s3tokenizer +spacy-pkuseg +pyloudnorm # Audio processing librosa>=0.10.0 diff --git a/justfile b/justfile index b0e1981f..ad172fa8 100644 --- a/justfile +++ b/justfile @@ -38,6 +38,8 @@ setup-python: echo "Installing Python dependencies..." {{ pip }} install --upgrade pip -q {{ pip }} install -r {{ backend_dir }}/requirements.txt + # Chatterbox pins numpy<1.26 / torch==2.6 which break on Python 3.12+ + {{ pip }} install --no-deps chatterbox-tts # Apple Silicon: install MLX backend if [ "$(uname -m)" = "arm64" ] && [ "$(uname)" = "Darwin" ]; then echo "Detected Apple Silicon — installing MLX dependencies..."