""" Copyright 2022 Balacoon TTS interactive demo """ import os import glob import logging from typing import cast from threading import Lock import gradio as gr from balacoon_tts import TTS from huggingface_hub import hf_hub_download, list_repo_files # locker that disallow access to the tts object from more then one thread locker = Lock() # global tts module, initialized from a model selected tts = None # path to the model that is currently used in tts cur_model_path = None # cache of speakers, maps model name to speaker list model_to_speakers = dict() model_repo_dir = "/data" for name in list_repo_files(repo_id="balacoon/tts"): if not os.path.isfile(os.path.join(model_repo_dir, name)): hf_hub_download( repo_id="balacoon/tts", filename=name, local_dir=model_repo_dir, ) def main(): logging.basicConfig(level=logging.INFO) with gr.Blocks() as demo: gr.Markdown( """

Balacoon🦝 Text-to-Speech

1. Write an utterance to generate, 2. Select the model to synthesize with 3. Select speaker 4. Hit "Generate" and listen to the result! You can learn more about models available [here](https://huggingface.co/balacoon/tts). Visit [Balacoon website](https://balacoon.com/) for more info. """ ) with gr.Row(variant="panel"): text = gr.Textbox(label="Text", placeholder="Type something here...") with gr.Row(): with gr.Column(variant="panel"): repo_files = os.listdir(model_repo_dir) model_files = [x for x in repo_files if x.endswith("_cpu.addon")] model_name = gr.Dropdown( label="Model", choices=model_files, ) with gr.Column(variant="panel"): speaker = gr.Dropdown(label="Speaker", choices=[]) def set_model(model_name_str: str): """ gets value from `model_name`. either uses cached list of speakers for the given model name or loads the addon and checks what are the speakers. """ global model_to_speakers if model_name_str in model_to_speakers: speakers = model_to_speakers[model_name_str] else: global tts, cur_model_path, locker with locker: # need to load this model to learn the list of speakers model_path = os.path.join(model_repo_dir, model_name_str) if tts is not None: del tts tts = TTS(model_path) cur_model_path = model_path speakers = tts.get_speakers() model_to_speakers[model_name_str] = speakers value = speakers[-1] return gr.Dropdown.update( choices=speakers, value=value, visible=True ) model_name.change(set_model, inputs=model_name, outputs=speaker) with gr.Row(variant="panel"): generate = gr.Button("Generate") with gr.Row(variant="panel"): audio = gr.Audio() def synthesize_audio(text_str: str, model_name_str: str, speaker_str: str): """ gets utterance to synthesize from `text` Textbox and speaker name from `speaker` dropdown list. speaker name might be empty for single-speaker models. Synthesizes the waveform and updates `audio` with it. """ if not text_str or not model_name_str or not speaker_str: logging.info("text, model name or speaker are not provided") return None expected_model_path = os.path.join(model_repo_dir, model_name_str) global tts, cur_model_path, locker with locker: if expected_model_path != cur_model_path: # reload model if tts is not None: del tts tts = TTS(expected_model_path) cur_model_path = expected_model_path if len(text_str) > 1024: # truncate the text text_str = text_str[:1024] samples = tts.synthesize(text_str, speaker_str) return gr.Audio.update(value=(tts.get_sampling_rate(), samples)) generate.click(synthesize_audio, inputs=[text, model_name, speaker], outputs=audio) demo.queue(concurrency_count=1).launch() if __name__ == "__main__": main()