import gradio as gr import edge_tts import asyncio import tempfile import os # Voices cachen VOICES_CACHE = None async def get_voices(): global VOICES_CACHE if VOICES_CACHE is None: voices = await edge_tts.list_voices() VOICES_CACHE = { f"{v['ShortName']} - {v['Locale']} ({v['Gender']})": v['ShortName'] for v in voices } return VOICES_CACHE async def text_to_speech(text: str, voice: str, rate: int, pitch: int): """TTS generieren""" if not text.strip(): return None, "Bitte Text eingeben." if not voice: return None, "Bitte Stimme auswählen." # Voice-Name extrahieren voice_name = voice.split(" - ")[0] if " - " in voice else voice # Parameter formatieren rate_str = f"{rate:+d}%" pitch_str = f"{pitch:+d}Hz" communicate = edge_tts.Communicate( text, voice_name, rate=rate_str, pitch=pitch_str ) # Temp-File erstellen with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp: tmp_path = tmp.name try: await communicate.save(tmp_path) return tmp_path, None except Exception as e: if os.path.exists(tmp_path): os.remove(tmp_path) return None, f"Fehler: {str(e)}" def create_demo(): """Sync Wrapper für Gradio""" voices_dict = asyncio.run(get_voices()) with gr.Blocks(analytics_enabled=False, title="Edge TTS") as demo: gr.Markdown("# 🎙️ Edge TTS Text-to-Speech") gr.Markdown("Python 3.13 kompatibel ✅") with gr.Row(): with gr.Column(): text_input = gr.Textbox( label="Text", lines=4, placeholder="Hallo, dies ist ein Test..." ) voice_dropdown = gr.Dropdown( choices=[""] + sorted(voices_dict.keys()), label="Stimme", value="" ) with gr.Row(): rate_slider = gr.Slider(-50, 50, 0, label="Rate %", step=1) pitch_slider = gr.Slider(-20, 20, 0, label="Pitch Hz", step=1) generate_btn = gr.Button("🔊 Generieren", variant="primary") with gr.Column(): audio_output = gr.Audio(label="Audio", type="filepath") warning_md = gr.Markdown(visible=False) generate_btn.click( fn=text_to_speech, inputs=[text_input, voice_dropdown, rate_slider, pitch_slider], outputs=[audio_output, warning_md] ) return demo if __name__ == "__main__": demo = create_demo() demo.queue(default_concurrency_limit=10) demo.launch(server_name="0.0.0.0", server_port=7860)