Spaces:
Paused
Paused
zxsipola123456
commited on
Commit
•
4a8f1f8
1
Parent(s):
ed0009e
Create app.py.bk
Browse files
app.py.bk
ADDED
@@ -0,0 +1,220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import tempfile
|
3 |
+
from openai import OpenAI
|
4 |
+
from tts_voice import tts_order_voice
|
5 |
+
import edge_tts
|
6 |
+
import numpy as np
|
7 |
+
import anyio
|
8 |
+
import torch
|
9 |
+
import torchaudio
|
10 |
+
import gradio as gr
|
11 |
+
from scipy.io import wavfile
|
12 |
+
from scipy.io.wavfile import write
|
13 |
+
#新加内容
|
14 |
+
import asyncio
|
15 |
+
import threading
|
16 |
+
import requests
|
17 |
+
from aiohttp import ClientSession
|
18 |
+
|
19 |
+
# # 异步函数进行预加载
|
20 |
+
# async def fetch_link_content(url):
|
21 |
+
# async with ClientSession() as session:
|
22 |
+
# async with session.get(url) as response:
|
23 |
+
# return await response.text()
|
24 |
+
|
25 |
+
# # 后台任务确保不阻塞主线程
|
26 |
+
# def fetch_link_in_background(url):
|
27 |
+
# loop = asyncio.new_event_loop()
|
28 |
+
# asyncio.set_event_loop(loop)
|
29 |
+
# content = loop.run_until_complete(fetch_link_content(url))
|
30 |
+
# # 将 content 缓存起来或者在全局状态中保存以供后续使用
|
31 |
+
# print("预加载的内容:", content)
|
32 |
+
|
33 |
+
# link_url = "https://huggingface.co/api/spaces/by-subdomain/zxsipola123456-tts"
|
34 |
+
# background_thread = threading.Thread(target=fetch_link_in_background, args=(link_url,))
|
35 |
+
# background_thread.start()
|
36 |
+
|
37 |
+
# 创建 KNN-VC 模型
|
38 |
+
knn_vc = torch.hub.load('bshall/knn-vc', 'knn_vc', prematched=True, trust_repo=True, pretrained=True, device='cpu')
|
39 |
+
|
40 |
+
# 初始化 language_dict
|
41 |
+
language_dict = tts_order_voice
|
42 |
+
|
43 |
+
# 异步文字转语音函数
|
44 |
+
async def text_to_speech_edge(text, language_code):
|
45 |
+
voice = language_dict[language_code]
|
46 |
+
communicate = edge_tts.Communicate(text, voice)
|
47 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
|
48 |
+
tmp_path = tmp_file.name
|
49 |
+
|
50 |
+
await communicate.save(tmp_path)
|
51 |
+
|
52 |
+
return "语音合成完成:{}".format(text), tmp_path
|
53 |
+
|
54 |
+
def voice_change(audio_in, audio_ref):
|
55 |
+
samplerate1, data1 = wavfile.read(audio_in)
|
56 |
+
samplerate2, data2 = wavfile.read(audio_ref)
|
57 |
+
|
58 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_audio_in, \
|
59 |
+
tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_audio_ref:
|
60 |
+
audio_in_path = tmp_audio_in.name
|
61 |
+
audio_ref_path = tmp_audio_ref.name
|
62 |
+
write(audio_in_path, samplerate1, data1)
|
63 |
+
write(audio_ref_path, samplerate2, data2)
|
64 |
+
|
65 |
+
query_seq = knn_vc.get_features(audio_in_path)
|
66 |
+
matching_set = knn_vc.get_matching_set([audio_ref_path])
|
67 |
+
out_wav = knn_vc.match(query_seq, matching_set, topk=4)
|
68 |
+
output_path = 'output.wav'
|
69 |
+
torchaudio.save(output_path, out_wav[None], 16000)
|
70 |
+
return output_path
|
71 |
+
|
72 |
+
|
73 |
+
# #验证中转api key是否有效
|
74 |
+
# def validate_api_key(api_proxy_key):
|
75 |
+
# try:
|
76 |
+
# client = OpenAI(api_key=api_proxy_key, base_url='https://lmzh.top/v1')
|
77 |
+
# # 测试调用一个简单的API来验证Key
|
78 |
+
# response = client.models.list()
|
79 |
+
# return True
|
80 |
+
# except Exception:
|
81 |
+
# return False
|
82 |
+
|
83 |
+
# # 更新Edge TTS标签页状态的函数
|
84 |
+
# def update_edge_tts_tab(api_proxy_key):
|
85 |
+
# is_valid = validate_api_key(api_proxy_key)
|
86 |
+
# return gr.update(interactive=is_valid)
|
87 |
+
|
88 |
+
|
89 |
+
# 文字转语音(OpenAI)
|
90 |
+
def tts(text, model, voice, api_key):
|
91 |
+
if len(text) > 300:
|
92 |
+
raise gr.Error('您输入的文本字符多于300个,请缩短您的文本')
|
93 |
+
if api_key == '':
|
94 |
+
raise gr.Error('请填写您的 中转API Key')
|
95 |
+
|
96 |
+
try:
|
97 |
+
client = OpenAI(api_key=api_key, base_url='https://lmzh.top/v1')
|
98 |
+
response = client.audio.speech.create(
|
99 |
+
model=model,
|
100 |
+
voice=voice,
|
101 |
+
input=text,
|
102 |
+
)
|
103 |
+
except Exception as error:
|
104 |
+
raise gr.Error(f"生成语音时出错:{error}")
|
105 |
+
|
106 |
+
with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as temp_file:
|
107 |
+
temp_file.write(response.content)
|
108 |
+
|
109 |
+
temp_file_path = temp_file.name
|
110 |
+
|
111 |
+
return temp_file_path
|
112 |
+
|
113 |
+
|
114 |
+
|
115 |
+
def tts1(text, model, voice, api_key):
|
116 |
+
if len(text)>300:
|
117 |
+
raise gr.Error('您输入的文本字符多于300个,请缩短您的文本')
|
118 |
+
if api_key == '':
|
119 |
+
raise gr.Error('Please enter your OpenAI API Key')
|
120 |
+
else:
|
121 |
+
try:
|
122 |
+
client = OpenAI(api_key=api_key)
|
123 |
+
|
124 |
+
response = client.audio.speech.create(
|
125 |
+
model=model, # "tts-1","tts-1-hd"
|
126 |
+
voice=voice, # 'alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'
|
127 |
+
input=text,
|
128 |
+
)
|
129 |
+
|
130 |
+
except Exception as error:
|
131 |
+
# Handle any exception that occurs
|
132 |
+
raise gr.Error("An error occurred while generating speech. Please check your API key and try again.")
|
133 |
+
print(str(error))
|
134 |
+
|
135 |
+
# Create a temp file to save the audio
|
136 |
+
with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as temp_file:
|
137 |
+
temp_file.write(response.content)
|
138 |
+
|
139 |
+
# Get the file path of the temp file
|
140 |
+
temp_file_path = temp_file.name
|
141 |
+
|
142 |
+
return temp_file_path
|
143 |
+
|
144 |
+
|
145 |
+
|
146 |
+
|
147 |
+
# Gradio 前端设计
|
148 |
+
app = gr.Blocks(title="TTS文本生成语音 + AI秒变声")
|
149 |
+
|
150 |
+
with app:
|
151 |
+
gr.Markdown("# <center>TTS文本生成语音 + AI秒变声</center>")
|
152 |
+
gr.Markdown("### <center>key获取地址[here](https://buy.sipola.cn),ai文案生成(可使用中转key和官方key)请访问 [here](https://ai.sipola.cn)</center>")
|
153 |
+
|
154 |
+
with gr.Tab("中转key-TTS文本生语音"):
|
155 |
+
with gr.Row(variant='panel'):
|
156 |
+
api_proxy_key = gr.Textbox(type='password', label='API Key', placeholder='请在此填写您在https://buy.sipola.cn获取的中转API Key')
|
157 |
+
model = gr.Dropdown(choices=['tts-1','tts-1-hd'], label='请选择模型(tts-1推理更快,tts-1-hd音质更好)', value='tts-1')
|
158 |
+
voice = gr.Dropdown(choices=['alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'], label='请选择一个说话人', value='alloy')
|
159 |
+
with gr.Row():
|
160 |
+
with gr.Column():
|
161 |
+
inp_text = gr.Textbox(label="请填写您想生成的文本中英文皆可", placeholder="请输入ai生成的文案,不要超过300字,最好200字左右", lines=5)
|
162 |
+
btn_text = gr.Button("一键生成音频", variant="primary")
|
163 |
+
with gr.Column():
|
164 |
+
inp1 = gr.Audio(type="filepath", label="TTS真实拟声", interactive=False)
|
165 |
+
inp2 = gr.Audio(type="filepath", label="请上传同文案参照音频,可自己读取同文案录音")
|
166 |
+
btn1 = gr.Button("一键AI变声合成", variant="primary")
|
167 |
+
with gr.Column():
|
168 |
+
out1 = gr.Audio(type="filepath", label="AI变声后的专属音频")
|
169 |
+
btn_text.click(tts, [inp_text, model, voice, api_proxy_key], inp1)
|
170 |
+
btn1.click(voice_change, [inp1, inp2], out1)
|
171 |
+
|
172 |
+
with gr.Tab("官方key-TTS文本生语音"):
|
173 |
+
with gr.Row(variant='panel'):
|
174 |
+
api_key = gr.Textbox(type='password', label='API Key', placeholder='请在此填写您在https://buy.sipola.cn 获取的官方API Key')
|
175 |
+
model = gr.Dropdown(choices=['tts-1','tts-1-hd'], label='请选择模型(tts-1推理更快,tts-1-hd音质更好)', value='tts-1')
|
176 |
+
voice = gr.Dropdown(choices=['alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'], label='请选择一个说话人', value='alloy')
|
177 |
+
with gr.Row():
|
178 |
+
with gr.Column():
|
179 |
+
inp_text = gr.Textbox(label="请填写您想生成的文本中英文皆可", placeholder="请输入ai生成的文案,不要超过300字,最好200字左右", lines=5)
|
180 |
+
btn_text = gr.Button("一键生成音频", variant="primary")
|
181 |
+
with gr.Column():
|
182 |
+
inp1 = gr.Audio(type="filepath", label="TTS真实拟声", interactive=False)
|
183 |
+
inp2 = gr.Audio(type="filepath", label="请上传同文案参照音频,可自己读取同文案录音")
|
184 |
+
btn1 = gr.Button("一键AI变声合成", variant="primary")
|
185 |
+
with gr.Column():
|
186 |
+
out1 = gr.Audio(type="filepath", label="AI变声后的专属音频")
|
187 |
+
btn_text.click(tts1, [inp_text, model, voice, api_key], inp1)
|
188 |
+
btn1.click(voice_change, [inp1, inp2], out1)
|
189 |
+
|
190 |
+
with gr.Tab("TTS-AI变声") as edge_tts_tab:
|
191 |
+
with gr.Row():
|
192 |
+
with gr.Column():
|
193 |
+
input_text = gr.Textbox(label="请填写您想生成的文本中英文皆可",placeholder="请输入ai生成的文案,不要超过300字,最好200字左右",lines=5)
|
194 |
+
btn_edge = gr.Button("一键生成音频", variant="primary")
|
195 |
+
with gr.Column():
|
196 |
+
default_language = list(language_dict.keys())[15]
|
197 |
+
language = gr.Dropdown(choices=list(language_dict.keys()), value=default_language, label="请选择文本对应的语言")
|
198 |
+
output_audio = gr.Audio(type="filepath", label="TTS真实拟声", interactive=False, show_download_button=False)
|
199 |
+
output_text = gr.Textbox(label="输出文本", visible=False)
|
200 |
+
with gr.Row():
|
201 |
+
with gr.Column():
|
202 |
+
inp_vc = gr.Audio(type="filepath", label="请上传和文案相同参照音频,可自己读取文案录音或者用TTS文本生语音同文案生成的音频")
|
203 |
+
btn_vc = gr.Button("一键AI变声合成", variant="primary")
|
204 |
+
with gr.Column():
|
205 |
+
out_vc = gr.Audio(type="filepath", label="AI变声后的专属音频")
|
206 |
+
|
207 |
+
btn_edge.click(lambda text, lang: anyio.run(text_to_speech_edge, text, lang), [input_text, language], [output_text, output_audio])
|
208 |
+
btn_vc.click(voice_change, [output_audio, inp_vc], out_vc)
|
209 |
+
# 监听API Key输入框的变化并更新Edge TTS标签页的状态
|
210 |
+
# api_proxy_key.change(
|
211 |
+
# update_edge_tts_tab,
|
212 |
+
# inputs=[api_proxy_key],
|
213 |
+
# outputs=[edge_tts_tab]
|
214 |
+
# )
|
215 |
+
|
216 |
+
gr.HTML('''
|
217 |
+
<div class="footer">
|
218 |
+
<center><p>Power by sipola </p></center>
|
219 |
+
</div>
|
220 |
+
''')
|