Coco-18 commited on
Commit
6fe5cfd
·
verified ·
1 Parent(s): eddb57d

Upload index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +384 -0
templates/index.html ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Speech Processing App</title>
7
+ <style>
8
+ body {
9
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
10
+ line-height: 1.6;
11
+ color: #333;
12
+ max-width: 800px;
13
+ margin: 0 auto;
14
+ padding: 20px;
15
+ background-color: #f5f5f5;
16
+ }
17
+ h1, h2 {
18
+ color: #2c3e50;
19
+ text-align: center;
20
+ }
21
+ .container {
22
+ background-color: white;
23
+ border-radius: 8px;
24
+ padding: 20px;
25
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
26
+ margin-bottom: 20px;
27
+ }
28
+ .form-group {
29
+ margin-bottom: 15px;
30
+ }
31
+ label {
32
+ display: block;
33
+ margin-bottom: 5px;
34
+ font-weight: bold;
35
+ }
36
+ select, button, input[type="text"], textarea {
37
+ width: 100%;
38
+ padding: 10px;
39
+ border: 1px solid #ddd;
40
+ border-radius: 4px;
41
+ box-sizing: border-box;
42
+ font-size: 16px;
43
+ }
44
+ button {
45
+ background-color: #3498db;
46
+ color: white;
47
+ border: none;
48
+ cursor: pointer;
49
+ font-weight: bold;
50
+ margin-top: 10px;
51
+ transition: background-color 0.3s;
52
+ }
53
+ button:hover {
54
+ background-color: #2980b9;
55
+ }
56
+ .result {
57
+ margin-top: 15px;
58
+ padding: 15px;
59
+ border-radius: 4px;
60
+ border-left: 4px solid #3498db;
61
+ background-color: #ecf0f1;
62
+ word-wrap: break-word;
63
+ }
64
+ .status {
65
+ margin-top: 10px;
66
+ font-style: italic;
67
+ color: #7f8c8d;
68
+ }
69
+ .recorder-controls {
70
+ display: flex;
71
+ gap: 10px;
72
+ margin-bottom: 10px;
73
+ }
74
+ .recorder-controls button {
75
+ flex: 1;
76
+ }
77
+ .recording-indicator {
78
+ height: 15px;
79
+ width: 15px;
80
+ border-radius: 50%;
81
+ background-color: gray;
82
+ display: inline-block;
83
+ margin-right: 5px;
84
+ }
85
+ .recording {
86
+ background-color: red;
87
+ animation: pulse 1.5s infinite;
88
+ }
89
+ @keyframes pulse {
90
+ 0% { opacity: 1; }
91
+ 50% { opacity: 0.5; }
92
+ 100% { opacity: 1; }
93
+ }
94
+ audio {
95
+ width: 100%;
96
+ margin-top: 10px;
97
+ }
98
+ .tab-container {
99
+ display: flex;
100
+ margin-bottom: 20px;
101
+ }
102
+ .tab {
103
+ padding: 10px 20px;
104
+ background-color: #ddd;
105
+ cursor: pointer;
106
+ border-radius: 5px 5px 0 0;
107
+ border: 1px solid #ccc;
108
+ border-bottom: none;
109
+ margin-right: 5px;
110
+ }
111
+ .tab.active {
112
+ background-color: white;
113
+ font-weight: bold;
114
+ }
115
+ .tab-content {
116
+ display: none;
117
+ }
118
+ .tab-content.active {
119
+ display: block;
120
+ }
121
+ .loader {
122
+ display: none;
123
+ border: 5px solid #f3f3f3;
124
+ border-top: 5px solid #3498db;
125
+ border-radius: 50%;
126
+ width: 30px;
127
+ height: 30px;
128
+ animation: spin 2s linear infinite;
129
+ margin: 20px auto;
130
+ }
131
+ @keyframes spin {
132
+ 0% { transform: rotate(0deg); }
133
+ 100% { transform: rotate(360deg); }
134
+ }
135
+ </style>
136
+ </head>
137
+ <body>
138
+ <h1>Speech Processing App</h1>
139
+
140
+ <div class="tab-container">
141
+ <div class="tab active" onclick="openTab(event, 'asr-tab')">Speech Recognition</div>
142
+ <div class="tab" onclick="openTab(event, 'tts-tab')">Text to Speech</div>
143
+ </div>
144
+
145
+ <div id="asr-tab" class="tab-content active">
146
+ <div class="container">
147
+ <h2>Automatic Speech Recognition</h2>
148
+
149
+ <div class="form-group">
150
+ <label for="asr-language">Language:</label>
151
+ <select id="asr-language">
152
+ <option value="kapampangan">Kapampangan</option>
153
+ <option value="tagalog">Tagalog</option>
154
+ <option value="english" selected>English</option>
155
+ </select>
156
+ </div>
157
+
158
+ <div class="form-group">
159
+ <label>Audio Input:</label>
160
+ <div class="recorder-controls">
161
+ <button id="record-button">
162
+ <span class="recording-indicator" id="record-indicator"></span> Record
163
+ </button>
164
+ <button id="stop-button" disabled>Stop Recording</button>
165
+ </div>
166
+ <p class="status" id="recording-status">Not recording</p>
167
+
168
+ <label>Or upload audio file:</label>
169
+ <input type="file" id="audio-upload" accept="audio/*">
170
+ </div>
171
+
172
+ <button id="transcribe-button">Transcribe</button>
173
+
174
+ <div class="loader" id="asr-loader"></div>
175
+
176
+ <div id="asr-result" class="result" style="display: none;">
177
+ <h3>Transcription Result:</h3>
178
+ <p id="transcription-text"></p>
179
+ </div>
180
+ </div>
181
+ </div>
182
+
183
+ <div id="tts-tab" class="tab-content">
184
+ <div class="container">
185
+ <h2>Text to Speech</h2>
186
+
187
+ <div class="form-group">
188
+ <label for="tts-language">Language:</label>
189
+ <select id="tts-language">
190
+ <option value="kapampangan" selected>Kapampangan</option>
191
+ <option value="tagalog">Tagalog</option>
192
+ <option value="english">English</option>
193
+ </select>
194
+ </div>
195
+
196
+ <div class="form-group">
197
+ <label for="text-input">Enter Text:</label>
198
+ <textarea id="text-input" rows="5" placeholder="Type the text you want to convert to speech..."></textarea>
199
+ </div>
200
+
201
+ <button id="synthesize-button">Generate Speech</button>
202
+
203
+ <div class="loader" id="tts-loader"></div>
204
+
205
+ <div id="tts-result" class="result" style="display: none;">
206
+ <h3>Generated Audio:</h3>
207
+ <audio id="audio-player" controls></audio>
208
+ </div>
209
+ </div>
210
+ </div>
211
+
212
+ <script>
213
+ // Global variables for recording
214
+ let mediaRecorder;
215
+ let audioChunks = [];
216
+ let isRecording = false;
217
+
218
+ // Initialize the application
219
+ document.addEventListener('DOMContentLoaded', function() {
220
+ // Tab navigation
221
+ document.getElementById('asr-tab').classList.add('active');
222
+
223
+ // Recording functionality
224
+ const recordButton = document.getElementById('record-button');
225
+ const stopButton = document.getElementById('stop-button');
226
+ const recordingStatus = document.getElementById('recording-status');
227
+ const recordIndicator = document.getElementById('record-indicator');
228
+
229
+ recordButton.addEventListener('click', async () => {
230
+ if (!isRecording) {
231
+ try {
232
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
233
+ mediaRecorder = new MediaRecorder(stream);
234
+ audioChunks = [];
235
+
236
+ mediaRecorder.ondataavailable = (event) => {
237
+ audioChunks.push(event.data);
238
+ };
239
+
240
+ mediaRecorder.onstop = () => {
241
+ isRecording = false;
242
+ recordButton.disabled = false;
243
+ stopButton.disabled = true;
244
+ recordingStatus.textContent = "Recording finished";
245
+ recordIndicator.classList.remove('recording');
246
+ };
247
+
248
+ mediaRecorder.start();
249
+ isRecording = true;
250
+ recordButton.disabled = true;
251
+ stopButton.disabled = false;
252
+ recordingStatus.textContent = "Recording...";
253
+ recordIndicator.classList.add('recording');
254
+ } catch (err) {
255
+ alert("Could not access microphone: " + err.message);
256
+ }
257
+ }
258
+ });
259
+
260
+ stopButton.addEventListener('click', () => {
261
+ if (isRecording && mediaRecorder) {
262
+ mediaRecorder.stop();
263
+ }
264
+ });
265
+
266
+ // ASR functionality
267
+ const transcribeButton = document.getElementById('transcribe-button');
268
+ const asrLanguage = document.getElementById('asr-language');
269
+ const asrLoader = document.getElementById('asr-loader');
270
+ const asrResult = document.getElementById('asr-result');
271
+ const transcriptionText = document.getElementById('transcription-text');
272
+ const audioUpload = document.getElementById('audio-upload');
273
+
274
+ transcribeButton.addEventListener('click', async () => {
275
+ let audioFile;
276
+
277
+ // Check if we have a recording or uploaded file
278
+ if (audioChunks.length > 0) {
279
+ audioFile = new Blob(audioChunks, { type: 'audio/webm' });
280
+ } else if (audioUpload.files.length > 0) {
281
+ audioFile = audioUpload.files[0];
282
+ } else {
283
+ alert("Please record audio or upload an audio file first.");
284
+ return;
285
+ }
286
+
287
+ const formData = new FormData();
288
+ formData.append('audio', audioFile);
289
+ formData.append('language', asrLanguage.value);
290
+
291
+ // Show loader
292
+ asrLoader.style.display = 'block';
293
+ asrResult.style.display = 'none';
294
+
295
+ try {
296
+ const response = await fetch('/asr', {
297
+ method: 'POST',
298
+ body: formData,
299
+ });
300
+
301
+ const data = await response.json();
302
+
303
+ if (response.ok) {
304
+ transcriptionText.textContent = data.transcription;
305
+ asrResult.style.display = 'block';
306
+ } else {
307
+ alert('Error: ' + (data.error || 'Unknown error'));
308
+ }
309
+ } catch (error) {
310
+ alert('Failed to connect to server: ' + error.message);
311
+ } finally {
312
+ asrLoader.style.display = 'none';
313
+ }
314
+ });
315
+
316
+ // TTS functionality
317
+ const synthesizeButton = document.getElementById('synthesize-button');
318
+ const ttsLanguage = document.getElementById('tts-language');
319
+ const textInput = document.getElementById('text-input');
320
+ const ttsLoader = document.getElementById('tts-loader');
321
+ const ttsResult = document.getElementById('tts-result');
322
+ const audioPlayer = document.getElementById('audio-player');
323
+
324
+ synthesizeButton.addEventListener('click', async () => {
325
+ const text = textInput.value.trim();
326
+ if (!text) {
327
+ alert('Please enter some text.');
328
+ return;
329
+ }
330
+
331
+ // Show loader
332
+ ttsLoader.style.display = 'block';
333
+ ttsResult.style.display = 'none';
334
+
335
+ try {
336
+ const response = await fetch('/tts', {
337
+ method: 'POST',
338
+ headers: {
339
+ 'Content-Type': 'application/json',
340
+ },
341
+ body: JSON.stringify({
342
+ text: text,
343
+ language: ttsLanguage.value
344
+ }),
345
+ });
346
+
347
+ const data = await response.json();
348
+
349
+ if (response.ok) {
350
+ // Update audio player with new source
351
+ audioPlayer.src = data.file_url;
352
+ ttsResult.style.display = 'block';
353
+ } else {
354
+ alert('Error: ' + (data.error || 'Unknown error'));
355
+ }
356
+ } catch (error) {
357
+ alert('Failed to connect to server: ' + error.message);
358
+ } finally {
359
+ ttsLoader.style.display = 'none';
360
+ }
361
+ });
362
+ });
363
+
364
+ // Tab navigation function
365
+ function openTab(evt, tabName) {
366
+ // Hide all tab content
367
+ const tabContents = document.getElementsByClassName('tab-content');
368
+ for (let i = 0; i < tabContents.length; i++) {
369
+ tabContents[i].classList.remove('active');
370
+ }
371
+
372
+ // Remove active class from tabs
373
+ const tabs = document.getElementsByClassName('tab');
374
+ for (let i = 0; i < tabs.length; i++) {
375
+ tabs[i].classList.remove('active');
376
+ }
377
+
378
+ // Show the selected tab content and add active class to the button
379
+ document.getElementById(tabName).classList.add('active');
380
+ evt.currentTarget.classList.add('active');
381
+ }
382
+ </script>
383
+ </body>
384
+ </html>