diff --git a/CHANGELOG.md b/CHANGELOG.md index f598cc41..20cb5824 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,16 @@ model now forces offline mode for the duration of the load, so it skips the network HEAD request (and its 5-retry backoff) for every config file — `config.json`, `generation_config.json`, and the rest — instead of retrying each one in sequence before the - app becomes ready. + app becomes ready. This reinstates the load-time `force_offline_if_cached` guard that 0.4.5 + ([#530](https://github.com/jamiepine/voicebox/pull/530)) removed: that removal was a hotfix + for the `_patch_mistral_regex` crash ([#526](https://github.com/jamiepine/voicebox/issues/526)), + which the wrapper installed in the same release now catches at the source, so the guard no + longer trips it. The per-file HEAD retries from + [#434](https://github.com/jamiepine/voicebox/issues/434) were never covered by that wrapper. + Because a load now fails hard offline when any file is missing, every backend's cache check + lists the full set of files its load reads (Chatterbox tokenizer/conds, TADA's Llama + tokenizer mirror), so a partially downloaded snapshot reports "not cached" and downloads + online instead. ### Linux diff --git a/backend/backends/chatterbox_backend.py b/backend/backends/chatterbox_backend.py index e7a025b3..234e74d3 100644 --- a/backend/backends/chatterbox_backend.py +++ b/backend/backends/chatterbox_backend.py @@ -29,11 +29,16 @@ logger = logging.getLogger(__name__) CHATTERBOX_HF_REPO = "ResembleAI/chatterbox" -# Files that must be present for the multilingual model +# Every file ChatterboxMultilingualTTS.from_pretrained() downloads (chatterbox-tts +# 0.1.7, mtl_tts.py allow_patterns). The load runs with HF offline mode forced +# when this reports cached, so a partial snapshot must not count as cached. _MTL_WEIGHT_FILES = [ "t3_mtl23ls_v2.safetensors", "s3gen.pt", "ve.pt", + "grapheme_mtl_merged_expanded_v1.json", + "conds.pt", + "Cangjie5_TC.json", ] diff --git a/backend/backends/chatterbox_turbo_backend.py b/backend/backends/chatterbox_turbo_backend.py index 6f7d6b94..41273bca 100644 --- a/backend/backends/chatterbox_turbo_backend.py +++ b/backend/backends/chatterbox_turbo_backend.py @@ -29,11 +29,18 @@ logger = logging.getLogger(__name__) CHATTERBOX_TURBO_HF_REPO = "ResembleAI/chatterbox-turbo" -# Files that must be present for the turbo model +# Every file ChatterboxTurboTTS.from_local() reads (chatterbox-tts 0.1.7): the +# three weight files, the GPT-2 tokenizer files AutoTokenizer needs, and the +# built-in voice. The load runs with HF offline mode forced when this reports +# cached, so a partial snapshot must not count as cached. _TURBO_WEIGHT_FILES = [ "t3_turbo_v1.safetensors", "s3gen_meanflow.safetensors", "ve.safetensors", + "tokenizer_config.json", + "vocab.json", + "merges.txt", + "conds.pt", ] diff --git a/backend/backends/hume_backend.py b/backend/backends/hume_backend.py index afb0060c..9cc89fab 100644 --- a/backend/backends/hume_backend.py +++ b/backend/backends/hume_backend.py @@ -35,6 +35,9 @@ logger = logging.getLogger(__name__) # HuggingFace repos TADA_CODEC_REPO = "HumeAI/tada-codec" +# TADA hardcodes the gated meta-llama/Llama-3.2-1B tokenizer; we load it from +# this ungated mirror instead (see load_model). +TADA_TOKENIZER_REPO = "unsloth/Llama-3.2-1B" TADA_1B_REPO = "HumeAI/tada-1b" TADA_3B_ML_REPO = "HumeAI/tada-3b-ml" @@ -52,6 +55,12 @@ _TADA_CODEC_WEIGHT_FILES = [ "encoder/model.safetensors", ] +_TADA_TOKENIZER_FILES = [ + "tokenizer.json", + "tokenizer_config.json", + "special_tokens_map.json", +] + class HumeTadaBackend: """HumeAI TADA TTS backend for high-quality voice cloning.""" @@ -80,7 +89,8 @@ class HumeTadaBackend: repo = TADA_MODEL_REPOS.get(model_size, TADA_1B_REPO) model_cached = is_model_cached(repo, required_files=_TADA_MODEL_WEIGHT_FILES) codec_cached = is_model_cached(TADA_CODEC_REPO, required_files=_TADA_CODEC_WEIGHT_FILES) - return model_cached and codec_cached + tokenizer_cached = is_model_cached(TADA_TOKENIZER_REPO, required_files=_TADA_TOKENIZER_FILES) + return model_cached and codec_cached and tokenizer_cached async def load_model(self, model_size: str = "1B") -> None: """Load the TADA model and encoder.""" @@ -140,7 +150,7 @@ class HumeTadaBackend: # local cache path so we can point TADA at it directly. logger.info("Downloading Llama tokenizer (ungated mirror)...") tokenizer_path = snapshot_download( - repo_id="unsloth/Llama-3.2-1B", + repo_id=TADA_TOKENIZER_REPO, token=None, allow_patterns=["tokenizer*", "special_tokens*"], )