Spaces:
Sleeping
Sleeping
| from datetime import datetime | |
| import gradio as gr | |
| import json, os | |
| import requests | |
| import numpy as np | |
| from string import Template | |
| import wave, io | |
| # 在开头加入路径 | |
| import os, sys | |
| now_dir = os.getcwd() | |
| sys.path.insert(0, now_dir) | |
| import logging | |
| logging.getLogger("markdown_it").setLevel(logging.ERROR) | |
| logging.getLogger("urllib3").setLevel(logging.ERROR) | |
| logging.getLogger("httpcore").setLevel(logging.ERROR) | |
| logging.getLogger("httpx").setLevel(logging.ERROR) | |
| logging.getLogger("asyncio").setLevel(logging.ERROR) | |
| logging.getLogger("charset_normalizer").setLevel(logging.ERROR) | |
| logging.getLogger("torchaudio._extension").setLevel(logging.ERROR) | |
| from Synthesizers.base import Base_TTS_Synthesizer, Base_TTS_Task, get_wave_header_chunk | |
| from src.common_config_manager import app_config, __version__ | |
| frontend_version = __version__ | |
| def load_character_emotions(character_name, characters_and_emotions): | |
| emotion_options = ["default"] | |
| emotion_options = characters_and_emotions.get(character_name, ["default"]) | |
| return gr.Dropdown(emotion_options, value="default") | |
| synthesizer_name = app_config.synthesizer | |
| from importlib import import_module | |
| import tools.i18n.i18n as i18n_module | |
| # 设置国际化支持 | |
| i18n = i18n_module.I18nAuto(language=app_config.locale, locale_path=f"Synthesizers/{synthesizer_name}/configs/i18n/locale") | |
| # 动态导入合成器模块, 此处可写成 from Synthesizers.xxx import TTS_Synthesizer, TTS_Task | |
| synthesizer_module = import_module(f"Synthesizers.{synthesizer_name}") | |
| TTS_Synthesizer = synthesizer_module.TTS_Synthesizer | |
| TTS_Task = synthesizer_module.TTS_Task | |
| # 创建合成器实例 | |
| tts_synthesizer:Base_TTS_Synthesizer = TTS_Synthesizer(debug_mode=True) | |
| import soundfile as sf | |
| all_gradio_components = {} | |
| from time import time as ttime | |
| def get_audio(*data, streaming=False): | |
| data = dict(zip([key for key in all_gradio_components.keys()], data)) | |
| data["stream"] = streaming | |
| if data.get("text") in ["", None]: | |
| gr.Warning(i18n("文本不能为空")) | |
| return None, None | |
| try: | |
| task: Base_TTS_Task= tts_synthesizer.params_parser(data) | |
| t2 = ttime() | |
| if not streaming: | |
| if synthesizer_name == "remote": | |
| save_path = tts_synthesizer.generate(task, return_type="filepath") | |
| yield save_path | |
| else: | |
| gen = tts_synthesizer.generate(task, return_type="numpy") | |
| yield next(gen) | |
| else: | |
| gen = tts_synthesizer.generate(task, return_type="numpy") | |
| sample_rate = 32000 if task.sample_rate in [None, 0] else task.sample_rate | |
| yield get_wave_header_chunk(sample_rate=sample_rate) | |
| for chunk in gen: | |
| yield chunk | |
| except Exception as e: | |
| gr.Warning(f"Error: {e}") | |
| from functools import partial | |
| get_streaming_audio = partial(get_audio, streaming=True) | |
| def stopAudioPlay(): | |
| return | |
| global characters_and_emotions_dict | |
| characters_and_emotions_dict = {} | |
| def get_characters_and_emotions(): | |
| global characters_and_emotions_dict | |
| # 直接检查字典是否为空,如果不是,直接返回,避免重复获取 | |
| if characters_and_emotions_dict == {}: | |
| characters_and_emotions_dict = tts_synthesizer.get_characters() | |
| print(characters_and_emotions_dict) | |
| return characters_and_emotions_dict | |
| def change_character_list( | |
| character="", emotion="default" | |
| ): | |
| characters_and_emotions = {} | |
| try: | |
| characters_and_emotions = get_characters_and_emotions() | |
| character_names = [i for i in characters_and_emotions] | |
| if len(character_names) != 0: | |
| if character in character_names: | |
| character_name_value = character | |
| else: | |
| character_name_value = character_names[0] | |
| else: | |
| character_name_value = "" | |
| emotions = characters_and_emotions.get(character_name_value, ["default"]) | |
| emotion_value = emotion | |
| except: | |
| character_names = [] | |
| character_name_value = "" | |
| emotions = ["default"] | |
| emotion_value = "default" | |
| characters_and_emotions = {} | |
| return ( | |
| gr.Dropdown(character_names, value=character_name_value, label=i18n("选择角色")), | |
| gr.Dropdown(emotions, value=emotion_value, label=i18n("情感列表"), interactive=True), | |
| characters_and_emotions, | |
| ) | |
| def cut_sentence_multilang(text, max_length=30): | |
| if max_length == -1: | |
| return text, "" | |
| # 初始化计数器 | |
| word_count = 0 | |
| in_word = False | |
| for index, char in enumerate(text): | |
| if char.isspace(): # 如果当前字符是空格 | |
| in_word = False | |
| elif char.isascii() and not in_word: # 如果是ASCII字符(英文)并且不在单词内 | |
| word_count += 1 # 新的英文单词 | |
| in_word = True | |
| elif not char.isascii(): # 如果字符非英文 | |
| word_count += 1 # 每个非英文字符单独计为一个字 | |
| if word_count > max_length: | |
| return text[:index], text[index:] | |
| return text, "" | |
| default_text = i18n("我是一个粉刷匠,粉刷本领强。我要把那新房子,刷得更漂亮。刷了房顶又刷墙,刷子像飞一样。哎呀我的小鼻子,变呀变了样。") | |
| information = "" | |
| try: | |
| with open("Information.md", "r", encoding="utf-8") as f: | |
| information = f.read() | |
| except: | |
| pass | |
| try: | |
| max_text_length = app_config.max_text_length | |
| except: | |
| max_text_length = -1 | |
| from webuis.builders.gradio_builder import GradioTabBuilder | |
| ref_settings = tts_synthesizer.ui_config.get("ref_settings", []) | |
| basic_settings = tts_synthesizer.ui_config.get("basic_settings", []) | |
| advanced_settings = tts_synthesizer.ui_config.get("advanced_settings", []) | |
| url_setting = tts_synthesizer.ui_config.get("url_settings", []) | |
| tts_task_example : Base_TTS_Task = TTS_Task() | |
| params_config = tts_task_example.params_config | |
| has_character_param = True if "character" in params_config else False | |
| with gr.Blocks() as app: | |
| gr.Markdown(information) | |
| with gr.Row(): | |
| max_text_length_tip = "" if max_text_length == -1 else f"( "+i18n("最大允许长度")+ f" : {max_text_length} ) " | |
| text = gr.Textbox( | |
| value=default_text, label=i18n("输入文本")+max_text_length_tip, interactive=True, lines=8 | |
| ) | |
| text.blur(lambda x: gr.update(value=cut_sentence_multilang(x,max_length=max_text_length)[0]), [text], [text]) | |
| all_gradio_components["text"] = text | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| with gr.Tabs(): | |
| with gr.Tab(label=i18n("角色选项"), visible=has_character_param): | |
| with gr.Group(): | |
| ( | |
| character, | |
| emotion, | |
| characters_and_emotions_, | |
| ) = change_character_list() | |
| characters_and_emotions = gr.State(characters_and_emotions_) | |
| scan_character_list = gr.Button( | |
| i18n("扫描人物列表"), variant="secondary" | |
| ) | |
| all_gradio_components["character"] = character | |
| all_gradio_components["emotion"] = emotion | |
| character.change( | |
| load_character_emotions, | |
| inputs=[character, characters_and_emotions], | |
| outputs=[emotion], | |
| ) | |
| scan_character_list.click( | |
| change_character_list, | |
| inputs=[character, emotion], | |
| outputs=[ | |
| character, | |
| emotion, | |
| characters_and_emotions, | |
| ], | |
| ) | |
| if len(ref_settings) > 0: | |
| with gr.Tab(label=i18n("参考设置")): | |
| ref_settings_tab = GradioTabBuilder( | |
| ref_settings, params_config | |
| ) | |
| ref_settings_components = ref_settings_tab.build() | |
| all_gradio_components.update(ref_settings_components) | |
| with gr.Column(scale=2): | |
| with gr.Tabs(): | |
| if len(basic_settings) > 0: | |
| with gr.Tab(label=i18n("基础选项")): | |
| basic_settings_tab = GradioTabBuilder( | |
| basic_settings, params_config | |
| ) | |
| basic_settings_components = basic_settings_tab.build() | |
| all_gradio_components.update(basic_settings_components) | |
| with gr.Column(scale=2): | |
| with gr.Tabs(): | |
| if len(advanced_settings) > 0: | |
| with gr.Tab(label=i18n("高级选项")): | |
| advanced_settings_tab = GradioTabBuilder( | |
| advanced_settings, params_config | |
| ) | |
| advanced_settings_components = advanced_settings_tab.build() | |
| all_gradio_components.update(advanced_settings_components) | |
| if len(url_setting) > 0: | |
| with gr.Tab(label=i18n("URL设置")): | |
| url_setting_tab = GradioTabBuilder(url_setting, params_config) | |
| url_setting_components = url_setting_tab.build() | |
| all_gradio_components.update(url_setting_components) | |
| with gr.Tabs(): | |
| with gr.Tab(label=i18n("请求完整音频")): | |
| with gr.Row(): | |
| get_full_audio_button = gr.Button(i18n("生成音频"), variant="primary") | |
| full_audio = gr.Audio( | |
| None, label=i18n("音频输出"), type="filepath", streaming=False | |
| ) | |
| get_full_audio_button.click(lambda: gr.update(interactive=False), None, [get_full_audio_button]).then( | |
| get_audio, | |
| inputs=[value for key, value in all_gradio_components.items()], | |
| outputs=[full_audio], | |
| ).then(lambda: gr.update(interactive=True), None, [get_full_audio_button]) | |
| with gr.Tab(label=i18n("流式音频")): | |
| with gr.Row(): | |
| get_streaming_audio_button = gr.Button(i18n("生成流式音频"), variant="primary") | |
| streaming_audio = gr.Audio( | |
| None, label=i18n("音频输出"), type="filepath", streaming=True, autoplay=True | |
| ) | |
| get_streaming_audio_button.click(lambda: gr.update(interactive=False), None, [get_streaming_audio_button]).then( | |
| get_streaming_audio, | |
| inputs=[value for key, value in all_gradio_components.items()], | |
| outputs=[streaming_audio], | |
| ).then(lambda: gr.update(interactive=True), None, [get_streaming_audio_button]) | |
| gr.HTML("<hr style='border-top: 1px solid #ccc; margin: 20px 0;' />") | |
| gr.HTML( | |
| f"""<p>{i18n("这是GSVI。")}{i18n(",当前版本:")}<a href="https://www.yuque.com/xter/zibxlp/awo29n8m6e6soru9">{frontend_version}</a> {i18n("项目开源地址:")} <a href="https://github.com/X-T-E-R/GPT-SoVITS-Inference">Github</a></p> | |
| <p>{i18n("若有疑问或需要进一步了解,可参考文档:")}<a href="{i18n("https://www.yuque.com/xter/zibxlp")}">{i18n("点击查看详细文档")}</a>。</p>""" | |
| ) | |
| # 以下是事件绑定 | |
| # app.load( | |
| # change_character_list, | |
| # inputs=[character, emotion], | |
| # outputs=[ | |
| # character, | |
| # emotion, | |
| # characters_and_emotions, | |
| # ] | |
| # ) | |
| if app_config.also_enable_api == True: | |
| import uvicorn | |
| from pure_api import tts, character_list, set_tts_synthesizer | |
| from fastapi import FastAPI | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from src.api_utils import get_gradio_frp, get_localhost_ipv4_address | |
| set_tts_synthesizer(tts_synthesizer) | |
| fastapi_app:FastAPI = app.app | |
| fastapi_app.add_api_route("/tts", tts, methods=["POST", "GET"]) | |
| fastapi_app.add_api_route("/character_list", character_list, methods=["GET"]) | |
| fastapi_app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| local_link = f"http://127.0.0.1:{app_config.server_port}" | |
| link = local_link | |
| if app_config.is_share: | |
| share_url = get_gradio_frp(app_config.server_name, app_config.server_port, app.share_token) | |
| print("This share link expires in 72 hours.") | |
| print(f"Share URL: {share_url}") | |
| link = share_url | |
| if app_config.inbrowser: | |
| import webbrowser | |
| webbrowser.open(link) | |
| ipv4_address = get_localhost_ipv4_address(app_config.server_name) | |
| ipv4_link = f"http://{ipv4_address}:{app_config.server_port}" | |
| print(f"INFO: Local Network URL: {ipv4_link}") | |
| fastapi_app = gr.mount_gradio_app(fastapi_app, app, path="/") | |
| uvicorn.run(fastapi_app, host=app_config.server_name, port=app_config.server_port) | |
| else: | |
| app.queue().launch(share=app_config.is_share, inbrowser=app_config.inbrowser, server_name=app_config.server_name, server_port=app_config.server_port) | |