Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,105 +1,110 @@
|
|
1 |
-
import tempfile
|
2 |
-
import edge_tts
|
3 |
-
import gradio as gr
|
4 |
-
import asyncio
|
5 |
-
|
6 |
-
# --- Final, VERIFIED Language & Voice Configuration ---
|
7 |
-
language_dict = {
|
8 |
-
"English": {
|
9 |
-
"Jenny (Female, US)": "en-US-JennyNeural",
|
10 |
-
"Andrew (Male, US)": "en-US-AndrewNeural",
|
11 |
-
"Sonia (Female, UK)": "en-GB-SoniaNeural",
|
12 |
-
"Ryan (Male, UK)": "en-GB-RyanNeural"
|
13 |
-
},
|
14 |
-
"Amharic": {
|
15 |
-
"Mekdes (Female)": "am-ET-MekdesNeural",
|
16 |
-
"Ameha (Male)": "am-ET-AmehaNeural"
|
17 |
-
},
|
18 |
-
"Tigrinya": {
|
19 |
-
# WORKAROUND: Using Amharic voices as a fallback for Tigrinya.
|
20 |
-
"Lulia (Female)": "am-ET-MekdesNeural",
|
21 |
-
"Birhane (Male)": "am-ET-AmehaNeural"
|
22 |
-
},
|
23 |
-
"
|
24 |
-
|
25 |
-
"
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
"
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
"
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
"
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
"
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
"
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
"
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
"
|
54 |
-
|
55 |
-
}
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
try:
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
)
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
105 |
demo.launch()
|
|
|
1 |
+
import tempfile
|
2 |
+
import edge_tts
|
3 |
+
import gradio as gr
|
4 |
+
import asyncio
|
5 |
+
|
6 |
+
# --- Final, VERIFIED Language & Voice Configuration ---
|
7 |
+
language_dict = {
|
8 |
+
"English": {
|
9 |
+
"Jenny (Female, US)": "en-US-JennyNeural",
|
10 |
+
"Andrew (Male, US)": "en-US-AndrewNeural",
|
11 |
+
"Sonia (Female, UK)": "en-GB-SoniaNeural",
|
12 |
+
"Ryan (Male, UK)": "en-GB-RyanNeural"
|
13 |
+
},
|
14 |
+
"Amharic": {
|
15 |
+
"Mekdes (Female)": "am-ET-MekdesNeural",
|
16 |
+
"Ameha (Male)": "am-ET-AmehaNeural"
|
17 |
+
},
|
18 |
+
"Tigrinya": {
|
19 |
+
# WORKAROUND: Using Amharic voices as a fallback for Tigrinya.
|
20 |
+
"Lulia (Female)": "am-ET-MekdesNeural",
|
21 |
+
"Birhane (Male)": "am-ET-AmehaNeural"
|
22 |
+
},
|
23 |
+
"Oromo": {
|
24 |
+
# This is a mock-up. It uses Swahili voices as a fallback.
|
25 |
+
"Zuri (Female)": "sw-KE-ZuriNeural",
|
26 |
+
"Rafiki (Male)": "sw-KE-RafikiNeural"
|
27 |
+
},
|
28 |
+
"Arabic": {
|
29 |
+
"Zariyah (Female, KSA)": "ar-SA-ZariyahNeural",
|
30 |
+
"Hamed (Male, KSA)": "ar-SA-HamedNeural"
|
31 |
+
},
|
32 |
+
"French": {
|
33 |
+
"Denise (Female)": "fr-FR-DeniseNeural",
|
34 |
+
"Henri (Male)": "fr-FR-HenriNeural"
|
35 |
+
},
|
36 |
+
"German": {
|
37 |
+
"Katja (Female)": "de-DE-KatjaNeural",
|
38 |
+
"Conrad (Male)": "de-DE-ConradNeural"
|
39 |
+
},
|
40 |
+
"Italian": {
|
41 |
+
"Elsa (Female)": "it-IT-ElsaNeural",
|
42 |
+
"Diego (Male)": "it-IT-DiegoNeural"
|
43 |
+
},
|
44 |
+
"Japanese": {
|
45 |
+
"Nanami (Female)": "ja-JP-NanamiNeural",
|
46 |
+
"Keita (Male)": "ja-JP-KeitaNeural"
|
47 |
+
},
|
48 |
+
"Korean": {
|
49 |
+
"Sun-Hi (Female)": "ko-KR-SunHiNeural",
|
50 |
+
"InJoon (Male)": "ko-KR-InJoonNeural"
|
51 |
+
},
|
52 |
+
"Chinese (Simplified)": {
|
53 |
+
"Xiaoxiao (Female)": "zh-CN-XiaoxiaoNeural",
|
54 |
+
"Yunxi (Male)": "zh-CN-YunxiNeural"
|
55 |
+
},
|
56 |
+
"Chinese (Traditional)": {
|
57 |
+
"HsiaoChen (Female)": "zh-TW-HsiaoChenNeural",
|
58 |
+
"YunJhe (Male)": "zh-TW-YunJheNeural"
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
async def text_to_speech_edge(text, language, speaker):
|
63 |
+
try:
|
64 |
+
voice = language_dict[language][speaker]
|
65 |
+
except KeyError:
|
66 |
+
raise gr.Error(f"Error: Voice '{speaker}' not found for {language}.")
|
67 |
+
|
68 |
+
try:
|
69 |
+
communicate = edge_tts.Communicate(text, voice)
|
70 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
|
71 |
+
tmp_path = tmp_file.name
|
72 |
+
await asyncio.wait_for(communicate.save(tmp_path), timeout=60)
|
73 |
+
return tmp_path
|
74 |
+
|
75 |
+
except asyncio.TimeoutError:
|
76 |
+
raise gr.Error("Error: Request timed out. Please try again.")
|
77 |
+
except Exception as e:
|
78 |
+
raise gr.Error(f"An unexpected error occurred: {str(e)}")
|
79 |
+
|
80 |
+
def update_speakers(language):
|
81 |
+
speakers = list(language_dict.get(language, []))
|
82 |
+
return gr.Dropdown(choices=speakers, value=speakers[0] if speakers else None, interactive=True)
|
83 |
+
|
84 |
+
# --- Gradio Interface ---
|
85 |
+
with gr.Blocks(title="SelamGPT TTS", theme=gr.themes.Soft()) as demo:
|
86 |
+
gr.Markdown("# SelamGPT Text-to-Speech")
|
87 |
+
|
88 |
+
with gr.Row():
|
89 |
+
language = gr.Dropdown(
|
90 |
+
choices=list(language_dict.keys()),
|
91 |
+
value="Amharic",
|
92 |
+
label="Language"
|
93 |
+
)
|
94 |
+
speaker = gr.Dropdown(
|
95 |
+
label="Speaker",
|
96 |
+
choices=list(language_dict["Amharic"].keys()),
|
97 |
+
value="Mekdes (Female)"
|
98 |
+
)
|
99 |
+
|
100 |
+
with gr.Column():
|
101 |
+
input_text = gr.Textbox(label="Input Text", placeholder="Enter text here...")
|
102 |
+
generate_btn = gr.Button("Generate Audio", variant="primary")
|
103 |
+
|
104 |
+
output_audio = gr.Audio(label="Output Audio", autoplay=True)
|
105 |
+
|
106 |
+
language.change(fn=update_speakers, inputs=language, outputs=speaker)
|
107 |
+
generate_btn.click(fn=text_to_speech_edge, inputs=[input_text, language, speaker], outputs=output_audio)
|
108 |
+
|
109 |
+
if __name__ == "__main__":
|
110 |
demo.launch()
|