Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,70 +1,44 @@
|
|
1 |
-
import os
|
2 |
-
import gradio as gr
|
3 |
import asyncio
|
4 |
import edge_tts
|
5 |
-
import
|
6 |
-
|
7 |
-
# Load voices once
|
8 |
-
def load_voices():
|
9 |
-
loop = asyncio.get_event_loop()
|
10 |
-
voices = loop.run_until_complete(edge_tts.list_voices())
|
11 |
-
return {f"{v['ShortName']} - {v['Locale']} ({v['Gender']})": v['ShortName']
|
12 |
-
for v in voices}
|
13 |
-
|
14 |
-
VOICES = load_voices()
|
15 |
-
|
16 |
-
# Async TTS
|
17 |
-
async def _tts(text, short_name, rate_str, pitch_str):
|
18 |
-
comm = edge_tts.Communicate(text, short_name, rate=rate_str, pitch=pitch_str)
|
19 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
|
20 |
-
await comm.save(tmp.name)
|
21 |
-
return tmp.name
|
22 |
-
|
23 |
-
# Sync wrapper
|
24 |
-
def tts_interface(text, voice, rate, pitch):
|
25 |
-
if not text.strip():
|
26 |
-
return None, "🚨 Enter some text."
|
27 |
-
if not voice:
|
28 |
-
return None, "🚨 Select a voice."
|
29 |
-
name = voice.split(" - ")[0]
|
30 |
-
rate_s = f"{rate:+d}%"
|
31 |
-
pitch_s = f"{pitch:+d}Hz"
|
32 |
-
try:
|
33 |
-
path = asyncio.get_event_loop().run_until_complete(
|
34 |
-
_tts(text, name, rate_s, pitch_s)
|
35 |
-
)
|
36 |
-
return path, ""
|
37 |
-
except Exception as e:
|
38 |
-
return None, f"❌ TTS failed: {e}"
|
39 |
|
40 |
-
#
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
with gr.Row():
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
inputs=[txt, vox, rate, pit],
|
57 |
-
outputs=[out_audio, warn]
|
58 |
-
)
|
59 |
-
demo.queue() # Register /api endpoints
|
60 |
-
|
61 |
return demo
|
62 |
|
63 |
if __name__ == "__main__":
|
64 |
-
|
65 |
-
port = int(os.environ.get("PORT", 7860))
|
66 |
-
demo.launch(
|
67 |
-
server_name="0.0.0.0",
|
68 |
-
server_port=port,
|
69 |
-
ssr_mode=False # disable SSR introspection errors
|
70 |
-
)
|
|
|
|
|
|
|
1 |
import asyncio
|
2 |
import edge_tts
|
3 |
+
ing import GradioComponent to match huggingface space conventions
|
4 |
+
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
+
# Fetch available voices once at startup
|
7 |
+
df_voices = asyncio.run(edge_tts.list_voices())
|
8 |
+
voice_names = [v["Name"] for v in df_voices]
|
9 |
+
|
10 |
+
async def generate_tts(text: str, voice: str, rate: int, pitch: int):
|
11 |
+
# Edge TTS parameters expect strings
|
12 |
+
rate_str = f"{rate}%"
|
13 |
+
pitch_str = f"{pitch}Hz"
|
14 |
+
communicate = edge_tts.Communicate(text, voice, rate=rate_str, pitch=pitch_str)
|
15 |
+
# Stream audio to memory
|
16 |
+
audio_chunks = []
|
17 |
+
async for chunk in communicate.stream():
|
18 |
+
audio_chunks.append(chunk)
|
19 |
+
return b"".join(audio_chunks)
|
20 |
+
|
21 |
+
# Synchronous wrapper for Gradio
|
22 |
+
def tts(text, voice, rate, pitch):
|
23 |
+
audio = asyncio.run(generate_tts(text, voice, rate, pitch))
|
24 |
+
return ("output.mp3", audio)
|
25 |
+
|
26 |
+
# Gradio UI
|
27 |
+
def main():
|
28 |
+
with gr.Blocks() as demo:
|
29 |
+
gr.Markdown("## Edge TTS Text-to-Speech Converter")
|
30 |
with gr.Row():
|
31 |
+
text_input = gr.Textbox(label="Input Text", lines=4, placeholder="Enter text to convert...")
|
32 |
+
voice_selector = gr.Dropdown(label="Voice Model", choices=voice_names, value=voice_names[0])
|
33 |
+
with gr.Row():
|
34 |
+
rate_slider = gr.Slider(label="Speaking Rate (%)", minimum=10, maximum=200, step=1, value=100)
|
35 |
+
pitch_slider = gr.Slider(label="Pitch (Hz)", minimum=-20, maximum=20, step=1, value=0)
|
36 |
+
output_audio = gr.Audio(label="Generated Audio", type="file")
|
37 |
+
generate_btn = gr.Button("Convert to Speech")
|
38 |
+
generate_btn.click(fn=tts,
|
39 |
+
inputs=[text_input, voice_selector, rate_slider, pitch_slider],
|
40 |
+
outputs=output_audio)
|
|
|
|
|
|
|
|
|
|
|
41 |
return demo
|
42 |
|
43 |
if __name__ == "__main__":
|
44 |
+
main().launch()
|
|
|
|
|
|
|
|
|
|
|
|