Techbitforge commited on
Commit
0b9014b
·
verified ·
1 Parent(s): 6b9e00a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +254 -0
app.py CHANGED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, send_file
2
+ import edge_tts
3
+ import asyncio
4
+ import tempfile
5
+ import os
6
+
7
+ app = Flask(__name__)
8
+
9
+ # ---------------------------
10
+ # Async helpers
11
+ # ---------------------------
12
+
13
+ async def get_voices_async():
14
+ voices = await edge_tts.list_voices()
15
+ return [
16
+ {
17
+ "short_name": v["ShortName"],
18
+ "locale": v["Locale"],
19
+ "gender": v["Gender"],
20
+ "display": f"{v['ShortName']} - {v['Locale']} ({v['Gender']})"
21
+ }
22
+ for v in voices
23
+ ]
24
+
25
+
26
+ async def tts_async(text, voice, rate, pitch):
27
+ rate_str = f"{rate:+d}%"
28
+ pitch_str = f"{pitch:+d}Hz"
29
+
30
+ communicate = edge_tts.Communicate(
31
+ text=text,
32
+ voice=voice,
33
+ rate=rate_str,
34
+ pitch=pitch_str
35
+ )
36
+
37
+ tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
38
+ tmp_path = tmp_file.name
39
+ tmp_file.close()
40
+
41
+ await communicate.save(tmp_path)
42
+ return tmp_path
43
+
44
+
45
+ # ---------------------------
46
+ # Routes
47
+ # ---------------------------
48
+
49
+ @app.route("/", methods=["GET"])
50
+ def hello():
51
+ return """
52
+ <!DOCTYPE html>
53
+ <html lang="en">
54
+ <head>
55
+ <meta charset="UTF-8">
56
+ <title>Edge TTS Voices</title>
57
+ <style>
58
+ body {
59
+ font-family: Arial, sans-serif;
60
+ background-color: #111;
61
+ color: #fff;
62
+ padding: 40px;
63
+ }
64
+
65
+ h1 {
66
+ text-align: center;
67
+ }
68
+
69
+ .stats {
70
+ display: flex;
71
+ justify-content: center;
72
+ gap: 40px;
73
+ margin-bottom: 30px;
74
+ }
75
+
76
+ .card {
77
+ background: #1e1e1e;
78
+ padding: 20px;
79
+ border-radius: 10px;
80
+ text-align: center;
81
+ min-width: 150px;
82
+ }
83
+
84
+ .male { border: 2px solid #3498db; }
85
+ .female { border: 2px solid #e91e63; }
86
+ .total { border: 2px solid #2ecc71; }
87
+
88
+ .voices-container {
89
+ display: flex;
90
+ gap: 40px;
91
+ }
92
+
93
+ .voices-list {
94
+ flex: 1;
95
+ background: #1a1a1a;
96
+ padding: 20px;
97
+ border-radius: 10px;
98
+ max-height: 500px;
99
+ overflow-y: auto;
100
+ }
101
+
102
+ .voice-item {
103
+ padding: 6px 0;
104
+ border-bottom: 1px solid #333;
105
+ font-size: 14px;
106
+ }
107
+ </style>
108
+ </head>
109
+ <body>
110
+
111
+ <h1>🎙 Edge TTS Voices</h1>
112
+
113
+ <div class="stats">
114
+ <div class="card total">
115
+ <h2 id="totalCount">0</h2>
116
+ <p>Total Voices</p>
117
+ </div>
118
+
119
+ <div class="card male">
120
+ <h2 id="maleCount">0</h2>
121
+ <p>Male Voices</p>
122
+ </div>
123
+
124
+ <div class="card female">
125
+ <h2 id="femaleCount">0</h2>
126
+ <p>Female Voices</p>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="voices-container">
131
+ <div class="voices-list">
132
+ <h3>👨 Male Voices</h3>
133
+ <div id="maleVoices"></div>
134
+ </div>
135
+
136
+ <div class="voices-list">
137
+ <h3>👩 Female Voices</h3>
138
+ <div id="femaleVoices"></div>
139
+ </div>
140
+ </div>
141
+
142
+ <script>
143
+ async function loadVoices() {
144
+ try {
145
+ const response = await fetch("/voices");
146
+ const data = await response.json();
147
+
148
+ const maleVoices = data.Male.voices;
149
+ const femaleVoices = data.Female.voices;
150
+
151
+ const maleCount = data.Male.count;
152
+ const femaleCount = data.Female.count;
153
+ const total = maleCount + femaleCount;
154
+
155
+ document.getElementById("maleCount").innerText = maleCount;
156
+ document.getElementById("femaleCount").innerText = femaleCount;
157
+ document.getElementById("totalCount").innerText = total;
158
+
159
+ const maleContainer = document.getElementById("maleVoices");
160
+ const femaleContainer = document.getElementById("femaleVoices");
161
+
162
+ maleVoices.forEach(v => {
163
+ const div = document.createElement("div");
164
+ div.className = "voice-item";
165
+ div.innerText = v.short_name;
166
+ maleContainer.appendChild(div);
167
+ });
168
+
169
+ femaleVoices.forEach(v => {
170
+ const div = document.createElement("div");
171
+ div.className = "voice-item";
172
+ div.innerText = v.short_name;
173
+ femaleContainer.appendChild(div);
174
+ });
175
+
176
+ } catch (error) {
177
+ alert("Error loading voices: " + error);
178
+ }
179
+ }
180
+
181
+ loadVoices();
182
+ </script>
183
+
184
+ </body>
185
+ </html>
186
+ """
187
+ @app.route("/voices", methods=["GET"])
188
+ def voices():
189
+ voices = asyncio.run(get_voices_async())
190
+
191
+ grouped = {
192
+ "Male": {
193
+ "count": 0,
194
+ "voices": []
195
+ },
196
+ "Female": {
197
+ "count": 0,
198
+ "voices": []
199
+ }
200
+ }
201
+
202
+ for v in voices:
203
+ gender = v["gender"].lower()
204
+
205
+ if gender == "male":
206
+ grouped["Male"]["voices"].append(v)
207
+ grouped["Male"]["count"] += 1
208
+
209
+ elif gender == "female":
210
+ grouped["Female"]["voices"].append(v)
211
+ grouped["Female"]["count"] += 1
212
+
213
+ return jsonify(grouped)
214
+
215
+
216
+
217
+ @app.route("/tts", methods=["POST"])
218
+ def tts():
219
+ data = request.json
220
+
221
+ text = data.get("text", "").strip()
222
+ voice = data.get("voice")
223
+ rate = int(data.get("rate", 0))
224
+ pitch = int(data.get("pitch", 0))
225
+
226
+ if not text:
227
+ return jsonify({"error": "Text is required"}), 400
228
+ if not voice:
229
+ return jsonify({"error": "Voice is required"}), 400
230
+
231
+ try:
232
+ audio_path = asyncio.run(tts_async(text, voice, rate, pitch))
233
+
234
+ return send_file(
235
+ audio_path,
236
+ mimetype="audio/mpeg",
237
+ as_attachment=True,
238
+ download_name="tts.mp3"
239
+ )
240
+
241
+ except Exception as e:
242
+ return jsonify({"error": str(e)}), 500
243
+
244
+
245
+ # ---------------------------
246
+ # Run server
247
+ # ---------------------------
248
+
249
+ if __name__ == "__main__":
250
+ app.run(
251
+ host="0.0.0.0",
252
+ port=7860,
253
+ debug=False
254
+ )