karim23657 commited on
Commit
e96dd2c
·
verified ·
1 Parent(s): 4a4c345

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +333 -333
app.py CHANGED
@@ -1,333 +1,333 @@
1
- from flask import Flask, render_template, request, jsonify, send_from_directory , send_file
2
- from flask_cors import CORS
3
- import time
4
- import uuid
5
- import threading
6
- from collections import deque
7
- import subprocess
8
- import os
9
-
10
- app = Flask(__name__)
11
- CORS(app)
12
-
13
- # Set the paths for espeak-ng and the script directory
14
- script_path = os.path.dirname(os.path.abspath(__file__))
15
- espeak_path = "C:\\Program Files\\eSpeak NG\\espeak-ng.exe" # Change this to the full path if needed
16
- static_folder = os.path.join(script_path, "static")
17
-
18
- # Ensure the static folder exists
19
- os.makedirs(static_folder, exist_ok=True)
20
-
21
- class Component:
22
- def __init__(self, component_type, label, options=None, value=None):
23
- self.component_type = component_type
24
- self.label = label
25
- self.options = options
26
- self.value = value
27
-
28
- def render(self):
29
- if self.component_type == "textbox":
30
- return f'<textarea name="{self.label}" class="form-control" placeholder="{self.label}">{self.value}</textarea>'
31
- elif self.component_type == "radio":
32
- options_html = ''.join([f'''
33
- <div class="form-check form-check-inline">
34
- <input class="form-check-input" type="radio" name="{self.label}" id="{self.label}-{index}" value="{self.value}">
35
- <label class="form-check-label" for="{self.label}-{index}">{option}</label></div>''' for index,option in enumerate(self.options)])
36
- return options_html
37
- elif self.component_type == "audio":
38
- return f'<audio controls id="{self.label}"><source src="" type="audio/wav">Your browser does not support the audio element.</audio>'
39
- elif self.component_type == "output":
40
- return f'<div id="{self.label}">Placeholder for {self.label}</div>'
41
- elif self.component_type == "better_textbox":
42
- return f'<div contenteditable="true" id="{self.label}" class="better-textbox" placeholder="{self.value}">{self.value}</div>'
43
- else:
44
- return ""
45
-
46
- class Row:
47
- def __init__(self, components):
48
- self.components = components
49
-
50
- def render(self):
51
- components_html = ''.join([component.render() for component in self.components])
52
- return f'<div class="row mb-3">{components_html}</div>'
53
-
54
- class Column:
55
- def __init__(self, components):
56
- self.components = components
57
-
58
- def render(self):
59
- components_html = ''.join([component.render() for component in self.components])
60
- return f'<div class="col">{components_html}</div>'
61
-
62
-
63
- class GradioInterface:
64
- def __init__(self, fn, input_components, output_components, max_parallel_tasks=5):
65
- self.fn = fn
66
- self.input_components = input_components
67
- self.output_components = output_components
68
- self.max_parallel_tasks = max_parallel_tasks
69
- self.task_queue = deque()
70
- self.results = {}
71
- self.current_tasks = {}
72
- self.task_threads = {}
73
- self.stop_flags = {}
74
-
75
- def submit(self, input_data):
76
- task_id = str(uuid.uuid4())
77
- if len(self.current_tasks) < self.max_parallel_tasks:
78
- self.task_queue.append(task_id)
79
- self.current_tasks[task_id] = input_data
80
-
81
- stop_flag = threading.Event()
82
- self.stop_flags[task_id] = stop_flag
83
-
84
- thread = threading.Thread(target=self.process_task, args=(task_id, input_data, stop_flag))
85
- self.task_threads[task_id] = thread
86
- thread.start()
87
- return task_id
88
- else:
89
- return None
90
-
91
- def process_task(self, task_id, input_data, stop_flag):
92
- result = self.fn(input_data)
93
- self.results[task_id] = result
94
- self.task_queue.remove(task_id)
95
- del self.current_tasks[task_id]
96
- del self.task_threads[task_id]
97
- del self.stop_flags[task_id]
98
-
99
- def get_result(self, task_id):
100
- if task_id in self.results:
101
- return {"status": "completed", "result": self.results[task_id]}
102
- return {"status": "pending"}
103
-
104
- def render_components(self):
105
- input_html = ''.join([component.render() for component in self.input_components])
106
- output_html = ''.join([component.render() for component in self.output_components])
107
- return input_html #f"{input_html}{output_html}"
108
-
109
- def get_queue_position(self):
110
- return len(self.task_queue)
111
-
112
- def stop_task(self, task_id):
113
- if task_id in self.stop_flags:
114
- self.stop_flags[task_id].set()
115
- return True
116
- return False
117
-
118
-
119
-
120
- import os
121
- import shutil
122
- import subprocess
123
-
124
- def find_espeak_ng_data_folder():
125
- try:
126
- # https://github.com/espeak-ng/espeak-ng/blob/b006f6d4f997fbfe4016cf29767743e6b397d0fb/src/espeak-ng.c#L309
127
- data_folder = subprocess.check_output([espeak_path, '--version']).decode().split('Data at: ')[1].strip()
128
- return data_folder
129
- except Exception as e:
130
- print(f"Error: {str(e)}")
131
- return None
132
-
133
- def copy_lang_dict(data_folder, destination,lang):
134
- dict_file=lang+'_dict'
135
- en_dict_path = os.path.join(data_folder,dict_file )
136
- try:
137
- # Copy the en_dict folder to the destination
138
- shutil.copyfile(en_dict_path, os.path.join(destination, dict_file))
139
- print(f"Successfully copied {dict_file} to {destination}")
140
- except Exception as e:
141
- print(f"Error copying {dict_file}: {str(e)}")
142
-
143
- def compile_espeak():
144
- compile_command = [espeak_path, "--compile=fa"]
145
- cwd_path = r"K:\code\dev\python\other\tts\espeak dictionary\dictsource"
146
- subprocess.run(compile_command, cwd=cwd_path)
147
- print("Compilation done!") # Giving feedback in the console for now
148
-
149
-
150
-
151
- import gzip
152
- phonetc_data_file_path = os.path.join(static_folder, 'fa_extra.txt.gz')
153
- generations_file_path = os.path.join(static_folder, 'generations.txt.gz')
154
-
155
- import time
156
- import datetime
157
-
158
- def get_iran_time_no_packages():
159
- iran_offset_seconds = 3.5 * 3600 # 3.5 hours * seconds/hour
160
- utc_time = time.gmtime()
161
- iran_time_tuple = time.localtime(time.mktime(utc_time) + iran_offset_seconds)
162
- iran_datetime = datetime.datetime(*iran_time_tuple[:6]) # Create datetime object
163
- formatted_time = iran_datetime.strftime("%Y-%m-%d %H:%M:%S")
164
- return formatted_time
165
-
166
- with gzip.open(phonetc_data_file_path, 'at',encoding='utf-8') as f: # 'at' for text mode
167
- f.write(f'// started at : {get_iran_time_no_packages()}\n')
168
-
169
-
170
- def tts(input_data):
171
- text = input_data.get('text')
172
- voice = input_data.get('voice')
173
- input_file_path = os.path.join(script_path, "input_text.txt") # Path for the input text file
174
- audio_file = os.path.join(static_folder, f'output_{uuid.uuid4()}.wav') # Path for the output audio file
175
-
176
- with gzip.open(generations_file_path, 'at',encoding='utf-8') as f:
177
- f.write(f'{voice}\t{text.strip()}\n')
178
-
179
- # Write the input text to a file
180
- with open(input_file_path, 'w', encoding='utf-8') as file:
181
- file.write(text)
182
-
183
- # Phonemize the text
184
- phonemes_command = [espeak_path, "-v", voice, "-x", "-q", "-f", input_file_path]
185
- phonemes_result = subprocess.run(phonemes_command, capture_output=True, text=True)
186
- phonemized_text = phonemes_result.stdout.strip()
187
-
188
- # Generate audio file
189
- audio_cmd = f'"{espeak_path}" -v {voice} -w "{audio_file}" -f "{input_file_path}"'
190
- subprocess.run(audio_cmd, shell=True)
191
-
192
- status = f'مدل : espeak-ng\nآوانگاشت: {phonemized_text}'
193
-
194
- return {"audio": f"/static/{os.path.basename(audio_file)}", # Return the static path
195
- "status": status
196
- }
197
-
198
-
199
- def phonemize(input_data):
200
- text = input_data.get('word')
201
- voice = 'fa'
202
- task = input_data.get('task')
203
- phonetic = input_data.get('phonetic',"").strip()
204
- input_file_path = os.path.join(script_path, "input_text.txt") # Path for the input text file
205
- audio_file = os.path.join(static_folder, f'output_{uuid.uuid4()}.wav') # Path for the output audio file
206
-
207
-
208
- if phonetic=='' or task=='phonemize' :
209
- phonetic=text
210
- else:
211
- phonetic=f'[[{phonetic.strip()}]]'
212
-
213
- # Write the input text to a file
214
- with open(input_file_path, 'w', encoding='utf-8') as file:
215
- file.write(phonetic)
216
-
217
- # Phonemize the text
218
-
219
- phonemes_command = [espeak_path, "-v", voice, "-x", "-q", "-f", input_file_path]
220
- phonemes_result = subprocess.run(phonemes_command, capture_output=True, text=True)
221
- phonemized_text = phonemes_result.stdout.strip()
222
-
223
- # Generate audio file
224
- audio_cmd = f'"{espeak_path}" -v {voice} -w "{audio_file}" -f "{input_file_path}"'
225
- subprocess.run(audio_cmd, shell=True)
226
-
227
- status = f'متن : {text}\nآوانگاشت: {phonemized_text}'
228
- if task=='send' and input_data.get('phonetic',False):
229
- with gzip.open(phonetc_data_file_path, 'at',encoding='utf-8') as f: # 'at' for text mode
230
- f.write(f'{text.strip()}\t{input_data.get("phonetic",False).strip()}\n')
231
-
232
-
233
- return {"audio": f"/static/{os.path.basename(audio_file)}",
234
- "text": text,
235
- "phonemes":phonemized_text,
236
- "status": status
237
- }
238
-
239
-
240
- def listWords(input_data):
241
- data = []
242
- with gzip.open(phonetc_data_file_path, 'rt',encoding='utf-8') as f: # 'rt' for text mode
243
- for line in f:
244
- if not line.startswith('//'): # Skip commented lines
245
- parts = line.strip().split('\t')
246
- if len(parts) == 2:
247
- data.append({'word': parts[0].strip(), 'phonetic': parts[1].strip()})
248
-
249
- return data
250
-
251
- def example_function(input_data):
252
- return input_data
253
-
254
- input_components = [
255
- Component("radio", "voice", options=["fa", "en", "ar"], value="fa")
256
- ]
257
-
258
- output_components = [
259
- Component("output", "phonemized_output"),
260
- Component("audio", "audio_output")
261
- ]
262
-
263
- ifaces = {
264
- 'tts' : GradioInterface(
265
- fn=tts,
266
- input_components=input_components,
267
- output_components=output_components,
268
- max_parallel_tasks=5
269
- )
270
- ,
271
- 'phonemize' : GradioInterface(
272
- fn=phonemize,
273
- input_components=input_components,
274
- output_components=output_components,
275
- max_parallel_tasks=5
276
- )
277
- ,
278
- 'words' : GradioInterface(
279
- fn=listWords,
280
- input_components=input_components,
281
- output_components=output_components,
282
- max_parallel_tasks=5
283
- )
284
- ,
285
-
286
- }
287
-
288
-
289
- @app.route("/", methods=["GET"])
290
- def index():
291
- return render_template("tab-2-6-template.html", components=ifaces['tts'].render_components())
292
-
293
- @app.route("/submit", methods=["POST"])
294
- def submit():
295
- tab = request.form.get("tab")
296
- task_id = ifaces[tab].submit(request.form)
297
-
298
- if task_id:
299
- position = ifaces[tab].get_queue_position()
300
- return jsonify({"task_id": task_id, "position": position})
301
- else:
302
- return jsonify({"error": "Task queue is full"}), 429
303
-
304
- @app.route("/result/<task_id>/<tab>", methods=["GET"])
305
- def result(task_id,tab):
306
- result_data = ifaces[tab].get_result(task_id)
307
- if result_data["status"] == "completed":
308
- return jsonify(result_data)
309
- return jsonify({"status": result_data["status"]})
310
-
311
- @app.route("/queue", methods=["GET"])
312
- def queue():
313
- return jsonify({"queue": list(iface.task_queue)})
314
-
315
- @app.route("/stop/<task_id>", methods=["POST"])
316
- def stop(task_id):
317
- stopped = iface.stop_task(task_id)
318
- if stopped:
319
- return jsonify({"status": "stopped"})
320
- return jsonify({"status": "not found"}), 404
321
-
322
- @app.route('/static/<path:filename>')
323
- def send_static(filename):
324
- return send_from_directory(static_folder, filename)
325
- @app.route('/download/fa_extra')
326
- def download():
327
- return send_file(phonetc_data_file_path, as_attachment=True)
328
- @app.route('/download/fa_dict')
329
- def download1():
330
- dict_file='fa_dict'
331
- return send_file(os.path.join(find_espeak_ng_data_folder(),dict_file ), as_attachment=True)
332
- if __name__ == "__main__":
333
- app.run(debug=True)
 
