karim23657 commited on
Commit
5726cfd
·
verified ·
1 Parent(s): b6c6c59

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +511 -512
templates/index.html CHANGED
@@ -1,513 +1,512 @@
1
- <!DOCTYPE html>
2
- <html lang="fa">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Karim23657</title>
7
- <link rel="stylesheet" href="/static/bootstrap.min.css">
8
- <script src="/static/jquery.min.js"></script>
9
- <link rel="stylesheet" href="../static/bootstrap.min.css">
10
- <script src="../static/jquery.min.js"></script>
11
- <style>
12
- @font-face {
13
- font-family: 'Sahel';
14
- src: url('/static/sahel.ttf') format('truetype');
15
- font-weight: normal;
16
- font-style: normal;
17
- font-display: swap;
18
- }
19
- body {
20
- font-family: Sahel, sans-serif;
21
- background-color: #f4f4f9;
22
- padding: 20px;
23
- text-align: center;
24
- direction: rtl; /* Right-to-left direction */
25
- }
26
- .content {
27
- padding: 20px;
28
- text-align: center;
29
- }
30
- .tab-pane {
31
- display: none;
32
- }
33
- .tab-pane.active {
34
- display: block;
35
- }
36
-
37
-
38
- .visualizer {
39
- display: flex;
40
- justify-content: center;
41
- align-items: flex-end;
42
- height: 30px;
43
- gap: 3px;
44
- margin: 20px 0;
45
- }
46
-
47
- .bar {
48
- width: 3px;
49
- background: #1db9b9;
50
- border-radius: 3px;
51
- animation: bounce 1s infinite;
52
- }
53
-
54
- @keyframes bounce {
55
-
56
- 0%,
57
- 100% {
58
- height: 5px;
59
- }
60
-
61
- 50% {
62
- height: 20px;
63
- }
64
- }
65
- </style>
66
- </head>
67
- <body>
68
-
69
- <div class="container mt-5">
70
- <!-- Tabs -->
71
- <ul class="nav nav-tabs">
72
- <li class="nav-item">
73
- <a class="nav-link active" href="#" data-target="#home">متن به گفتار 🗣️</a>
74
- </li>
75
- <li class="nav-item">
76
- <a class="nav-link" href="#" data-target="#menu1">ویرایش تلفظ</a>
77
- </li>
78
- <li class="nav-item">
79
- <a class="nav-link" href="#" data-target="#menu2">واژه های اخیر</a>
80
- </li>
81
- </ul>
82
-
83
- <!-- Tab Content -->
84
- <div class="tab-content">
85
- <div id="home" class="container tab-pane active content"><br>
86
- <h3 class="mb-3">متن به گفتار 🗣️</h3>
87
- <div class="row">
88
- <form class="form col-md-6 input" dir="rtl" id="tts">
89
- <input type="hidden" name="tab" value="tts">
90
- <div class="form-group">
91
- <div class="rounded p-2 border" style="background-color: #f8f9fa;">
92
- <div class="form-group">
93
-
94
- <label for="textarea" class="d-flex justify-content-start">متن:</label>
95
- <textarea class="form-control" id="textarea" rows="3" name="text" required></textarea>
96
-
97
- </div>
98
- <div class="form-group">
99
-
100
- <label class="d-flex justify-content-start">انتخاب صدا:</label>
101
-
102
- {{ components|safe }}
103
-
104
-
105
- </div>
106
-
107
- </div>
108
- </div>
109
-
110
- <div class="form-group">
111
- <div class="row mb-3">
112
- <div class="col">
113
- <button class="btn btn-light btn-outline-dark btn-block" type="submit" value="submit">بگو</button>
114
- </div>
115
- <div class="col">
116
- <button class="btn btn-light btn-outline-dark btn-block" value="stop">توقف</button>
117
- </div>
118
- </div>
119
- </div>
120
-
121
- </form>
122
-
123
- <div class="form-group col-md-6 output">
124
- <div class="rounded p-2 border" style="background-color: #f8f9fa;">
125
-
126
- <label for="tts-audio" class="d-flex justify-content-start">صوت:</label>
127
- <audio controls id="tts-audio" class="col-12 result">Your browser does not support the audio element.</audio>
128
-
129
- <label for="status" class="d-flex justify-content-start">وضعیت:</label>
130
- <textarea class="form-control result" id="status" rows="2" disabled></textarea>
131
-
132
-
133
- </div>
134
- </div>
135
-
136
- </div>
137
-
138
-
139
- </div>
140
-
141
-
142
- <div id="menu1" class="container tab-pane content">
143
- <br>
144
- <h3 class="mb-3">ویرایش تلفظ واژه</h3>
145
-
146
- <div class="row">
147
-
148
- <div class="form-group col-md-6">
149
-
150
- <form dir="rtl" class="form-group " id="phonemize">
151
- <input type="hidden" name="tab" value="phonemize">
152
- <div class="rounded p-2 border mb-3" style="background-color: #f8f9fa;">
153
- <div class="form-group row align-items-center">
154
- <div class="col-2"><label for="input_word" class="col-form-label">واژه:</label></div>
155
- <div class="col-10"><input type="text" class="form-control" id="input_word" name="word" placeholder="واژه را وارد کنید"></div>
156
- </div>
157
- <div class="form-group row align-items-center">
158
- <div class="col-2"><label for="phonetics" class="d-flex justify-content-start">تلفظ:</label></div>
159
- <div class="col-10"><input type="text" class="form-control result" id="phonetics" name="phonetic" placeholder="تلفظ را وارد کنید"></div>
160
- </div>
161
-
162
- </div>
163
-
164
- <div class="form-group row align-items-center">
165
- <div class="col"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="phonemize">آوانویسی</button></div>
166
- <div class="col"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="say">بگو</button></div>
167
- <div class="col"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="send">ارسال واژه</button></div>
168
- </div>
169
- </form>
170
- </div>
171
-
172
- <div class="form-group col-md-6">
173
- <div class="rounded p-2 border" style="background-color: #f8f9fa;">
174
-
175
- <label for="audio" class="d-flex justify-content-start">صوت:</label>
176
- <audio controls id="audio" class="col-12 result">Your browser does not support the audio element.</audio>
177
-
178
- <label for="status" class="d-flex justify-content-start">وضعیت:</label>
179
- <textarea class="form-control result" id="status" rows="2" disabled></textarea>
180
-
181
-
182
- </div>
183
- </div>
184
-
185
- </div>
186
-
187
-
188
- </div>
189
-
190
-
191
-
192
- <div id="menu2" class="container tab-pane content"><br>
193
- <h3>واژه هایی که ثبت شده</h3>
194
- <form dir="rtl" class="form-group " id="words">
195
- <input type="hidden" name="tab" value="words">
196
- <div class="form-group row align-items-center">
197
- <div class="col-6"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="words">بروز رسانی</button></div>
198
- <div class="col-3"><a class="btn btn-light btn-outline-dark btn-block" href="/download/fa_dict">dict ⇩</a></div>
199
- <div class="col-3"><a class="btn btn-light btn-outline-dark btn-block" href="/download/fa_extra">list ⇩</a></div>
200
- </div>
201
- <table class="table table-bordered table-striped result">
202
- <thead>
203
- <tr>
204
- <th>#</th>
205
- <th>واژه</th>
206
- <th>تلفظ</th>
207
- </tr>
208
- </thead>
209
- <tbody>
210
-
211
- </tbody>
212
- </table>
213
- </form>
214
- </div>
215
- </div>
216
- </div>
217
-
218
- <script>
219
- $(document).ready(function() {
220
-
221
- $('.nav-link').on('click', function(e) {
222
- e.preventDefault();
223
- $('.nav-link').removeClass('active');
224
- $(this).addClass('active');
225
-
226
- var target = $(this).data('target');
227
- $('.tab-pane').removeClass('active');
228
- $(target).addClass('active');
229
- });
230
-
231
- let currentTaskId = null;
232
- let resultCheckInterval = null;
233
-
234
-
235
- function createLoadingOverlay(element) {
236
- const overlay = $("<div>", {
237
- class: "loading-overlay position-absolute top-0 start-0 d-flex justify-content-center align-items-center bg-secondary bg-opacity-50",
238
- css: {
239
- zIndex: 1000,
240
- fontFamily: 'sans-serif' // Or a suitable Persian font
241
- }
242
- });
243
-
244
- // Use RTL layout for Persian text
245
- overlay.html('<span class="spinner-border spinner-border-sm text-light ms-2" role="status"></span><span class="text-light mr-3" dir="rtl">در حال بارگذاری... <span id="loading-counter">0.00</span></span>');
246
-
247
-
248
- $("body").append(overlay);
249
-
250
- let counter = 0.00;
251
- const counterInterval = setInterval(() => {
252
- counter = parseFloat((counter + 0.01).toFixed(2));
253
- $("#loading-counter", overlay).text(counter.toFixed(2));
254
- }, 10);
255
-
256
- overlay.data('counterInterval', counterInterval);
257
- overlay.data('element', element);
258
-
259
- updateOverlayPosition(overlay);
260
-
261
- $(window).on("resize.overlay scroll.overlay", function() {
262
- updateOverlayPosition(overlay);
263
- });
264
-
265
- return overlay;
266
- }
267
-
268
- function updateOverlayPosition(overlay) {
269
- const element = overlay.data('element');
270
- if (!element || !element.length) {
271
- return;
272
- }
273
-
274
- const elementPosition = element.offset();
275
- const elementWidth = element.outerWidth();
276
- const elementHeight = element.outerHeight();
277
-
278
- overlay.css({
279
- top: elementPosition.top,
280
- left: elementPosition.left,
281
- width: elementWidth,
282
- height: elementHeight
283
- });
284
- }
285
-
286
- function destroyOverlayAll(elements) {
287
- elements.each(function() {
288
- const $this = $(this);
289
- destroyOverlay($this);
290
- });
291
- }
292
- function destroyOverlay(element) {
293
- const overlay = $(".loading-overlay").filter(function() {
294
- return $(this).data('element')[0] === element[0];
295
- });
296
- if (overlay.length) {
297
- clearInterval(overlay.data('counterInterval'));
298
- $(window).off("resize.overlay scroll.overlay");
299
- overlay.remove();
300
- }
301
- }
302
-
303
-
304
- $('#tts').on('submit', function(e) {
305
- e.preventDefault();
306
- const formData = new FormData(this);
307
- $(this).parent().find('.result').each(function() {
308
- const $this = $(this);
309
- const overlay = createLoadingOverlay($this);
310
- });
311
-
312
- const clickedButton = $(e.originalEvent.submitter);
313
-
314
- if(clickedButton.val()=='submit'){
315
-
316
- clickedButton.prop('disabled',true)
317
-
318
- $.ajax({
319
- url: '/submit',
320
- type: 'POST',
321
- data: formData,
322
- contentType: false,
323
- processData: false,
324
- success: function(data) {
325
- currentTaskId = data.task_id;
326
- const position = data.position;
327
- //$('#queuePosition').html(`Your task is in position: ${position}`);
328
-
329
- checkResult(currentTaskId);
330
- },
331
- error: function(xhr) {
332
- destroyOverlayAll($('#tts').parent().find('.result'));
333
- if (xhr.status === 429) {
334
- //$('#queuePosition').html('Error: Task queue is full. Please try again later.');
335
- clickedButton.prop('disabled',false)
336
- }
337
- }
338
- });
339
- }else if(clickedButton.val()=='stop'){
340
-
341
- if (currentTaskId) {
342
- $.post(`/stop/${currentTaskId}`, function(data) {
343
- destroyOverlayAll($('#tts').parent().find('.result'));
344
- clearInterval(resultCheckInterval);
345
- }).fail(function() {
346
- //$('#queuePosition').html('Error stopping the task. It may have already completed.');
347
- });
348
- }
349
-
350
- }
351
-
352
-
353
- function checkResult(taskId) {
354
- resultCheckInterval = setInterval(function() {
355
- $.get(`/result/${taskId}/tts`, function(data) {
356
- if (data.status === "completed") {
357
- clearInterval(resultCheckInterval);
358
- $('#status').val(data.result.status);
359
- $('#tts-audio').attr('src', data.result.audio); // Update audio source
360
- destroyOverlayAll($('#tts').parent().find('.result'));
361
- clickedButton.prop('disabled',false)
362
-
363
- }
364
- });
365
- }, 1000); // Check every second for a faster response
366
- }
367
-
368
- });
369
-
370
-
371
-
372
- $('#phonemize').on('submit', function(e) {
373
- e.preventDefault();
374
- const formData = new FormData(this);
375
-
376
- let parentEl = $(this).parent().parent();
377
- let result_holders = parentEl.find('.result');
378
- result_holders.each(function() {
379
- const $this = $(this);
380
- const overlay = createLoadingOverlay($this);
381
- });
382
-
383
- const clickedButton = $(e.originalEvent.submitter);
384
- console.log(clickedButton.val());
385
-
386
- if(['say','phonemize','send'].includes(clickedButton.val())){
387
-
388
- clickedButton.prop('disabled',true);
389
- formData.append('task',clickedButton.val());
390
-
391
-
392
- $.ajax({
393
- url: '/submit',
394
- type: 'POST',
395
- data: formData,
396
- contentType: false,
397
- processData: false,
398
- success: function(data) {
399
- currentTaskId = data.task_id;
400
- const position = data.position;
401
- //$('#queuePosition').html(`Your task is in position: ${position}`);
402
-
403
- checkResult(currentTaskId);
404
- },
405
- error: function(xhr) {
406
- destroyOverlayAll(result_holders);
407
- if (xhr.status === 429) {
408
- //$('#queuePosition').html('Error: Task queue is full. Please try again later.');
409
- clickedButton.prop('disabled',false)
410
- }
411
- }
412
- });
413
-
414
- }
415
-
416
-
417
- function checkResult(taskId) {
418
- resultCheckInterval = setInterval(function() {
419
- $.get(`/result/${taskId}/phonemize`, function(data) {
420
- if (data.status === "completed") {
421
- clearInterval(resultCheckInterval);
422
- parentEl.find('#phonetics').val(data.result.phonemes);
423
- parentEl.find('#status').val(data.result.status);
424
- parentEl.find('#audio').attr('src', data.result.audio); // Update audio source
425
- destroyOverlayAll(result_holders);
426
- clickedButton.prop('disabled',false)
427
-
428
- }
429
- });
430
- }, 1000); // Check every second for a faster response
431
- }
432
-
433
- });
434
-
435
-
436
- $('#words').on('submit', function(e) {
437
- e.preventDefault();
438
- let parentEl = $(this).parent();
439
- let result_holders = parentEl.find('.result');
440
- const formData = new FormData(this);
441
- result_holders.each(function() {
442
- const $this = $(this);
443
- const overlay = createLoadingOverlay($this);
444
- });
445
-
446
- const clickedButton = $(e.originalEvent.submitter);
447
- console.log(clickedButton.val());
448
-
449
-
450
- clickedButton.prop('disabled',true);
451
- formData.append('task',clickedButton.val());
452
-
453
-
454
- $.ajax({
455
- url: '/submit',
456
- type: 'POST',
457
- data: formData,
458
- contentType: false,
459
- processData: false,
460
- success: function(data) {
461
- currentTaskId = data.task_id;
462
- const position = data.position;
463
- //$('#queuePosition').html(`Your task is in position: ${position}`);
464
-
465
- checkResult(currentTaskId);
466
- },
467
- error: function(xhr) {
468
- destroyOverlayAll(result_holders);
469
- if (xhr.status === 429) {
470
- //$('#queuePosition').html('Error: Task queue is full. Please try again later.');
471
- clickedButton.prop('disabled',false)
472
- }
473
- }
474
- });
475
-
476
-
477
-
478
-
479
- function checkResult(taskId) {
480
- resultCheckInterval = setInterval(function() {
481
- $.get(`/result/${taskId}/words`, function(data) {
482
- if (data.status === "completed") {
483
- clearInterval(resultCheckInterval);
484
- let tbody = parentEl.find('tbody');
485
- tbody.empty();
486
- data.result.forEach(function(item, index) {
487
- tbody.append(`<tr><td>${index + 1}</td><td>${item.word}</td><td>${item.phonetic}</td></tr>`);
488
- });
489
- destroyOverlayAll(result_holders);
490
- clickedButton.prop('disabled',false)
491
-
492
- }
493
- });
494
- }, 1000); // Check every second for a faster response
495
- }
496
-
497
- });
498
-
499
-
500
-
501
-
502
-
503
-
504
- });
505
-
506
-
507
-
508
-
509
-
510
- </script>
511
-
512
- </body>
513
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="fa">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Karim23657</title>
7
+ <link rel="stylesheet" href="/static/bootstrap.min.css">
8
+ <script src="/static/jquery.min.js"></script>
9
+
10
+ <style>
11
+ @font-face {
12
+ font-family: 'Sahel';
13
+ src: url('/static/sahel.ttf') format('truetype');
14
+ font-weight: normal;
15
+ font-style: normal;
16
+ font-display: swap;
17
+ }
18
+ body {
19
+ font-family: Sahel, sans-serif;
20
+ background-color: #f4f4f9;
21
+ padding: 20px;
22
+ text-align: center;
23
+ direction: rtl; /* Right-to-left direction */
24
+ }
25
+ .content {
26
+ padding: 20px;
27
+ text-align: center;
28
+ }
29
+ .tab-pane {
30
+ display: none;
31
+ }
32
+ .tab-pane.active {
33
+ display: block;
34
+ }
35
+
36
+
37
+ .visualizer {
38
+ display: flex;
39
+ justify-content: center;
40
+ align-items: flex-end;
41
+ height: 30px;
42
+ gap: 3px;
43
+ margin: 20px 0;
44
+ }
45
+
46
+ .bar {
47
+ width: 3px;
48
+ background: #1db9b9;
49
+ border-radius: 3px;
50
+ animation: bounce 1s infinite;
51
+ }
52
+
53
+ @keyframes bounce {
54
+
55
+ 0%,
56
+ 100% {
57
+ height: 5px;
58
+ }
59
+
60
+ 50% {
61
+ height: 20px;
62
+ }
63
+ }
64
+ </style>
65
+ </head>
66
+ <body>
67
+
68
+ <div class="container mt-5">
69
+ <!-- Tabs -->
70
+ <ul class="nav nav-tabs">
71
+ <li class="nav-item">
72
+ <a class="nav-link active" href="#" data-target="#home">متن به گفتار 🗣️</a>
73
+ </li>
74
+ <li class="nav-item">
75
+ <a class="nav-link" href="#" data-target="#menu1">ویرایش تلفظ</a>
76
+ </li>
77
+ <li class="nav-item">
78
+ <a class="nav-link" href="#" data-target="#menu2">واژه های اخیر</a>
79
+ </li>
80
+ </ul>
81
+
82
+ <!-- Tab Content -->
83
+ <div class="tab-content">
84
+ <div id="home" class="container tab-pane active content"><br>
85
+ <h3 class="mb-3">متن به گفتار 🗣️</h3>
86
+ <div class="row">
87
+ <form class="form col-md-6 input" dir="rtl" id="tts">
88
+ <input type="hidden" name="tab" value="tts">
89
+ <div class="form-group">
90
+ <div class="rounded p-2 border" style="background-color: #f8f9fa;">
91
+ <div class="form-group">
92
+
93
+ <label for="textarea" class="d-flex justify-content-start">متن:</label>
94
+ <textarea class="form-control" id="textarea" rows="3" name="text" required></textarea>
95
+
96
+ </div>
97
+ <div class="form-group">
98
+
99
+ <label class="d-flex justify-content-start">انتخاب صدا:</label>
100
+
101
+ {{ components|safe }}
102
+
103
+
104
+ </div>
105
+
106
+ </div>
107
+ </div>
108
+
109
+ <div class="form-group">
110
+ <div class="row mb-3">
111
+ <div class="col">
112
+ <button class="btn btn-light btn-outline-dark btn-block" type="submit" value="submit">بگو</button>
113
+ </div>
114
+ <div class="col">
115
+ <button class="btn btn-light btn-outline-dark btn-block" value="stop">توقف</button>
116
+ </div>
117
+ </div>
118
+ </div>
119
+
120
+ </form>
121
+
122
+ <div class="form-group col-md-6 output">
123
+ <div class="rounded p-2 border" style="background-color: #f8f9fa;">
124
+
125
+ <label for="tts-audio" class="d-flex justify-content-start">صوت:</label>
126
+ <audio controls id="tts-audio" class="col-12 result">Your browser does not support the audio element.</audio>
127
+
128
+ <label for="status" class="d-flex justify-content-start">وضعیت:</label>
129
+ <textarea class="form-control result" id="status" rows="2" disabled></textarea>
130
+
131
+
132
+ </div>
133
+ </div>
134
+
135
+ </div>
136
+
137
+
138
+ </div>
139
+
140
+
141
+ <div id="menu1" class="container tab-pane content">
142
+ <br>
143
+ <h3 class="mb-3">ویرایش تلفظ واژه</h3>
144
+
145
+ <div class="row">
146
+
147
+ <div class="form-group col-md-6">
148
+
149
+ <form dir="rtl" class="form-group " id="phonemize">
150
+ <input type="hidden" name="tab" value="phonemize">
151
+ <div class="rounded p-2 border mb-3" style="background-color: #f8f9fa;">
152
+ <div class="form-group row align-items-center">
153
+ <div class="col-2"><label for="input_word" class="col-form-label">واژه:</label></div>
154
+ <div class="col-10"><input type="text" class="form-control" id="input_word" name="word" placeholder="واژه را وارد کنید"></div>
155
+ </div>
156
+ <div class="form-group row align-items-center">
157
+ <div class="col-2"><label for="phonetics" class="d-flex justify-content-start">تلفظ:</label></div>
158
+ <div class="col-10"><input type="text" class="form-control result" id="phonetics" name="phonetic" placeholder="تلفظ را وارد کنید"></div>
159
+ </div>
160
+
161
+ </div>
162
+
163
+ <div class="form-group row align-items-center">
164
+ <div class="col"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="phonemize">آوانویسی</button></div>
165
+ <div class="col"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="say">بگو</button></div>
166
+ <div class="col"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="send">ارسال واژه</button></div>
167
+ </div>
168
+ </form>
169
+ </div>
170
+
171
+ <div class="form-group col-md-6">
172
+ <div class="rounded p-2 border" style="background-color: #f8f9fa;">
173
+
174
+ <label for="audio" class="d-flex justify-content-start">صوت:</label>
175
+ <audio controls id="audio" class="col-12 result">Your browser does not support the audio element.</audio>
176
+
177
+ <label for="status" class="d-flex justify-content-start">وضعیت:</label>
178
+ <textarea class="form-control result" id="status" rows="2" disabled></textarea>
179
+
180
+
181
+ </div>
182
+ </div>
183
+
184
+ </div>
185
+
186
+
187
+ </div>
188
+
189
+
190
+
191
+ <div id="menu2" class="container tab-pane content"><br>
192
+ <h3>واژه هایی که ثبت شده</h3>
193
+ <form dir="rtl" class="form-group " id="words">
194
+ <input type="hidden" name="tab" value="words">
195
+ <div class="form-group row align-items-center">
196
+ <div class="col-6"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="words">بروز رسانی</button></div>
197
+ <div class="col-3"><a class="btn btn-light btn-outline-dark btn-block" href="/download/fa_dict">dict ⇩</a></div>
198
+ <div class="col-3"><a class="btn btn-light btn-outline-dark btn-block" href="/download/fa_extra">list ⇩</a></div>
199
+ </div>
200
+ <table class="table table-bordered table-striped result">
201
+ <thead>
202
+ <tr>
203
+ <th>#</th>
204
+ <th>واژه</th>
205
+ <th>تلفظ</th>
206
+ </tr>
207
+ </thead>
208
+ <tbody>
209
+
210
+ </tbody>
211
+ </table>
212
+ </form>
213
+ </div>
214
+ </div>
215
+ </div>
216
+
217
+ <script>
218
+ $(document).ready(function() {
219
+
220
+ $('.nav-link').on('click', function(e) {
221
+ e.preventDefault();
222
+ $('.nav-link').removeClass('active');
223
+ $(this).addClass('active');
224
+
225
+ var target = $(this).data('target');
226
+ $('.tab-pane').removeClass('active');
227
+ $(target).addClass('active');
228
+ });
229
+
230
+ let currentTaskId = null;
231
+ let resultCheckInterval = null;
232
+
233
+
234
+ function createLoadingOverlay(element) {
235
+ const overlay = $("<div>", {
236
+ class: "loading-overlay position-absolute top-0 start-0 d-flex justify-content-center align-items-center bg-secondary bg-opacity-50",
237
+ css: {
238
+ zIndex: 1000,
239
+ fontFamily: 'sans-serif' // Or a suitable Persian font
240
+ }
241
+ });
242
+
243
+ // Use RTL layout for Persian text
244
+ overlay.html('<span class="spinner-border spinner-border-sm text-light ms-2" role="status"></span><span class="text-light mr-3" dir="rtl">در حال بارگذاری... <span id="loading-counter">0.00</span></span>');
245
+
246
+
247
+ $("body").append(overlay);
248
+
249
+ let counter = 0.00;
250
+ const counterInterval = setInterval(() => {
251
+ counter = parseFloat((counter + 0.01).toFixed(2));
252
+ $("#loading-counter", overlay).text(counter.toFixed(2));
253
+ }, 10);
254
+
255
+ overlay.data('counterInterval', counterInterval);
256
+ overlay.data('element', element);
257
+
258
+ updateOverlayPosition(overlay);
259
+
260
+ $(window).on("resize.overlay scroll.overlay", function() {
261
+ updateOverlayPosition(overlay);
262
+ });
263
+
264
+ return overlay;
265
+ }
266
+
267
+ function updateOverlayPosition(overlay) {
268
+ const element = overlay.data('element');
269
+ if (!element || !element.length) {
270
+ return;
271
+ }
272
+
273
+ const elementPosition = element.offset();
274
+ const elementWidth = element.outerWidth();
275
+ const elementHeight = element.outerHeight();
276
+
277
+ overlay.css({
278
+ top: elementPosition.top,
279
+ left: elementPosition.left,
280
+ width: elementWidth,
281
+ height: elementHeight
282
+ });
283
+ }
284
+
285
+ function destroyOverlayAll(elements) {
286
+ elements.each(function() {
287
+ const $this = $(this);
288
+ destroyOverlay($this);
289
+ });
290
+ }
291
+ function destroyOverlay(element) {
292
+ const overlay = $(".loading-overlay").filter(function() {
293
+ return $(this).data('element')[0] === element[0];
294
+ });
295
+ if (overlay.length) {
296
+ clearInterval(overlay.data('counterInterval'));
297
+ $(window).off("resize.overlay scroll.overlay");
298
+ overlay.remove();
299
+ }
300
+ }
301
+
302
+
303
+ $('#tts').on('submit', function(e) {
304
+ e.preventDefault();
305
+ const formData = new FormData(this);
306
+ $(this).parent().find('.result').each(function() {
307
+ const $this = $(this);
308
+ const overlay = createLoadingOverlay($this);
309
+ });
310
+
311
+ const clickedButton = $(e.originalEvent.submitter);
312
+
313
+ if(clickedButton.val()=='submit'){
314
+
315
+ clickedButton.prop('disabled',true)
316
+
317
+ $.ajax({
318
+ url: '/submit',
319
+ type: 'POST',
320
+ data: formData,
321
+ contentType: false,
322
+ processData: false,
323
+ success: function(data) {
324
+ currentTaskId = data.task_id;
325
+ const position = data.position;
326
+ //$('#queuePosition').html(`Your task is in position: ${position}`);
327
+
328
+ checkResult(currentTaskId);
329
+ },
330
+ error: function(xhr) {
331
+ destroyOverlayAll($('#tts').parent().find('.result'));
332
+ if (xhr.status === 429) {
333
+ //$('#queuePosition').html('Error: Task queue is full. Please try again later.');
334
+ clickedButton.prop('disabled',false)
335
+ }
336
+ }
337
+ });
338
+ }else if(clickedButton.val()=='stop'){
339
+
340
+ if (currentTaskId) {
341
+ $.post(`/stop/${currentTaskId}`, function(data) {
342
+ destroyOverlayAll($('#tts').parent().find('.result'));
343
+ clearInterval(resultCheckInterval);
344
+ }).fail(function() {
345
+ //$('#queuePosition').html('Error stopping the task. It may have already completed.');
346
+ });
347
+ }
348
+
349
+ }
350
+
351
+
352
+ function checkResult(taskId) {
353
+ resultCheckInterval = setInterval(function() {
354
+ $.get(`/result/${taskId}/tts`, function(data) {
355
+ if (data.status === "completed") {
356
+ clearInterval(resultCheckInterval);
357
+ $('#status').val(data.result.status);
358
+ $('#tts-audio').attr('src', data.result.audio); // Update audio source
359
+ destroyOverlayAll($('#tts').parent().find('.result'));
360
+ clickedButton.prop('disabled',false)
361
+
362
+ }
363
+ });
364
+ }, 1000); // Check every second for a faster response
365
+ }
366
+
367
+ });
368
+
369
+
370
+
371
+ $('#phonemize').on('submit', function(e) {
372
+ e.preventDefault();
373
+ const formData = new FormData(this);
374
+
375
+ let parentEl = $(this).parent().parent();
376
+ let result_holders = parentEl.find('.result');
377
+ result_holders.each(function() {
378
+ const $this = $(this);
379
+ const overlay = createLoadingOverlay($this);
380
+ });
381
+
382
+ const clickedButton = $(e.originalEvent.submitter);
383
+ console.log(clickedButton.val());
384
+
385
+ if(['say','phonemize','send'].includes(clickedButton.val())){
386
+
387
+ clickedButton.prop('disabled',true);
388
+ formData.append('task',clickedButton.val());
389
+
390
+
391
+ $.ajax({
392
+ url: '/submit',
393
+ type: 'POST',
394
+ data: formData,
395
+ contentType: false,
396
+ processData: false,
397
+ success: function(data) {
398
+ currentTaskId = data.task_id;
399
+ const position = data.position;
400
+ //$('#queuePosition').html(`Your task is in position: ${position}`);
401
+
402
+ checkResult(currentTaskId);
403
+ },
404
+ error: function(xhr) {
405
+ destroyOverlayAll(result_holders);
406
+ if (xhr.status === 429) {
407
+ //$('#queuePosition').html('Error: Task queue is full. Please try again later.');
408
+ clickedButton.prop('disabled',false)
409
+ }
410
+ }
411
+ });
412
+
413
+ }
414
+
415
+
416
+ function checkResult(taskId) {
417
+ resultCheckInterval = setInterval(function() {
418
+ $.get(`/result/${taskId}/phonemize`, function(data) {
419
+ if (data.status === "completed") {
420
+ clearInterval(resultCheckInterval);
421
+ parentEl.find('#phonetics').val(data.result.phonemes);
422
+ parentEl.find('#status').val(data.result.status);
423
+ parentEl.find('#audio').attr('src', data.result.audio); // Update audio source
424
+ destroyOverlayAll(result_holders);
425
+ clickedButton.prop('disabled',false)
426
+
427
+ }
428
+ });
429
+ }, 1000); // Check every second for a faster response
430
+ }
431
+
432
+ });
433
+
434
+
435
+ $('#words').on('submit', function(e) {
436
+ e.preventDefault();
437
+ let parentEl = $(this).parent();
438
+ let result_holders = parentEl.find('.result');
439
+ const formData = new FormData(this);
440
+ result_holders.each(function() {
441
+ const $this = $(this);
442
+ const overlay = createLoadingOverlay($this);
443
+ });
444
+
445
+ const clickedButton = $(e.originalEvent.submitter);
446
+ console.log(clickedButton.val());
447
+
448
+
449
+ clickedButton.prop('disabled',true);
450
+ formData.append('task',clickedButton.val());
451
+
452
+
453
+ $.ajax({
454
+ url: '/submit',
455
+ type: 'POST',
456
+ data: formData,
457
+ contentType: false,
458
+ processData: false,
459
+ success: function(data) {
460
+ currentTaskId = data.task_id;
461
+ const position = data.position;
462
+ //$('#queuePosition').html(`Your task is in position: ${position}`);
463
+
464
+ checkResult(currentTaskId);
465
+ },
466
+ error: function(xhr) {
467
+ destroyOverlayAll(result_holders);
468
+ if (xhr.status === 429) {
469
+ //$('#queuePosition').html('Error: Task queue is full. Please try again later.');
470
+ clickedButton.prop('disabled',false)
471
+ }
472
+ }
473
+ });
474
+
475
+
476
+
477
+
478
+ function checkResult(taskId) {
479
+ resultCheckInterval = setInterval(function() {
480
+ $.get(`/result/${taskId}/words`, function(data) {
481
+ if (data.status === "completed") {
482
+ clearInterval(resultCheckInterval);
483
+ let tbody = parentEl.find('tbody');
484
+ tbody.empty();
485
+ data.result.forEach(function(item, index) {
486
+ tbody.append(`<tr><td>${index + 1}</td><td>${item.word}</td><td>${item.phonetic}</td></tr>`);
487
+ });
488
+ destroyOverlayAll(result_holders);
489
+ clickedButton.prop('disabled',false)
490
+
491
+ }
492
+ });
493
+ }, 1000); // Check every second for a faster response
494
+ }
495
+
496
+ });
497
+
498
+
499
+
500
+
501
+
502
+
503
+ });
504
+
505
+
506
+
507
+
508
+
509
+ </script>
510
+
511
+ </body>
 
512
  </html>