Spaces:
Running
Running
import tempfile | |
import edge_tts | |
import gradio as gr | |
import asyncio | |
# Updated language dictionary with clear voice labeling | |
language_dict = { | |
"Amharic": { | |
"Ameha": "am-ET-AmehaNeural", | |
"Mekdes": "am-ET-MekdesNeural" | |
}, | |
"English": { | |
"Ryan": "en-GB-RyanNeural", | |
"Clara": "en-CA-ClaraNeural" | |
}, | |
"Tigrinya": { | |
"Ameha (Amharic Voice)": "am-ET-AmehaNeural", | |
"Mekdes (Amharic Voice)": "am-ET-MekdesNeural" | |
} | |
} | |
async def text_to_speech_edge(text, language, speaker): | |
# Clean speaker name if it's a Tigrinya selection | |
if language == "Tigrinya": | |
speaker = speaker.replace(" (Amharic Voice)", "") | |
try: | |
voice = language_dict[language][speaker] | |
except KeyError: | |
error_msg = (f"α΅α α°α΅: α΅αα '{speaker}' αααα '{language}' α αα°αααα’" | |
if language in ["Amharic", "Tigrinya"] | |
else f"Error: Voice '{speaker}' not available for '{language}'") | |
raise gr.Error(error_msg) | |
try: | |
communicate = edge_tts.Communicate(text, voice) | |
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file: | |
tmp_path = tmp_file.name | |
await asyncio.wait_for(communicate.save(tmp_path), timeout=30) | |
return tmp_path | |
except asyncio.TimeoutError: | |
error_msg = ("α΅α α°α΅: αα α αααα’ α₯α£αα α₯αα°αα αααα©α’" | |
if language in ["Amharic", "Tigrinya"] | |
else "Error: Timeout. Please try again.") | |
raise gr.Error(error_msg) | |
except Exception as e: | |
error_msg = (f"α΅α α°α΅: {str(e)}" | |
if language in ["Amharic", "Tigrinya"] | |
else f"Error: {str(e)}") | |
raise gr.Error(error_msg) | |
def update_speakers(language): | |
speakers = list(language_dict[language].keys()) | |
return gr.Dropdown( | |
choices=speakers, | |
value=speakers[0], | |
label=f"Select Speaker {'(Amharic Voices)' if language == 'Tigrinya' else ''}" | |
) | |
with gr.Blocks(title="Amharic, English & Tigrinya TTS", theme=gr.themes.Soft()) as demo: | |
gr.HTML(""" | |
<style> | |
h1 { | |
color: #2E86C1; | |
text-align: center; | |
background: linear-gradient(45deg, #FF007F, #2E86C1); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
margin-bottom: 20px; | |
} | |
.notice { | |
font-size: 0.9em; | |
color: #666; | |
text-align: center; | |
margin: 10px 0; | |
font-style: italic; | |
} | |
.gradio-button { | |
background: linear-gradient(45deg, #FF007F, #2E86C1) !important; | |
color: white !important; | |
} | |
</style> | |
<center> | |
<h1>Amharic, English & Tigrinya Text-to-Speech</h1> | |
<div class="notice"> | |
Note: Tigrinya uses Amharic-accented voices until dedicated models become available | |
</div> | |
</center> | |
""") | |
with gr.Row(): | |
with gr.Column(): | |
language = gr.Dropdown( | |
choices=["Amharic", "English", "Tigrinya"], | |
value="Amharic", | |
label="Select Language / ααα ααα¨α‘" | |
) | |
input_text = gr.Textbox( | |
lines=5, | |
label="Enter Text / α½αα α«α΅αα‘", | |
placeholder="Type your text here... / α½αααα αα»α..." | |
) | |
speaker = gr.Dropdown( | |
label="Select Speaker / α αα²α΅α΅ ααα¨α‘", | |
interactive=True | |
) | |
run_btn = gr.Button( | |
value="Generate Audio / α΅αα αα α", | |
variant="primary" | |
) | |
with gr.Column(): | |
output_audio = gr.Audio( | |
type="filepath", | |
label="Generated Audio / α¨α°αα α¨ α΅αα ", | |
interactive=False | |
) | |
# Initialize speakers dropdown | |
demo.load( | |
fn=lambda: gr.Dropdown(choices=list(language_dict["Amharic"].keys()), | |
outputs=speaker | |
) | |
# Update speakers when language changes | |
language.change( | |
update_speakers, | |
inputs=language, | |
outputs=speaker | |
) | |
run_btn.click( | |
text_to_speech_edge, | |
inputs=[input_text, language, speaker], | |
outputs=output_audio | |
) | |
if __name__ == "__main__": | |
demo.launch(server_port=7860, share=False) |