1
+ from flask import Flask, render_template, request, jsonify, send_from_directory , send_file
2
+ from flask_cors import CORS
3
+ import time
4
+ import uuid
5
+ import threading
6
+ from collections import deque
7
+ import subprocess
8
+ import os
9
+
10
+ app = Flask(__name__)
11
+ CORS(app)
12
+
13
+ # Set the paths for espeak-ng and the script directory
14
+ script_path = os.path.dirname(os.path.abspath(__file__))
15
+ espeak_path = "C:\\Program Files\\eSpeak NG\\espeak-ng.exe" # Change this to the full path if needed
16
+ static_folder = os.path.join(script_path, "static")
17
+
18
+ # Ensure the static folder exists
19
+ os.makedirs(static_folder, exist_ok=True)
20
+
21
+ class Component:
22
+ def __init__(self, component_type, label, options=None, value=None):
23
+ self.component_type = component_type
24
+ self.label = label
25
+ self.options = options
26
+ self.value = value
27
+
28
+ def render(self):
29
+ if self.component_type == "textbox":
30
+ return f'<textarea name="{self.label}" class="form-control" placeholder="{self.label}">{self.value}</textarea>'
31
+ elif self.component_type == "radio":
32
+ options_html = ''.join([f'''
33
+ <div class="form-check form-check-inline">
34
+ <input class="form-check-input" type="radio" name="{self.label}" id="{self.label}-{index}" value="{self.value}">
35
+ <label class="form-check-label" for="{self.label}-{index}">{option}</label></div>''' for index,option in enumerate(self.options)])
36
+ return options_html
37
+ elif self.component_type == "audio":
38
+ return f'<audio controls id="{self.label}"><source src="" type="audio/wav">Your browser does not support the audio element.</audio>'
39
+ elif self.component_type == "output":
40
+ return f'<div id="{self.label}">Placeholder for {self.label}</div>'
41
+ elif self.component_type == "better_textbox":
42
+ return f'<div contenteditable="true" id="{self.label}" class="better-textbox" placeholder="{self.value}">{self.value}</div>'
43
+ else:
44
+ return ""
45
+
46
+ class Row:
47
+ def __init__(self, components):
48
+ self.components = components
49
+
50
+ def render(self):
51
+ components_html = ''.join([component.render() for component in self.components])
52
+ return f'<div class="row mb-3">{components_html}</div>'
53
+
54
+ class Column:
55
+ def __init__(self, components):
56
+ self.components = components
57
+
58
+ def render(self):
59
+ components_html = ''.join([component.render() for component in self.components])
60
+ return f'<div class="col">{components_html}</div>'
61
+
62
+
63
+ class GradioInterface:
64
+ def __init__(self, fn, input_components, output_components, max_parallel_tasks=5):
65
+ self.fn = fn
66
+ self.input_components = input_components
67
+ self.output_components = output_components
68
+ self.max_parallel_tasks = max_parallel_tasks
69
+ self.task_queue = deque()
70
+ self.results = {}
71
+ self.current_tasks = {}
72
+ self.task_threads = {}
73
+ self.stop_flags = {}
74
+
75
+ def submit(self, input_data):
76
+ task_id = str(uuid.uuid4())
77
+ if len(self.current_tasks) < self.max_parallel_tasks:
78
+ self.task_queue.append(task_id)
79
+ self.current_tasks[task_id] = input_data
80
+
81
+ stop_flag = threading.Event()
82
+ self.stop_flags[task_id] = stop_flag
83
+
84
+ thread = threading.Thread(target=self.process_task, args=(task_id, input_data, stop_flag))
85
+ self.task_threads[task_id] = thread
86
+ thread.start()
87
+ return task_id
88
+ else:
89
+ return None
90
+
91
+ def process_task(self, task_id, input_data, stop_flag):
92
+ result = self.fn(input_data)
93
+ self.results[task_id] = result
94
+ self.task_queue.remove(task_id)
95
+ del self.current_tasks[task_id]
96
+ del self.task_threads[task_id]
97
+ del self.stop_flags[task_id]
98
+
99
+ def get_result(self, task_id):
100
+ if task_id in self.results:
101
+ return {"status": "completed", "result": self.results[task_id]}
102
+ return {"status": "pending"}
103
+
104
+ def render_components(self):
105
+ input_html = ''.join([component.render() for component in self.input_components])
106
+ output_html = ''.join([component.render() for component in self.output_components])
107
+ return input_html #f"{input_html}{output_html}"
108
+
109
+ def get_queue_position(self):
110
+ return len(self.task_queue)
111
+
112
+ def stop_task(self, task_id):
113
+ if task_id in self.stop_flags:
114
+ self.stop_flags[task_id].set()
115
+ return True
116
+ return False
117
+
118
+
119
+
120
+ import os
121
+ import shutil
122
+ import subprocess
123
+
124
+ def find_espeak_ng_data_folder():
125
+ try:
126
+ # https://github.com/espeak-ng/espeak-ng/blob/b006f6d4f997fbfe4016cf29767743e6b397d0fb/src/espeak-ng.c#L309
127
+ data_folder = subprocess.check_output([espeak_path, '--version']).decode().split('Data at: ')[1].strip()
128
+ return data_folder
129
+ except Exception as e:
130
+ print(f"Error: {str(e)}")
131
+ return None
132
+
133
+ def copy_lang_dict(data_folder, destination,lang):
134
+ dict_file=lang+'_dict'
135
+ en_dict_path = os.path.join(data_folder,dict_file )
136
+ try:
137
+ # Copy the en_dict folder to the destination
138
+ shutil.copyfile(en_dict_path, os.path.join(destination, dict_file))
139
+ print(f"Successfully copied {dict_file} to {destination}")
140
+ except Exception as e:
141
+ print(f"Error copying {dict_file}: {str(e)}")
142
+
143
+ def compile_espeak():
144
+ compile_command = [espeak_path, "--compile=fa"]
145
+ cwd_path = r"K:\code\dev\python\other\tts\espeak dictionary\dictsource"
146
+ subprocess.run(compile_command, cwd=cwd_path)
147
+ print("Compilation done!") # Giving feedback in the console for now
148
+
149
+
150
+
151
+ import gzip
152
+ phonetc_data_file_path = os.path.join(static_folder, 'fa_extra.txt.gz')
153
+ generations_file_path = os.path.join(static_folder, 'generations.txt.gz')
154
+
155
+ import time
156
+ import datetime
157
+
158
+ def get_iran_time_no_packages():
159
+ iran_offset_seconds = 3.5 * 3600 # 3.5 hours * seconds/hour
160
+ utc_time = time.gmtime()
161
+ iran_time_tuple = time.localtime(time.mktime(utc_time) + iran_offset_seconds)
162
+ iran_datetime = datetime.datetime(*iran_time_tuple[:6]) # Create datetime object
163
+ formatted_time = iran_datetime.strftime("%Y-%m-%d %H:%M:%S")
164
+ return formatted_time
165
+
166
+ with gzip.open(phonetc_data_file_path, 'at',encoding='utf-8') as f: # 'at' for text mode
167
+ f.write(f'// started at : {get_iran_time_no_packages()}\n')
168
+
169
+
170
+ def tts(input_data):
171
+ text = input_data.get('text')
172
+ voice = input_data.get('voice')
173
+ input_file_path = os.path.join(script_path, "input_text.txt") # Path for the input text file
174
+ audio_file = os.path.join(static_folder, f'output_{uuid.uuid4()}.wav') # Path for the output audio file
175
+
176
+ with gzip.open(generations_file_path, 'at',encoding='utf-8') as f:
177
+ f.write(f'{voice}\t{text.strip()}\n')
178
+
179
+ # Write the input text to a file
180
+ with open(input_file_path, 'w', encoding='utf-8') as file:
181
+ file.write(text)
182
+
183
+ # Phonemize the text
184
+ phonemes_command = [espeak_path, "-v", voice, "-x", "-q", "-f", input_file_path]
185
+ phonemes_result = subprocess.run(phonemes_command, capture_output=True, text=True)
186
+ phonemized_text = phonemes_result.stdout.strip()
187
+
188
+ # Generate audio file
189
+ audio_cmd = f'"{espeak_path}" -v {voice} -w "{audio_file}" -f "{input_file_path}"'
190
+ subprocess.run(audio_cmd, shell=True)
191
+
192
+ status = f'مدل : espeak-ng\nآوانگاشت: {phonemized_text}'
193
+
194
+ return {"audio": f"/static/{os.path.basename(audio_file)}", # Return the static path
195
+ "status": status
196
+ }
197
+
198
+
199
+ def phonemize(input_data):
200
+ text = input_data.get('word')
201
+ voice = 'fa'
202
+ task = input_data.get('task')
203
+ phonetic = input_data.get('phonetic',"").strip()
204
+ input_file_path = os.path.join(script_path, "input_text.txt") # Path for the input text file
205
+ audio_file = os.path.join(static_folder, f'output_{uuid.uuid4()}.wav') # Path for the output audio file
206
+
207
+
208
+ if phonetic=='' or task=='phonemize' :
209
+ phonetic=text
210
+ else:
211
+ phonetic=f'[[{phonetic.strip()}]]'
212
+
213
+ # Write the input text to a file
214
+ with open(input_file_path, 'w', encoding='utf-8') as file:
215
+ file.write(phonetic)
216
+
217
+ # Phonemize the text
218
+
219
+ phonemes_command = [espeak_path, "-v", voice, "-x", "-q", "-f", input_file_path]
220
+ phonemes_result = subprocess.run(phonemes_command, capture_output=True, text=True)
221
+ phonemized_text = phonemes_result.stdout.strip()
222
+
223
+ # Generate audio file
224
+ audio_cmd = f'"{espeak_path}" -v {voice} -w "{audio_file}" -f "{input_file_path}"'
225
+ subprocess.run(audio_cmd, shell=True)
226
+
227
+ status = f'متن : {text}\nآوانگاشت: {phonemized_text}'
228
+ if task=='send' and input_data.get('phonetic',False):
229
+ with gzip.open(phonetc_data_file_path, 'at',encoding='utf-8') as f: # 'at' for text mode
230
+ f.write(f'{text.strip()}\t{input_data.get("phonetic",False).strip()}\n')
231
+
232
+
233
+ return {"audio": f"/static/{os.path.basename(audio_file)}",
234
+ "text": text,
235
+ "phonemes":phonemized_text,
236
+ "status": status
237
+ }
238
+
239
+
240
+ def listWords(input_data):
241
+ data = []
242
+ with gzip.open(phonetc_data_file_path, 'rt',encoding='utf-8') as f: # 'rt' for text mode
243
+ for line in f:
244
+ if not line.startswith('//'): # Skip commented lines
245
+ parts = line.strip().split('\t')
246
+ if len(parts) == 2:
247
+ data.append({'word': parts[0].strip(), 'phonetic': parts[1].strip()})
248
+
249
+ return data
250
+
251
+ def example_function(input_data):
252
+ return input_data
253
+
254
+ input_components = [
255
+ Component("radio", "voice", options=["fa", "en", "ar"], value="fa")
256
+ ]
257
+
258
+ output_components = [
259
+ Component("output", "phonemized_output"),
260
+ Component("audio", "audio_output")
261
+ ]
262
+
263
+ ifaces = {
264
+ 'tts' : GradioInterface(
265
+ fn=tts,
266
+ input_components=input_components,
267
+ output_components=output_components,
268
+ max_parallel_tasks=5
269
+ )
270
+ ,
271
+ 'phonemize' : GradioInterface(
272
+ fn=phonemize,
273
+ input_components=input_components,
274
+ output_components=output_components,
275
+ max_parallel_tasks=5
276
+ )
277
+ ,
278
+ 'words' : GradioInterface(
279
+ fn=listWords,
280
+ input_components=input_components,
281
+ output_components=output_components,
282
+ max_parallel_tasks=5
283
+ )
284
+ ,
285
+
286
+ }
287
+
288
+
289
+ @app.route("/", methods=["GET"])
290
+ def index():
291
+ return render_template("tab-2-6-template.html", components=ifaces['tts'].render_components())
292
+
293
+ @app.route("/submit", methods=["POST"])
294
+ def submit():
295
+ tab = request.form.get("tab")
296
+ task_id = ifaces[tab].submit(request.form)
297
+
298
+ if task_id:
299
+ position = ifaces[tab].get_queue_position()
300
+ return jsonify({"task_id": task_id, "position": position})
301
+ else:
302
+ return jsonify({"error": "Task queue is full"}), 429
303
+
304
+ @app.route("/result/<task_id>/<tab>", methods=["GET"])
305
+ def result(task_id,tab):
306
+ result_data = ifaces[tab].get_result(task_id)
307
+ if result_data["status"] == "completed":
308
+ return jsonify(result_data)
309
+ return jsonify({"status": result_data["status"]})
310
+
311
+ @app.route("/queue", methods=["GET"])
312
+ def queue():
313
+ return jsonify({"queue": list(iface.task_queue)})
314
+
315
+ @app.route("/stop/<task_id>", methods=["POST"])
316
+ def stop(task_id):
317
+ stopped = iface.stop_task(task_id)
318
+ if stopped:
319
+ return jsonify({"status": "stopped"})
320
+ return jsonify({"status": "not found"}), 404
321
+
322
+ @app.route('/static/<path:filename>')
323
+ def send_static(filename):
324
+ return send_from_directory(static_folder, filename)
325
+ @app.route('/download/fa_extra')
326
+ def download():
327
+ return send_file(phonetc_data_file_path, as_attachment=True)
328
+ @app.route('/download/fa_dict')
329
+ def download1():
330
+ dict_file='fa_dict'
331
+ return send_file(os.path.join(find_espeak_ng_data_folder(),dict_file ), as_attachment=True)
332
+ if __name__ == "__main__":
333
+ app.run(host='0.0.0.0', port= 7860))