teamseven commited on
Commit
7d46e4e
Β·
verified Β·
1 Parent(s): effcfe6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +176 -0
app.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import asyncio
3
+ import tempfile
4
+ import logging
5
+ import secrets
6
+ from pathlib import Path
7
+
8
+ import gradio as gr
9
+ import edge_tts
10
+
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger("edge-tts-bridge")
13
+
14
+ APP_TITLE = "Edge TTS Bridge"
15
+ API_KEY = os.environ.get("EDGE_TTS_API_KEY", "").strip()
16
+
17
+ VOICES = {
18
+ "Myanmar Female": "my-MM-NilarNeural",
19
+ "Myanmar Male": "my-MM-ThihaNeural",
20
+ }
21
+
22
+
23
+ async def synthesize(text: str, voice: str) -> str:
24
+ """Generate speech using Microsoft Edge TTS."""
25
+
26
+ with tempfile.NamedTemporaryFile(
27
+ suffix=".mp3",
28
+ delete=False
29
+ ) as temp:
30
+ output_path = temp.name
31
+
32
+ try:
33
+ communicate = edge_tts.Communicate(
34
+ text=text,
35
+ voice=voice,
36
+ )
37
+
38
+ await communicate.save(output_path)
39
+
40
+ if not os.path.exists(output_path):
41
+ raise RuntimeError("Audio file was not created.")
42
+
43
+ if os.path.getsize(output_path) < 100:
44
+ raise RuntimeError(
45
+ "Audio file is empty or unexpectedly small."
46
+ )
47
+
48
+ return output_path
49
+
50
+ except Exception:
51
+ try:
52
+ os.remove(output_path)
53
+ except OSError:
54
+ pass
55
+ raise
56
+
57
+
58
+ def generate_audio(text, voice_name, api_key):
59
+ """Gradio interface handler."""
60
+
61
+ text = (text or "").strip()
62
+
63
+ if not text:
64
+ raise gr.Error("Please enter text.")
65
+
66
+ if len(text) > 3000:
67
+ raise gr.Error(
68
+ "Maximum 3000 characters per request."
69
+ )
70
+
71
+ if voice_name not in VOICES:
72
+ raise gr.Error("Unsupported voice.")
73
+
74
+ if API_KEY:
75
+ supplied_key = (api_key or "").strip()
76
+
77
+ if not secrets.compare_digest(
78
+ supplied_key,
79
+ API_KEY
80
+ ):
81
+ raise gr.Error("Invalid API key.")
82
+
83
+ voice = VOICES[voice_name]
84
+
85
+ try:
86
+ return asyncio.run(
87
+ synthesize(text, voice)
88
+ )
89
+
90
+ except Exception as exc:
91
+ logger.exception("Edge TTS synthesis failed")
92
+
93
+ message = str(exc)
94
+
95
+ raise gr.Error(
96
+ f"Edge TTS failed: {message[:500]}"
97
+ )
98
+
99
+
100
+ def api_generate(text, voice_name, api_key):
101
+ """Programmatic API handler."""
102
+
103
+ return generate_audio(
104
+ text,
105
+ voice_name,
106
+ api_key
107
+ )
108
+
109
+
110
+ with gr.Blocks(title=APP_TITLE) as demo:
111
+ gr.Markdown(
112
+ """
113
+ # Edge TTS Bridge
114
+
115
+ Test Microsoft Edge TTS from Hugging Face Spaces.
116
+
117
+ This service requires an active connection to
118
+ Microsoft's speech service.
119
+ """
120
+ )
121
+
122
+ with gr.Row():
123
+ text_input = gr.Textbox(
124
+ label="Text",
125
+ placeholder="α€™α€„α€Ία€Ήα€‚α€œα€¬α€•α€«αŠ α€‘α€žα€Άα€…α€™α€Ία€Έα€žα€•α€Ία€”α€±α€•α€«α€α€šα€Ία‹",
126
+ lines=4,
127
+ max_lines=10,
128
+ )
129
+
130
+ voice_input = gr.Dropdown(
131
+ choices=list(VOICES.keys()),
132
+ value="Myanmar Female",
133
+ label="Voice",
134
+ )
135
+
136
+ key_input = gr.Textbox(
137
+ label="API Key (if configured)",
138
+ type="password",
139
+ placeholder="Enter your API key",
140
+ )
141
+
142
+ generate_button = gr.Button(
143
+ "Generate Audio",
144
+ variant="primary",
145
+ )
146
+
147
+ audio_output = gr.Audio(
148
+ label="Generated Audio",
149
+ type="filepath",
150
+ )
151
+
152
+ generate_button.click(
153
+ fn=generate_audio,
154
+ inputs=[
155
+ text_input,
156
+ voice_input,
157
+ key_input,
158
+ ],
159
+ outputs=audio_output,
160
+ api_name="generate",
161
+ )
162
+
163
+ gr.Markdown(
164
+ """
165
+ ## Test instructions
166
+
167
+ 1. Enter a short Myanmar sentence.
168
+ 2. Select a voice.
169
+ 3. Click Generate Audio.
170
+ 4. Check whether the MP3 is playable.
171
+ """
172
+ )
173
+
174
+
175
+ if __name__ == "__main__":
176
+ demo.queue(max_size=5).launch()