File size: 2,799 Bytes
287bd0a
 
 
 
 
 
81eb5d4
2ff2249
287bd0a
2ff2249
 
 
 
 
 
 
 
 
287bd0a
2ff2249
81eb5d4
287bd0a
 
 
 
 
81eb5d4
2ff2249
287bd0a
2ff2249
287bd0a
 
 
 
2ff2249
287bd0a
 
2ff2249
287bd0a
 
 
 
2ff2249
 
287bd0a
2ff2249
 
 
287bd0a
81eb5d4
 
 
287bd0a
2ff2249
 
81eb5d4
287bd0a
 
2ff2249
287bd0a
2ff2249
 
287bd0a
 
81eb5d4
2ff2249
287bd0a
 
2ff2249
 
 
287bd0a
2ff2249
 
287bd0a
 
 
81eb5d4
287bd0a
2ff2249
287bd0a
 
 
 
 
81eb5d4
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
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
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)