From b373f915b516d0013b609c5c5fe8141bb97a38e8 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Fri, 24 Apr 2026 19:16:44 +0200 Subject: [PATCH] feat(f5tts): HF-URL Support fuer Custom Checkpoints (aihpi/F5-TTS-German) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _resolve_hf_path wandelt hf://user/repo/path → lokaler Download via huggingface_hub.hf_hub_download. So kann man in Diagnostic einfach die HF-Pfade fuer custom Modelle reinschreiben, ohne erst manuell zu downloaden + zu mounten. Format: hf://aihpi/F5-TTS-German/F5TTS_Base/model_365000.safetensors hf://aihpi/F5-TTS-German/vocab.txt Diagnostic UI: Placeholders + Labels angepasst mit Beispiel-HF-Pfaden und Hinweis dass fuer Fine-Tunes "F5TTS_Base" statt "F5TTS_v1_Base" als Architektur-Name gesetzt werden muss. Co-Authored-By: Claude Opus 4.7 (1M context) --- diagnostic/index.html | 12 +++++++----- xtts/f5tts/bridge.py | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/diagnostic/index.html b/diagnostic/index.html index 690770d..4d2d868 100644 --- a/diagnostic/index.html +++ b/diagnostic/index.html @@ -469,23 +469,25 @@ Hardcoded Defaults: F5TTS_v1_Base, cfg_strength=2.5, nfe_step=32. - +
diff --git a/xtts/f5tts/bridge.py b/xtts/f5tts/bridge.py index e409568..15f39d4 100644 --- a/xtts/f5tts/bridge.py +++ b/xtts/f5tts/bridge.py @@ -99,6 +99,33 @@ def _get_f5tts_cls(): return _F5TTS_cls +def _resolve_hf_path(p: str) -> str: + """Wenn p mit 'hf://' anfaengt → aus HuggingFace Hub runterladen, + lokalen Pfad zurueckgeben. Sonst unveraendert. + + Format: hf://user/repo/path/to/file.ext + Beispiel: hf://aihpi/F5-TTS-German/F5TTS_Base/model_365000.safetensors + """ + if not p or not p.startswith("hf://"): + return p + try: + from huggingface_hub import hf_hub_download + rest = p[5:] + parts = rest.split("/", 2) + if len(parts) < 3: + logger.warning("Ungueltiges hf:// Format: %s (erwarte hf://user/repo/path)", p) + return p + repo_id = f"{parts[0]}/{parts[1]}" + filename = parts[2] + logger.info("HF-Download: %s aus %s", filename, repo_id) + local = hf_hub_download(repo_id=repo_id, filename=filename) + logger.info("HF-Download fertig: %s", local) + return local + except Exception as e: + logger.exception("HF-Download fehlgeschlagen fuer %s: %s", p, e) + return p + + class F5Runner: """Haelt das F5-TTS-Modell. Synthese laeuft im Executor (blocking). @@ -122,14 +149,16 @@ class F5Runner: def _load_blocking(self) -> None: cls = _get_f5tts_cls() + ckpt_resolved = _resolve_hf_path(self.ckpt_file) if self.ckpt_file else "" + vocab_resolved = _resolve_hf_path(self.vocab_file) if self.vocab_file else "" logger.info("Lade F5-TTS '%s' (device=%s, ckpt=%s)...", - self.model_id, F5TTS_DEVICE, self.ckpt_file or "default") + self.model_id, F5TTS_DEVICE, ckpt_resolved or "default") self._load_started_at = time.time() kwargs = {"model": self.model_id, "device": F5TTS_DEVICE} - if self.ckpt_file: - kwargs["ckpt_file"] = self.ckpt_file - if self.vocab_file: - kwargs["vocab_file"] = self.vocab_file + if ckpt_resolved: + kwargs["ckpt_file"] = ckpt_resolved + if vocab_resolved: + kwargs["vocab_file"] = vocab_resolved self.model = cls(**kwargs) elapsed = time.time() - self._load_started_at logger.info("F5-TTS geladen in %.1fs (cfg_strength=%.1f, nfe=%d)",