Instructions to use RegaLabs/RegaLabs-TTS with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- CosyVoice
How to use RegaLabs/RegaLabs-TTS with CosyVoice:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
| import os | |
| import sys | |
| from pathlib import Path | |
| import torch | |
| import soundfile as sf | |
| import tempfile | |
| import gradio as gr | |
| # Ensure local imports and CosyVoice path are configured | |
| ROOT_DIR = Path(__file__).parent.resolve() | |
| sys.path.insert(0, str(ROOT_DIR)) | |
| # Ensure CosyVoice repo is accessible | |
| COSYVOICE_REPO = os.environ.get("COSYVOICE_REPO", "./CosyVoice") | |
| if os.path.exists(COSYVOICE_REPO): | |
| sys.path.insert(0, COSYVOICE_REPO) | |
| matcha_path = Path(COSYVOICE_REPO) / "third_party" / "Matcha-TTS" | |
| if matcha_path.exists(): | |
| sys.path.insert(0, str(matcha_path)) | |
| # Sorani text normalizer fallback logic | |
| try: | |
| from sorani.frontend import normalize_sorani_text | |
| except ImportError: | |
| import unicodedata | |
| import re | |
| try: | |
| from sorani.censor import censor_text, verify_wordlist | |
| except ImportError: | |
| from sorani.censor import CensorIntegrityError | |
| def censor_text(text): | |
| raise CensorIntegrityError( | |
| "Sorani censorship module (sorani/censor.py) is missing. " | |
| "RegaLabs-TTS refuses to synthesize without it." | |
| ) | |
| def verify_wordlist(): | |
| raise CensorIntegrityError("Sorani censorship module is missing.") | |
| _CHARACTER_MAP = str.maketrans({"ك": "ک", "ي": "ی", "ى": "ی", "ة": "ە"}) | |
| def normalize_sorani_text(text: str) -> str: | |
| if not text: | |
| return "" | |
| text = unicodedata.normalize("NFKC", text).translate(_CHARACTER_MAP) | |
| text = re.sub(r"[\u064B-\u065F]", "", text) | |
| text = censor_text(text) | |
| verify_wordlist() | |
| return re.sub(r"\s+", " ", text).strip() | |
| # Global model instance | |
| COSYVOICE_MODEL = None | |
| def get_model(): | |
| global COSYVOICE_MODEL | |
| if COSYVOICE_MODEL is None: | |
| try: | |
| from cosyvoice.cli.cosyvoice import CosyVoice3 | |
| except ImportError: | |
| raise RuntimeError( | |
| "CosyVoice runtime not found. Please ensure CosyVoice is cloned: " | |
| "git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git" | |
| ) | |
| base_model = "FunAudioLLM/Fun-CosyVoice3-0.5B-2512" | |
| flow_ckpt = ROOT_DIR / "cosyvoice3_sorani_flow_best_step2300.pt" | |
| adapter_ckpt = ROOT_DIR / "cosyvoice3_sorani_lora_refined_best.pt" | |
| print(f"Loading base CosyVoice model: {base_model}...") | |
| device_fp16 = torch.cuda.is_available() | |
| cosyvoice = CosyVoice3(base_model, fp16=device_fp16) | |
| if adapter_ckpt.exists(): | |
| from cosyvoice.utils.lora import inject_lora, load_lora_state_dict | |
| llm = cosyvoice.model.llm | |
| target_count = inject_lora(llm, rank=16, alpha=32.0, dropout=0.05) | |
| load_lora_state_dict( | |
| llm, torch.load(adapter_ckpt, map_location="cpu", weights_only=False) | |
| ) | |
| llm.to(cosyvoice.model.device).eval() | |
| print(f"Loaded RegaLabs-TTS Sorani LLM adapter ({target_count} projections).") | |
| if flow_ckpt.exists(): | |
| from sorani.censor import verify_checkpoint | |
| verify_checkpoint(flow_ckpt) | |
| print(f"Loading RegaLabs-TTS Sorani flow weights: {flow_ckpt}...") | |
| flow_state = torch.load(flow_ckpt, map_location="cpu", weights_only=False) | |
| if isinstance(flow_state, dict): | |
| for key in ("model", "state_dict", "flow"): | |
| nested = flow_state.get(key) | |
| if isinstance(nested, dict): | |
| flow_state = nested | |
| break | |
| flow_state = {k: v for k, v in flow_state.items() if isinstance(k, str) and isinstance(v, torch.Tensor)} | |
| cosyvoice.model.flow.load_state_dict(flow_state, strict=False) | |
| cosyvoice.model.flow.to(cosyvoice.model.device).eval() | |
| print("Successfully loaded RegaLabs-TTS Sorani flow model.") | |
| COSYVOICE_MODEL = cosyvoice | |
| return COSYVOICE_MODEL | |
| def synthesize_sorani(text, prompt_wav, prompt_text, speed, do_normalize): | |
| if not text or not text.strip(): | |
| raise gr.Error("Please enter Sorani Kurdish text to synthesize.") | |
| if not prompt_wav: | |
| raise gr.Error("Please upload or select a reference prompt audio WAV.") | |
| if not prompt_text or not prompt_text.strip(): | |
| raise gr.Error("Please provide the transcript text for the reference prompt audio.") | |
| # Text Normalization | |
| clean_text = normalize_sorani_text(text) if do_normalize else text.strip() | |
| clean_prompt_text = normalize_sorani_text(prompt_text) if do_normalize else prompt_text.strip() | |
| model = get_model() | |
| pieces = [] | |
| with torch.inference_mode(): | |
| for output in model.inference_zero_shot( | |
| clean_text, | |
| clean_prompt_text, | |
| prompt_wav, | |
| stream=False, | |
| speed=speed, | |
| text_frontend=False, | |
| ): | |
| pieces.append(output["tts_speech"].detach().cpu()) | |
| if not pieces: | |
| raise RuntimeError("No audio was returned from the TTS model.") | |
| speech = torch.cat(pieces, dim=1).squeeze(0).numpy() | |
| with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file: | |
| sf.write(tmp_file.name, speech, model.sample_rate, subtype="PCM_16") | |
| out_wav_path = tmp_file.name | |
| return out_wav_path, f"✅ Synthesis complete! Normalized Text: '{clean_text}'" | |
| # Default sample files | |
| sample_wav = str(ROOT_DIR / "samples" / "aran_en021.wav") if (ROOT_DIR / "samples" / "aran_en021.wav").exists() else None | |
| # Custom CSS | |
| custom_css = """ | |
| .container { max-width: 900px; margin: auto; } | |
| .header { text-align: center; margin-bottom: 20px; } | |
| .attribution { background-color: #1a1a24; border-radius: 8px; padding: 15px; margin-top: 25px; border-left: 4px solid #6366f1; } | |
| """ | |
| with gr.Blocks(title="RegaLabs-TTS: Sorani Speech Synthesis", css=custom_css) as demo: | |
| gr.Markdown( | |
| """ | |
| # 🎙️ RegaLabs-TTS: Central Kurdish (Sorani) Speech Synthesis | |
| **CosyVoice 3 Zero-Shot TTS & Voice Cloning Adaptation for Sorani Kurdish (سۆرانی)** | |
| Developed by **[RegaLabs](https://huggingface.co/RegaLabs)** | |
| """, | |
| elem_classes=["header"] | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| text_input = gr.Textbox( | |
| label="Sorani Text (دەقی سۆرانی)", | |
| placeholder="سڵاو، بەخێربێن بۆ تاقیکردنەوەی دەنگی RegaLabs-TTS...", | |
| value="سڵاو، بەخێربێن بۆ تاقیکردنەوەی دەنگی RegaLabs-TTS", | |
| lines=4, | |
| ) | |
| prompt_audio = gr.Audio( | |
| label="Reference Voice Audio (دەنگی نموونە)", | |
| type="filepath", | |
| value=sample_wav, | |
| ) | |
| prompt_text_input = gr.Textbox( | |
| label="Reference Voice Transcript (دەقی دەنگی نموونەکە)", | |
| placeholder="دەنگێکی لەسەرخۆ، هێمن و پڕ لە بڕوابەخۆبوون.", | |
| value="دەنگێکی لەسەرخۆ، هێمن و پڕ لە بڕوابەخۆبوون.", | |
| lines=2, | |
| ) | |
| with gr.Accordion("Advanced Options (ڕێکخستنەکان)", open=False): | |
| speed_slider = gr.Slider( | |
| minimum=0.5, maximum=1.5, value=1.0, step=0.05, label="Speech Speed (خێرایی خوێندنەوە)" | |
| ) | |
| normalize_check = gr.Checkbox( | |
| value=True, label="Enable Sorani Text Normalization (ڕێکخستنی دەق)" | |
| ) | |
| generate_btn = gr.Button("🎤 Synthesize Sorani Speech (دروستکردنی دەنگ)", variant="primary", size="lg") | |
| with gr.Column(scale=1): | |
| audio_output = gr.Audio(label="Synthesized Sorani Speech (دەنگی دروستکراو)", type="filepath") | |
| status_output = gr.Textbox(label="Status & Info", interactive=False) | |
| generate_btn.click( | |
| fn=synthesize_sorani, | |
| inputs=[text_input, prompt_audio, prompt_text_input, speed_slider, normalize_check], | |
| outputs=[audio_output, status_output], | |
| ) | |
| gr.Markdown( | |
| """ | |
| --- | |
| ### 📜 License & Mandatory Attribution | |
| * **Model Checkpoint & Codebase:** **Apache 2.0** by **RegaLabs**. Commercial and non-commercial use is **fully allowed** with mandatory credit to RegaLabs. | |
| * **Stock Prompt Voices & Audio Samples:** **Non-Commercial Use Only**. Pre-packaged stock voice samples are strictly restricted from commercial use/cloning. | |
| **📌 Mandatory Credit:** Any public use, generated media (videos, podcasts, voiceovers, radio/TV), applications, or derivative works MUST explicitly credit **RegaLabs**: | |
| > *"Voice synthesized using RegaLabs-TTS by RegaLabs"* (or *"Audio powered by RegaLabs"*). | |
| """, | |
| elem_classes=["attribution"] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch(server_name="0.0.0.0", server_port=7860) | |