import datetime import os import gradio as gr import numpy as np import torch from infer import infer from server_fastapi import Models is_hf_spaces = os.getenv("SYSTEM") == "spaces" limit = 100 root_dir = "weights" model_holder = Models() def refresh_model(): global model_holder model_holder = Models() model_dirs = [ d for d in os.listdir(root_dir) if os.path.isdir(os.path.join(root_dir, d)) ] model_names = [] for model_name in model_dirs: model_dir = os.path.join(root_dir, model_name) pth_files = [f for f in os.listdir(model_dir) if f.endswith(".pth")] if len(pth_files) != 1: print(f"{root_dir}/{model_name}のpthファイルの数が1つではないので無視します") continue model_path = os.path.join(model_dir, pth_files[0]) config_path = os.path.join(model_dir, "config.json") try: model_holder.init_model( config_path=config_path, model_path=model_path, device=device, language="JP", ) model_names.append(model_name) except Exception as e: print(f"{root_dir}/{model_name}の初期化に失敗しました\n{e}") continue return model_names def update_model_dropdown(): model_names = refresh_model() return gr.Dropdown(choices=model_names, value=model_names[0]) # `server_fastapi.py`から取ってきて微修正 def _voice( model_id: int, text: str, language: str = "JP", emotion: int = 0, sdp_ratio: float = 0.2, noise: float = 0.6, noisew: float = 0.8, length: float = 1.0, line_split: bool = True, split_interval: float = 0.2, speaker_id: int = 0, ): if model_id not in model_holder.models.keys(): return f"エラー、model_id={model_id}は存在しません", None speaker_name = model_holder.models[model_id].id2spk[speaker_id] start_time = datetime.datetime.now() print("-----") print(datetime.datetime.now()) print( f"model_id={model_id}, speaker_id={speaker_id}, speaker_name={speaker_name}, language={language}" ) print(f"text:\n{text}") if is_hf_spaces and len(text) > limit: print(f"Error: 文字数が{limit}文字を超えています") return f"エラー、文字数が{limit}文字を超えています", None try: if not line_split: with torch.no_grad(): audio = infer( text=text, sdp_ratio=sdp_ratio, noise_scale=noise, noise_scale_w=noisew, length_scale=length, sid=speaker_name, language=language, hps=model_holder.models[model_id].hps, net_g=model_holder.models[model_id].net_g, device=model_holder.models[model_id].device, emotion=emotion, ) else: texts = text.split("\n") texts = [t for t in texts if t != ""] # 空行を削除 audios = [] with torch.no_grad(): for i, t in enumerate(texts): audios.append( infer( text=t, sdp_ratio=sdp_ratio, noise_scale=noise, noise_scale_w=noisew, length_scale=length, sid=speaker_name, language=language, hps=model_holder.models[model_id].hps, net_g=model_holder.models[model_id].net_g, device=model_holder.models[model_id].device, emotion=emotion, ) ) if i != len(texts) - 1: audios.append(np.zeros(int(44100 * split_interval))) audio = np.concatenate(audios) end_time = datetime.datetime.now() duration = (end_time - start_time).total_seconds() print(f"{end_time}: Done, {duration} seconds.") return f"Success, time: {duration} seconds.", ( model_holder.models[model_id].hps.data.sampling_rate, audio, ) except Exception as e: print(f"Error: {e}") return f"エラー\n{e}", None initial_text = "この電車は、急行、調布ゆきです。" example_local = [ [initial_text, "JP"], [ # ChatGPTに考えてもらった告白セリフ """私、ずっと前からあなたのことを見てきました。あなたの笑顔、優しさ、強さに、心惹かれていたんです。 友達として過ごす中で、あなたのことがだんだんと特別な存在になっていくのがわかりました。 えっと、私、あなたのことが好きです!もしよければ、私と付き合ってくれませんか?""", "JP", ], [ # 夏目漱石『吾輩は猫である』 """吾輩は猫である。名前はまだ無い。 どこで生れたかとんと見当がつかぬ。なんでも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。 吾輩はここで始めて人間というものを見た。しかもあとで聞くと、それは書生という、人間中で一番獰悪な種族であったそうだ。 この書生というのは時々我々を捕まえて煮て食うという話である。""", "JP", ], [ # 梶井基次郎『桜の樹の下には』 """桜の樹の下には屍体が埋まっている!これは信じていいことなんだよ。 何故って、桜の花があんなにも見事に咲くなんて信じられないことじゃないか。俺はあの美しさが信じられないので、このにさんにち不安だった。 しかしいま、やっとわかるときが来た。桜の樹の下には屍体が埋まっている。これは信じていいことだ。""", "JP", ], [ # ChatGPTと考えた、感情を表すセリフ """やったー!テストで満点取れたよ!私とっても嬉しいな! どうして私の意見を無視するの?許せない!ムカつく!あんたなんか死ねばいいのに。 あはははっ!この漫画めっちゃ笑える、見てよこれ、ふふふ、あはは。 あなたがいなくなって、私は一人になっちゃって、泣いちゃいそうなほど悲しい。""", "JP", ], [ # 上の丁寧語バージョン """やりました!テストで満点取れましたよ!私とっても嬉しいです! どうして私の意見を無視するんですか?許せません!ムカつきます!あんたなんか死んでください。 あはははっ!この漫画めっちゃ笑えます、見てくださいこれ、ふふふ、あはは。 あなたがいなくなって、私は一人になっちゃって、泣いちゃいそうなほど悲しいです。""", "JP", ], [ # ChatGPTに考えてもらった音声合成の説明文章 """音声合成は、機械学習を活用して、テキストから人の声を再現する技術です。この技術は、言語の構造を解析し、それに基づいて音声を生成します。 この分野の最新の研究成果を使うと、より自然で表現豊かな音声の生成が可能である。深層学習の応用により、感情やアクセントを含む声質の微妙な変化も再現することが出来る。""", "JP", ], [ "Speech synthesis is the artificial production of human speech. A computer system used for this purpose is called a speech synthesizer, and can be implemented in software or hardware products.", "EN", ], ] example_hf_spaces = [ [initial_text, "JP"], ["えっと、私、あなたのことが好きです!もしよければ付き合ってくれませんか?", "JP"], ["吾輩は猫である。名前はまだ無い。", "JP"], ["どこで生れたかとんと見当がつかぬ。なんでも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。", "JP"], ["やったー!テストで満点取れたよ!私とっても嬉しいな!", "JP"], ["どうして私の意見を無視するの?許せない!ムカつく!あんたなんか死ねばいいのに。", "JP"], ["あはははっ!この漫画めっちゃ笑える、見てよこれ、ふふふ、あはは。", "JP"], ["あなたがいなくなって、私は一人になっちゃって、泣いちゃいそうなほど悲しい。", "JP"], ["深層学習の応用により、感情やアクセントを含む声質の微妙な変化も再現されている。", "JP"], ] initial_md = """ # 京王線自動放送メーカー """ if __name__ == "__main__": device = "cuda" if torch.cuda.is_available() else "cpu" # device = "cpu" languages = ["JP", "EN", "ZH"] examples = example_hf_spaces if is_hf_spaces else example_local model_names = refresh_model() with gr.Blocks() as app: gr.Markdown(initial_md) with gr.Row(): with gr.Column(): with gr.Row(): model_input = gr.Dropdown( label="モデル一覧", choices=model_names, type="index", scale=3, ) if not is_hf_spaces: refresh_button = gr.Button("モデル一覧を更新", scale=1) refresh_button.click( update_model_dropdown, outputs=[model_input] ) text_input = gr.TextArea(label="テキスト", value=initial_text) language = gr.Dropdown(choices=languages, value="JP", label="言語") line_split = gr.Checkbox(label="改行で分けて生成", value=not is_hf_spaces) split_interval = gr.Slider( minimum=0.1, maximum=2, value=0.5, step=0.1, label="分けた場合に挟む無音の長さ" ) with gr.Accordion(label="詳細設定", open=False): emotion = gr.Slider( minimum=0, maximum=9, value=0, step=1, label="Emotion" ) sdp_ratio = gr.Slider( minimum=0, maximum=1, value=0.2, step=0.1, label="SDP Ratio" ) noise_scale = gr.Slider( minimum=0.1, maximum=2, value=0.6, step=0.1, label="Noise" ) noise_scale_w = gr.Slider( minimum=0.1, maximum=2, value=0.8, step=0.1, label="Noise_W" ) length_scale = gr.Slider( minimum=0.1, maximum=2, value=1.0, step=0.1, label="Length" ) with gr.Column(): button = gr.Button("実行", variant="primary") text_output = gr.Textbox(label="情報") audio_output = gr.Audio(label="結果") button.click( _voice, inputs=[ model_input, # model_id text_input, # text language, # language emotion, # emotion sdp_ratio, # sdp_ratio noise_scale, # noise noise_scale_w, # noise_w length_scale, # length line_split, # auto_split split_interval, # interval ], outputs=[text_output, audio_output], ) app.launch(inbrowser=True)