import tempfile import edge_tts import gradio as gr import asyncio # --- Final, VERIFIED Language & Voice Configuration --- language_dict = { "English": { "Jenny (Female, US)": "en-US-JennyNeural", "Andrew (Male, US)": "en-US-AndrewNeural", "Sonia (Female, UK)": "en-GB-SoniaNeural", "Ryan (Male, UK)": "en-GB-RyanNeural" }, "Amharic": { "Mekdes (Female)": "am-ET-MekdesNeural", "Ameha (Male)": "am-ET-AmehaNeural" }, "Tigrinya": { # WORKAROUND: Using Amharic voices as a fallback for Tigrinya. "Lulia (Female)": "am-ET-MekdesNeural", "Birhane (Male)": "am-ET-AmehaNeural" }, "Oromo": { # This is a mock-up. It uses Swahili voices as a fallback. "Zuri (Female)": "sw-KE-ZuriNeural", "Rafiki (Male)": "sw-KE-RafikiNeural" }, "Somali": { "Ubax (Female)": "so-SO-UbaxNeural", "Muuse (Male)": "so-SO-MuuseNeural" }, "Arabic": { "Zariyah (Female, KSA)": "ar-SA-ZariyahNeural", "Hamed (Male, KSA)": "ar-SA-HamedNeural" }, "French": { "Denise (Female)": "fr-FR-DeniseNeural", "Henri (Male)": "fr-FR-HenriNeural" }, "German": { "Katja (Female)": "de-DE-KatjaNeural", "Conrad (Male)": "de-DE-ConradNeural" }, "Italian": { "Elsa (Female)": "it-IT-ElsaNeural", "Diego (Male)": "it-IT-DiegoNeural" }, "Japanese": { "Nanami (Female)": "ja-JP-NanamiNeural", "Keita (Male)": "ja-JP-KeitaNeural" }, "Korean": { "Sun-Hi (Female)": "ko-KR-SunHiNeural", "InJoon (Male)": "ko-KR-InJoonNeural" }, "Chinese (Simplified)": { "Xiaoxiao (Female)": "zh-CN-XiaoxiaoNeural", "Yunxi (Male)": "zh-CN-YunxiNeural" }, "Chinese (Traditional)": { "HsiaoChen (Female)": "zh-TW-HsiaoChenNeural", "YunJhe (Male)": "zh-TW-YunJheNeural" } } async def text_to_speech_edge(text, language, speaker): try: voice = language_dict[language][speaker] except KeyError: raise gr.Error(f"Error: Voice '{speaker}' not found for {language}.") 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=60) return tmp_path except asyncio.TimeoutError: raise gr.Error("Error: Request timed out. Please try again.") except Exception as e: raise gr.Error(f"An unexpected error occurred: {str(e)}") def update_speakers(language): speakers = list(language_dict.get(language, [])) return gr.Dropdown(choices=speakers, value=speakers[0] if speakers else None, interactive=True) # --- Gradio Interface --- with gr.Blocks(title="SelamGPT TTS", theme=gr.themes.Soft()) as demo: gr.Markdown("# SelamGPT Text-to-Speech") with gr.Row(): language = gr.Dropdown( choices=list(language_dict.keys()), value="Amharic", label="Language" ) speaker = gr.Dropdown( label="Speaker", choices=list(language_dict["Amharic"].keys()), value="Mekdes (Female)" ) with gr.Column(): input_text = gr.Textbox(label="Input Text", placeholder="Enter text here...") generate_btn = gr.Button("Generate Audio", variant="primary") output_audio = gr.Audio(label="Output Audio", autoplay=True) language.change(fn=update_speakers, inputs=language, outputs=speaker) generate_btn.click(fn=text_to_speech_edge, inputs=[input_text, language, speaker], outputs=output_audio) if __name__ == "__main__": demo.launch()