Spaces:
Running on Zero
Running on Zero
| #!/usr/bin/env python3 | |
| """Higgs Audio v3 (4B) TTS backend for ZeroGPU. | |
| Ported from the `transformers`-native demo at | |
| multimodalart/higgs-audio-v3-tts, which wraps bosonai/higgs-audio-v3-tts-4b | |
| via multimodalart/higgs-audio-v3-tts-4b-transformers. | |
| ``load()`` is called once at app startup. ZeroGPU's CUDA emulation packs the | |
| model tensors before a real GPU is assigned to the decorated request handler. | |
| """ | |
| import logging | |
| import os | |
| import torch | |
| MODEL_REPO = "multimodalart/higgs-audio-v3-tts-4b-transformers" | |
| _tokenizer = None | |
| _model = None | |
| _sample_rate = None | |
| def load(): | |
| """Load the tokenizer, model, and audio codec onto cuda. Idempotent.""" | |
| global _tokenizer, _model, _sample_rate | |
| if _model is not None: | |
| return | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| logging.info(f"Loading Higgs Audio v3 ({MODEL_REPO})…") | |
| token = os.environ.get("HF_TOKEN") | |
| _tokenizer = AutoTokenizer.from_pretrained( | |
| MODEL_REPO, | |
| token=token, | |
| trust_remote_code=True, | |
| ) | |
| _model = ( | |
| AutoModelForCausalLM.from_pretrained( | |
| MODEL_REPO, | |
| token=token, | |
| trust_remote_code=True, | |
| dtype=torch.bfloat16, | |
| ) | |
| .to("cuda") | |
| .eval() | |
| ) | |
| _model.get_audio_codec() # preload the 24 kHz codec | |
| _sample_rate = _model.config.sample_rate | |
| logging.info("Higgs Audio v3 ready.") | |
| def generate(text, voice_ref=None, reference_text=None, temperature=0.7, | |
| top_p=0.95, top_k=50, max_new_tokens=2048, seed=-1): | |
| """Generate speech with Higgs Audio v3. | |
| voice_ref: optional path to a reference clip for zero-shot cloning. | |
| reference_text: optional transcript of voice_ref — improves cloning when | |
| provided, but generation works without it. | |
| Returns (waveform: 1-D numpy array, sample_rate: int). | |
| """ | |
| if _model is None: | |
| raise RuntimeError("Higgs Audio v3 is not loaded — call higgs_backend.load() at startup.") | |
| import soundfile as sf | |
| if seed is not None and int(seed) >= 0: | |
| torch.manual_seed(int(seed)) | |
| kwargs = dict( | |
| max_new_tokens=int(max_new_tokens), | |
| temperature=float(temperature), | |
| top_p=float(top_p) if float(top_p) < 1.0 else None, | |
| top_k=int(top_k) if int(top_k) > 0 else None, | |
| ) | |
| if voice_ref: | |
| data, sr = sf.read(voice_ref, dtype="float32", always_2d=True) # [L, C] | |
| wav = torch.from_numpy(data).mean(dim=1) # to mono [L] | |
| kwargs["reference_audio"] = wav | |
| kwargs["reference_sample_rate"] = sr | |
| if reference_text and reference_text.strip(): | |
| kwargs["reference_text"] = reference_text.strip() | |
| audio = _model.generate_speech(text, _tokenizer, **kwargs) | |
| if audio.numel() == 0: | |
| raise RuntimeError("Higgs Audio v3 produced no audio — try again or adjust the text.") | |
| return audio.numpy(), _sample_rate | |