Spaces:
Running
Running
Upload app.py
Browse files
app.py
CHANGED
@@ -7,10 +7,7 @@ import os
|
|
7 |
import re
|
8 |
from pydub import AudioSegment
|
9 |
import uuid
|
10 |
-
import io
|
11 |
import edge_tts
|
12 |
-
import asyncio
|
13 |
-
import aiofiles
|
14 |
import json
|
15 |
|
16 |
def create_client(api_key=None):
|
@@ -100,37 +97,46 @@ Follow this JSON example structure, MUST be in {language} language:
|
|
100 |
podcast_match = re.search(r'{.*}', response.choices[0].message.content, re.DOTALL)
|
101 |
if podcast_match:
|
102 |
podcast_json = podcast_match.group(0)
|
103 |
-
# 嘗試解析 JSON,如果失敗則進行清理
|
104 |
try:
|
105 |
json.loads(podcast_json)
|
106 |
except json.JSONDecodeError:
|
107 |
-
|
108 |
-
podcast_json = re.sub(r',\s*
|
109 |
-
podcast_json = re.sub(r',\s*]', ']', podcast_json) # 移除數組最後一個逗號
|
110 |
return podcast_json
|
111 |
else:
|
112 |
-
raise gr.Error("
|
113 |
except Exception as e:
|
114 |
if "API key not valid" in str(e):
|
115 |
-
raise gr.Error("
|
116 |
elif "rate limit" in str(e).lower():
|
117 |
-
raise gr.Error("
|
118 |
else:
|
119 |
-
raise gr.Error(f"
|
120 |
|
121 |
async def tts_generate(input_text, speaker1, speaker2):
|
122 |
voice_names = {
|
123 |
-
"YunJhe -
|
124 |
-
"HsiaoChen -
|
125 |
-
"HsiaoYu -
|
126 |
-
"
|
127 |
-
"
|
128 |
-
"
|
129 |
-
"
|
130 |
-
"
|
131 |
-
"
|
132 |
-
"
|
133 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
}
|
135 |
|
136 |
speaker1_voice = voice_names[speaker1]
|
@@ -166,14 +172,14 @@ async def tts_generate(input_text, speaker1, speaker2):
|
|
166 |
|
167 |
audio = AudioSegment.from_mp3(audio_file)
|
168 |
combined += audio
|
169 |
-
os.remove(audio_file)
|
170 |
|
171 |
podcast_json["podcast"].append({
|
172 |
"speaker": speaker_map.get(speaker, speaker),
|
173 |
"line": text
|
174 |
})
|
175 |
|
176 |
-
output_file = f"
|
177 |
combined.export(output_file, format="mp3")
|
178 |
return output_file
|
179 |
|
@@ -185,7 +191,7 @@ async def process_podcast(input_text, language, speaker1, speaker2, api_key):
|
|
185 |
with gr.Blocks() as iface:
|
186 |
gr.Markdown("# 🎙️ Generated Podcast Audio. Deployed by 江信宗")
|
187 |
|
188 |
-
input_text = gr.Textbox(label="請輸入 Podcast 話題(建議50~500字之間)")
|
189 |
|
190 |
with gr.Row():
|
191 |
Language = gr.Dropdown(
|
@@ -197,39 +203,52 @@ with gr.Blocks() as iface:
|
|
197 |
)
|
198 |
|
199 |
speaker_choices = [
|
200 |
-
"YunJhe -
|
201 |
-
"HsiaoChen -
|
202 |
-
"HsiaoYu -
|
203 |
-
"
|
204 |
-
"
|
205 |
-
"
|
206 |
-
"
|
207 |
-
"
|
208 |
-
"
|
209 |
-
"
|
210 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
211 |
]
|
212 |
|
213 |
Speaker_1 = gr.Dropdown(
|
214 |
choices=speaker_choices,
|
215 |
-
value="YunJhe -
|
216 |
label="主持人的語音",
|
217 |
interactive=True,
|
218 |
scale=2
|
219 |
)
|
220 |
Speaker_2 = gr.Dropdown(
|
221 |
choices=speaker_choices,
|
222 |
-
value="HsiaoChen -
|
223 |
label="來賓的語音",
|
224 |
interactive=True,
|
225 |
scale=2
|
226 |
)
|
227 |
|
228 |
-
|
|
|
|
|
|
|
229 |
podcast_script = gr.Textbox(label="生成的結果")
|
230 |
audio_output = gr.Audio(label="生成的音頻")
|
231 |
|
232 |
-
generate_button = gr.Button("生成")
|
233 |
generate_button.click(fn=process_podcast, inputs=[input_text, Language, Speaker_1, Speaker_2, api_key], outputs=[podcast_script, audio_output])
|
234 |
|
235 |
if __name__ == "__main__":
|
|
|
7 |
import re
|
8 |
from pydub import AudioSegment
|
9 |
import uuid
|
|
|
10 |
import edge_tts
|
|
|
|
|
11 |
import json
|
12 |
|
13 |
def create_client(api_key=None):
|
|
|
97 |
podcast_match = re.search(r'{.*}', response.choices[0].message.content, re.DOTALL)
|
98 |
if podcast_match:
|
99 |
podcast_json = podcast_match.group(0)
|
|
|
100 |
try:
|
101 |
json.loads(podcast_json)
|
102 |
except json.JSONDecodeError:
|
103 |
+
podcast_json = re.sub(r',\s*}', '}', podcast_json)
|
104 |
+
podcast_json = re.sub(r',\s*]', ']', podcast_json)
|
|
|
105 |
return podcast_json
|
106 |
else:
|
107 |
+
raise gr.Error("生成 Podcast 劇本失敗!!請稍後再試。")
|
108 |
except Exception as e:
|
109 |
if "API key not valid" in str(e):
|
110 |
+
raise gr.Error("無效的 API 金鑰!!請提供有效的 API 金鑰。")
|
111 |
elif "rate limit" in str(e).lower():
|
112 |
+
raise gr.Error("API 金鑰使用額度已超過限制!!請稍後再試或使用其他 API 金鑰。")
|
113 |
else:
|
114 |
+
raise gr.Error(f"生成 Podcast 劇本失敗!!請稍後再試。")
|
115 |
|
116 |
async def tts_generate(input_text, speaker1, speaker2):
|
117 |
voice_names = {
|
118 |
+
"YunJhe - 臺灣國語 (Male)": "zh-TW-YunJheNeural",
|
119 |
+
"HsiaoChen - 臺灣國語 (Female)": "zh-TW-HsiaoChenNeural",
|
120 |
+
"HsiaoYu - 臺灣國語 (Female)": "zh-TW-HsiaoYuNeural",
|
121 |
+
"HiuGaai - 中文 (Female)": "zh-HK-HiuGaaiNeural",
|
122 |
+
"HiuMaan - 中文 (Female)": "zh-HK-HiuMaanNeural",
|
123 |
+
"WanLung - 中文 (Female)": "zh-HK-WanLungNeural",
|
124 |
+
"Xiaoxiao - 中文 (Female)": "zh-CN-XiaoxiaoNeural",
|
125 |
+
"Xiaoyi - 中文 (Female)": "zh-CN-XiaoyiNeural",
|
126 |
+
"Yunjian - 中文 (Male)": "zh-CN-YunjianNeural",
|
127 |
+
"Yunxi - 中文 (Male)": "zh-CN-YunxiNeural",
|
128 |
+
"Yunxia - 中文 (Male)": "zh-CN-YunxiaNeural",
|
129 |
+
"Yunyang - 中文 (Male)": "zh-CN-YunyangNeural",
|
130 |
+
"Xiaobei - 中文 (Female)": "zh-CN-liaoning-XiaobeiNeural",
|
131 |
+
"Xiaoni - 中文 (Female)": "zh-CN-shaanxi-XiaoniNeural",
|
132 |
+
"Andrew - English (Male)": "en-US-AndrewMultilingualNeural",
|
133 |
+
"Ava - English (Female)": "en-US-AvaMultilingualNeural",
|
134 |
+
"Brian - English (Male)": "en-US-BrianMultilingualNeural",
|
135 |
+
"Emma - English (Female)": "en-US-EmmaMultilingualNeural",
|
136 |
+
"Florian - German (Male)": "de-DE-FlorianMultilingualNeural",
|
137 |
+
"Seraphina - German (Female)": "de-DE-SeraphinaMultilingualNeural",
|
138 |
+
"Remy - French (Male)": "fr-FR-RemyMultilingualNeural",
|
139 |
+
"Vivienne - French (Female)": "fr-FR-VivienneMultilingualNeural"
|
140 |
}
|
141 |
|
142 |
speaker1_voice = voice_names[speaker1]
|
|
|
172 |
|
173 |
audio = AudioSegment.from_mp3(audio_file)
|
174 |
combined += audio
|
175 |
+
os.remove(audio_file)
|
176 |
|
177 |
podcast_json["podcast"].append({
|
178 |
"speaker": speaker_map.get(speaker, speaker),
|
179 |
"line": text
|
180 |
})
|
181 |
|
182 |
+
output_file = f"Jiangxz_{uuid.uuid4()}.mp3"
|
183 |
combined.export(output_file, format="mp3")
|
184 |
return output_file
|
185 |
|
|
|
191 |
with gr.Blocks() as iface:
|
192 |
gr.Markdown("# 🎙️ Generated Podcast Audio. Deployed by 江信宗")
|
193 |
|
194 |
+
input_text = gr.Textbox(label="請輸入 Podcast 話題(建議50~500字之間)", placeholder="輸入 Podcast 話題簡易內容......")
|
195 |
|
196 |
with gr.Row():
|
197 |
Language = gr.Dropdown(
|
|
|
203 |
)
|
204 |
|
205 |
speaker_choices = [
|
206 |
+
"YunJhe - 臺灣國語 (Male)",
|
207 |
+
"HsiaoChen - 臺灣國語 (Female)",
|
208 |
+
"HsiaoYu - 臺灣國語 (Female)",
|
209 |
+
"HiuGaai - 中文 (Female)",
|
210 |
+
"HiuMaan - 中文 (Female)",
|
211 |
+
"WanLung - 中文 (Female)",
|
212 |
+
"Xiaoxiao - 中文 (Female)",
|
213 |
+
"Xiaoyi - 中文 (Female)",
|
214 |
+
"Yunjian - 中文 (Male)",
|
215 |
+
"Yunxi - 中文 (Male)",
|
216 |
+
"Yunxia - 中文 (Male)",
|
217 |
+
"Yunyang - 中文 (Male)",
|
218 |
+
"Xiaobei - 中文 (Female)",
|
219 |
+
"Xiaoni - 中文 (Female)",
|
220 |
+
"Andrew - English (Male)",
|
221 |
+
"Ava - English (Female)",
|
222 |
+
"Brian - English (Male)",
|
223 |
+
"Emma - English (Female)",
|
224 |
+
"Florian - German (Male)",
|
225 |
+
"Seraphina - German (Female)",
|
226 |
+
"Remy - French (Male)",
|
227 |
+
"Vivienne - French (Female)"
|
228 |
]
|
229 |
|
230 |
Speaker_1 = gr.Dropdown(
|
231 |
choices=speaker_choices,
|
232 |
+
value="YunJhe - 臺灣國語 (Male)",
|
233 |
label="主持人的語音",
|
234 |
interactive=True,
|
235 |
scale=2
|
236 |
)
|
237 |
Speaker_2 = gr.Dropdown(
|
238 |
choices=speaker_choices,
|
239 |
+
value="HsiaoChen - 臺灣國語 (Female)",
|
240 |
label="來賓的語音",
|
241 |
interactive=True,
|
242 |
scale=2
|
243 |
)
|
244 |
|
245 |
+
with gr.Row():
|
246 |
+
generate_button = gr.Button("生成", scale=2)
|
247 |
+
api_key = gr.Textbox(label="API Key", type="password", placeholder="API authentication key for large language models", scale=1)
|
248 |
+
|
249 |
podcast_script = gr.Textbox(label="生成的結果")
|
250 |
audio_output = gr.Audio(label="生成的音頻")
|
251 |
|
|
|
252 |
generate_button.click(fn=process_podcast, inputs=[input_text, Language, Speaker_1, Speaker_2, api_key], outputs=[podcast_script, audio_output])
|
253 |
|
254 |
if __name__ == "__main__":
|