From 66bbebd9d3ef669b93fd7e39587672b20efc5933 Mon Sep 17 00:00:00 2001 From: boatman <1930807094@qq.com> Date: Sat, 5 Sep 2026 10:58:33 +0800 Subject: [PATCH] [Bugfix] Fix fallback loading for IndexTTS external models (#6137) Signed-off-by: boatman <109857087+sphinxkkkbc@users.noreply.github.com> --- .../models/indextts2/test_enhanced_codec.py | 28 +++++++++++++++++++ .../models/indextts2/test_s2mel_v2_5.py | 10 +++++++ .../indextts2/indextts2_s2mel_decoder.py | 2 -- .../models/indextts2/preprocess_utils.py | 7 ----- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/tests/model_executor/models/indextts2/test_enhanced_codec.py b/tests/model_executor/models/indextts2/test_enhanced_codec.py index 2f82eaf91..b58c1598b 100644 --- a/tests/model_executor/models/indextts2/test_enhanced_codec.py +++ b/tests/model_executor/models/indextts2/test_enhanced_codec.py @@ -82,3 +82,31 @@ def test_model_asset_resolver_supports_native_checkpoints_layout(tmp_path): checkpoint.touch() assert preprocess_utils.resolve_model_file(str(tmp_path), "codec.pth") == str(checkpoint) + + +def test_campplus_falls_back_to_hub_for_local_model_dir(tmp_path, monkeypatch): + import huggingface_hub + + from vllm_omni.model_executor.models.indextts2.utils.campplus import dtdnn + + checkpoint = tmp_path / "downloaded-campplus.bin" + checkpoint.touch() + downloads = [] + + class FakeCAMPPlus(torch.nn.Module): + def load_state_dict(self, state, strict=True): + self.loaded_state = (state, strict) + + monkeypatch.setattr(dtdnn, "CAMPPlus", lambda **_kwargs: FakeCAMPPlus()) + monkeypatch.setattr( + huggingface_hub, + "hf_hub_download", + lambda repo_id, filename: downloads.append((repo_id, filename)) or str(checkpoint), + ) + monkeypatch.setattr(preprocess_utils.torch, "load", lambda *_args, **_kwargs: {"weight": torch.ones(1)}) + preprocess_utils._campplus_cache.clear() + + model = preprocess_utils.load_campplus(str(tmp_path), torch.device("cpu")) + + assert isinstance(model, FakeCAMPPlus) + assert downloads == [("funasr/campplus", "campplus_cn_common.bin")] diff --git a/tests/model_executor/models/indextts2/test_s2mel_v2_5.py b/tests/model_executor/models/indextts2/test_s2mel_v2_5.py index 7d7e6e8d2..7babf4c18 100644 --- a/tests/model_executor/models/indextts2/test_s2mel_v2_5.py +++ b/tests/model_executor/models/indextts2/test_s2mel_v2_5.py @@ -838,6 +838,16 @@ def test_v25_resolved_vocoder_source_is_cached(monkeypatch): assert calls == [("/models/indextts25", "fake-bigvgan")] +def test_bigvgan_source_falls_back_to_hub_repo_for_local_model_dir(tmp_path): + assert ( + indextts2_s2mel_decoder._resolve_bigvgan_source( + str(tmp_path), + "nvidia/bigvgan_v2_22khz_80band_256x", + ) + == "nvidia/bigvgan_v2_22khz_80band_256x" + ) + + def test_stage1_preload_does_not_swallow_cuda_runtime_failure(monkeypatch): decoder = object.__new__(IndexTTS2S2MelDecoder) torch.nn.Module.__init__(decoder) diff --git a/vllm_omni/model_executor/models/indextts2/indextts2_s2mel_decoder.py b/vllm_omni/model_executor/models/indextts2/indextts2_s2mel_decoder.py index a6fb66329..e48af9172 100644 --- a/vllm_omni/model_executor/models/indextts2/indextts2_s2mel_decoder.py +++ b/vllm_omni/model_executor/models/indextts2/indextts2_s2mel_decoder.py @@ -78,8 +78,6 @@ def _resolve_bigvgan_source(model_path: str, vocoder_name: str) -> str: ) if local_dir is not None: return local_dir - if os.path.isdir(model_path): - raise FileNotFoundError(f"IndexTTS BigVGAN assets are missing from local bundle {model_path!r}") return vocoder_name diff --git a/vllm_omni/model_executor/models/indextts2/preprocess_utils.py b/vllm_omni/model_executor/models/indextts2/preprocess_utils.py index 1b6fa9485..88e9a0639 100644 --- a/vllm_omni/model_executor/models/indextts2/preprocess_utils.py +++ b/vllm_omni/model_executor/models/indextts2/preprocess_utils.py @@ -102,9 +102,6 @@ def load_wav2vec2(model_path: str, device: torch.device): except Exception as exc: raise RuntimeError(f"Failed to load local IndexTTS Wav2Vec2-BERT assets from {local_dir!r}") from exc - if local_dir is None and os.path.isdir(model_path): - raise FileNotFoundError(f"IndexTTS Wav2Vec2-BERT assets are missing from local bundle {model_path!r}") - # Try a remote model subfolder, then the public base model. try: if model is None or processor is None: @@ -173,8 +170,6 @@ def load_semantic_codec( state = torch.load(ckpt_path, map_location="cpu", weights_only=True) codec.load_state_dict(state, strict=False) else: - if os.path.isdir(model_path): - raise FileNotFoundError(f"IndexTTS RepCodec checkpoint is missing from local bundle {model_path!r}") import safetensors.torch from huggingface_hub import hf_hub_download @@ -203,8 +198,6 @@ def load_campplus(model_path: str, device: torch.device): if ckpt_path is not None: break if ckpt_path is None: - if os.path.isdir(model_path): - raise FileNotFoundError(f"IndexTTS CAMPPlus checkpoint is missing from local bundle {model_path!r}") from huggingface_hub import hf_hub_download ckpt_path = hf_hub_download("funasr/campplus", filename="campplus_cn_common.bin")