TTS_all_in_one / TTSs /base_tts.py
jianuo
支持输出报错的函数调用栈,并用更优雅的方式切换本地推理时的工作目录
c02528e
raw
history blame
No virus
4.62 kB
import abc
import io
import scipy.io.wavfile as wavfile
from pydub import AudioSegment
import traceback
import gradio as gr
def mix_background_music(original_audio, 背景音乐, TTS_up, bg_up):
original_audio = original_audio + TTS_up
ori_out = io.BytesIO()
original_audio.export(ori_out, format="mp3")
ori_out.seek(0)
original_audio_bytes = ori_out.read()
if 背景音乐 is None: # 没有背景音乐
return original_audio_bytes, None
else: # 有背景音乐
# 读取用户上传的背景音乐文件
wav_io = io.BytesIO()
wavfile.write(wav_io, 背景音乐[0], 背景音乐[1])
wav_io.seek(0)
background_music = AudioSegment.from_wav(wav_io)
background_music = background_music + bg_up
# 将背景音乐合并到原始音频中
combined = original_audio.overlay(background_music)
# 使用BytesIO导出合并后的音频为字节串
mix_out = io.BytesIO()
combined.export(mix_out, format="mp3")
mix_out.seek(0) # 重置指针到开始位置
combined_audio_bytes = mix_out.read()
return original_audio_bytes, combined_audio_bytes
class Base_TTS(metaclass=abc.ABCMeta):
default_show = False
@abc.abstractmethod
def _get_config_page(self):
"""要求返回2个参数:config和inputs
config: gr.Group对象,用于包裹所有的输入项
inputs: 一个列表,包含所有的输入项,用于后续的事件绑定,列表的顺序必须和后续_generate方法中参数args的顺序一致
例如:
:return: config, inputs
"""
@abc.abstractmethod
def _generate(self, text, *args):
"""要求返回一个AudioSegment对象
:param text: str,要转换为语音的文本
:param args: 其他参数,与_get_config_page方法中的inputs一一对应
:return: original_audio
示例:
original_audio = AudioSegment.from_file(io.BytesIO(original_audio_bytes), format="mp3")
return original_audio
"""
@abc.abstractmethod
def get_name(self):
"""要求返回一个str,是TTS的名称
:return: name
示例:
return '原神语音合成引擎'
"""
def is_show(self):
"""
是否显示这个TTS
:return: True or False
"""
return True
def _get_submit_button(self):
"""
要求返回1个参数:btn
btn: gr.Button对象,是提交按钮
:return: btn
"""
btn = gr.Button(value="test提交", variant="primary", interactive=True, visible=False)
return btn
def get_config_page(self):
self.config, self.inputs = self._get_config_page()
if self.default_show:
self.config.visible = True
else:
self.config.visible = False
def get_submit_button(self):
self.btn = self._get_submit_button()
if self.default_show:
self.btn.visible = True
else:
self.btn.visible = False
def set_visible(self, visible: bool):
# 检查是否已经获取了config和btn
if not hasattr(self, 'config') or not hasattr(self, 'btn'):
raise Exception('请先调用get_config_page和get_submit_button方法')
self.btn.visible = visible
self.config.visible = visible
def create_interface_event(self, text, audio, TTS_up, bg_up, text_output, ori_audio_output, mix_audio_output):
"""如果交互方法只是的点击提交按钮,可以不用重写这个方法"""
# 检查是否已经获取了config和btn
if not hasattr(self, 'config') or not hasattr(self, 'btn'):
raise Exception('请先调用get_config_page和get_submit_button方法')
self.btn.click(self.generate, inputs=[
text,
audio,
TTS_up,
bg_up
] + self.inputs,
outputs=[text_output, ori_audio_output, mix_audio_output])
def generate(self, text, 背景音乐, TTS_up, bg_up, *args):
try:
original_audio = self._generate(text, *args)
return None, *mix_background_music(original_audio, 背景音乐, TTS_up, bg_up)
except Exception as e:
msg = traceback.format_exc()
return msg + '\n\n' + str(e), None, None