blisc's picture
update Arabic
9010af9
Raw History Blame Contribute Delete
8.13 kB
"""
To run locally, do python app.py
"""
import os
os.environ["NUMBA_DISABLE_CUDA"] = "1"
os.environ['OMP_NUM_THREADS'] = '2'
import gradio as gr
import spaces
from huggingface_hub import hf_hub_download, login
from nemo.collections.tts.modules.magpietts_inference.utils import ModelLoadConfig, load_magpie_model
login(token=os.environ.get("HF_TOKEN"))
print("login successful")
server_port = os.getenv("SERVER_PORT")
if isinstance(server_port, str):
server_port = int(server_port)
print(f"server_port {server_port}")
CODEC_MODEL_PATH = "nvidia/nemo-nano-codec-22khz-1.89kbps-21.5fps"
CHECKPOINT_PATH = hf_hub_download(
repo_id="nvidia/magpie_tts_multilingual_357m",
filename="magpie_tts_multilingual_357m.nemo",
token=os.environ.get("HF_TOKEN"),
)
print(f"checkpoint downloaded to {CHECKPOINT_PATH}")
SPEAKER_MAP = {
"Aria": 0,
"Jason": 1,
"John": 2,
"Leo": 3,
"Sofia": 4,
}
LANGUAGE_MAP = {
# "Arabic-UAE": "ar-AE",
# "Arabic-Saudi Arabia": "ar-SA",
"Arabic-MSA": "ar-MSA",
"Chinese": "zh",
"English": "en",
"French": "fr",
"German": "de",
"Hindi": "hi",
"Italian": "it",
"Japanese": "ja",
"Korean": "ko",
"Brazilian Portuguese": "pt-BR",
"Spanish": "es",
"Vietnamese": "vi",
}
BODY = """
**MagpieTTS** is NVIDIA's state-of-the-art multilingual text-to-speech system built on the [NeMo Speech](https://github.com/NVIDIA-NeMo/Speech) framework. \
It employs a two-stage pipeline architecture: a language model generates discrete acoustic tokens from text, which are then decoded into \
high-fidelity audio using a neural audio codec: [NanoCodec](https://huggingface.co/nvidia/nemo-nano-codec-22khz-1.89kbps-21.5fps). \
The model synthesizes speech in 5 different English speakers - Sofia, Aria, Jason, Leo, \
[John Van Stan](https://librivox.org/reader/9017?primary_key=9017&search_category=reader&search_page=1&search_form=get_results&search_order=alpha) \
across 12 languages: Arabic, Chinese, English, French, German, Hindi, Italian, Japanese, Korean, Portuguese, Spanish, and Vietnamese. \
The model predicts discrete audio codec tokens autoregressively using a transformer encoder-decoder architecture. It employs multi-codebook \
prediction (typically 8 codebooks) with frame stacking (factor = 2) and a local transformer for fine-grained refinement of \
high-fidelity audio generation, and leverages techniques like attention priors, classifier-free guidance (CFG), and Group Relative Policy \
Optimization (GRPO) for improved alignment.
### Key Features of the model
- **Multilingual Support** — Synthesizes natural speech in 12 languages: Arabic, Chinese, English, French, German, Hindi, Italian, Japanese, Korean, Portuguese, Spanish, and Vietnamese.
- **Expressive Voices** — Multiple voice options with emotional tones and gender variations including 4 proprietary voices and 1 public voice.
- **Text Normalization** — Built-in text normalization for handling numbers, abbreviations, and special characters for all languages.
### Resources
- 🤗 **MagpieTTS Weights**: [nvidia/magpie_tts_multilingual_357m](https://huggingface.co/nvidia/magpie_tts_multilingual_357m)
- 🤗 **NanoCodec Weights**: [nvidia/nemo-nano-codec-22khz-1.89kbps-21.5fps](https://huggingface.co/nvidia/nemo-nano-codec-22khz-1.89kbps-21.5fps)
- 💻 **NeMo Framework**: [github.com/NVIDIA-NeMo/NeMo](https://github.com/NVIDIA-NeMo/NeMo)
Note about the demo:
- Text normalization takes time to load, so if you want faster generation select "Do not apply TN."
- Text normalization works for all supported languages.
- Text normalization is required for numbers to be processed and spoken.
- When the model runs on ZeroGPU Hardware, expect slower generation because the model checkpoint is loaded everytime.
- As the model's speakers are all native English speakers, expect accented speech in the other languages.
- The current model can generate long-form speech (more than 20 seconds) in English. However, longer generations can cause timeout due to Huggingface timeout limit.
- Loan words are not supported at this time. For example, English characters in Mandarin will lead to unexpected results.
- To add custom phone pronunciations for supported languages, replace the word with it's IPA characters surrounded by '|' characters and add a space inbetween each IPA phone. For example, "Hello world from NeMo Text to Speech." could be written as "Hello world from | ˈ n ɛ m o ʊ | Text to Speech." replacing "NeMo" with "| ˈ n ɛ m o ʊ |".
- Text normalization does not work with custom pronunciations. To mix the two, normalize the input first and then replace the word with the custom pronunciation.
- While the checkpoint was trained with 4 Arabic dialects, only ar-MSA is recommended for use.
- For the enterprise offering, see the [MagpieTTS NIM](https://build.nvidia.com/nvidia/magpie-tts-multilingual) which includes additional native voices in the supported languages, emotional speech capabilities, and optimized batch and latency inference pipeline.
"""
model_config = ModelLoadConfig(
nemo_file=CHECKPOINT_PATH,
codecmodel_path=CODEC_MODEL_PATH,
legacy_codebooks=False,
legacy_text_conditioning=False,
hparams_from_wandb=None,
)
model = None
try:
print(f"model_config {model_config}")
model, _ = load_magpie_model(model_config)
model.eval().cuda()
print("Model loaded and ready for inference.")
except Exception as e:
print(f"Exception in model loading: {e}")
@spaces.GPU
def demo_tts(input_text, language, speaker, apply_TN):
global model
if not input_text or input_text.strip() == "":
raise gr.Error("Please enter some text to synthesize.")
# Reload model inside GPU context if it failed at startup (ZeroGPU fallback)
if model is None:
try:
model, _ = load_magpie_model(model_config)
model.eval().cuda()
print("Model loaded and ready for inference.")
except Exception as e:
raise gr.Error(f"Model failed to load: {e}")
if speaker not in SPEAKER_MAP:
raise gr.Error(f"Unknown speaker: {speaker!r}. Choose from {list(SPEAKER_MAP)}.")
if language not in LANGUAGE_MAP:
raise gr.Error(f"Unknown language: {language!r}. Choose from {list(LANGUAGE_MAP)}.")
apply_tn_flag = apply_TN == "Apply TN"
speaker_idx = SPEAKER_MAP[speaker]
language_code = LANGUAGE_MAP[language]
input_text = input_text.strip()
if not (input_text.endswith(".") or input_text.endswith("?") or input_text.endswith("!")):
input_text = f"{input_text}."
try:
import traceback
audio, audio_len = model.do_tts(
input_text, language=language_code, apply_TN=apply_tn_flag, speaker_index=speaker_idx
)
print(f"audio {audio.shape} audio_len {audio_len}")
except Exception as e:
traceback.print_exc()
raise gr.Error(f"Speech synthesis failed: {e}")
audio_np = audio[0, :audio_len[0]].cpu().numpy()
# Return only picklable objects (int and numpy array)
return model.sample_rate, audio_np
demo = gr.Interface(
fn=demo_tts,
inputs=[
gr.Textbox(label="Text to synthesize"),
gr.Dropdown(
choices=LANGUAGE_MAP.keys(),
value="English",
label="Target Language",
info="Select the target language for the speech to be synthesized in",
),
gr.Dropdown(
choices=["Aria", "Jason", "John", "Leo", "Sofia"],
value="Aria",
label="Target Speaker",
info="Select the target speaker whose voice you would like the the speech to be synthesized in",
),
gr.Radio(
["Apply TN", "Do not apply TN"],
value="Do not apply TN",
label="Apply Text Normalization",
info="Select if you want to apply text normalization to the input text",
),
],
outputs="audio",
description=BODY,
title="Text to Speech MagpieTTS Multilingual Demo",
)
if __name__ == "__main__":
demo.launch(server_port=server_port)