noumanjavaid commited on
Commit
a896f82
·
verified ·
1 Parent(s): d566fb5

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +879 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Testing Space From Deepsite
3
- emoji: 👀
4
- colorFrom: purple
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: testing-space-from-deepsite
3
+ emoji: 🐳
4
+ colorFrom: blue
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,879 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Whisper AI Transcription</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
+ <style>
9
+ :root {
10
+ --primary: #6e48aa;
11
+ --primary-dark: #4a2d8a;
12
+ --secondary: #9d50bb;
13
+ --gradient-start: #4776e6;
14
+ --gradient-end: #8e54e9;
15
+ --light: #f8f9fa;
16
+ --dark: #2d3748;
17
+ --gray: #edf2f7;
18
+ --success: #48bb78;
19
+ --danger: #e53e3e;
20
+ --warning: #ed8936;
21
+ }
22
+
23
+ * {
24
+ margin: 0;
25
+ padding: 0;
26
+ box-sizing: border-box;
27
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
28
+ }
29
+
30
+ body {
31
+ background-color: #f0f4f8;
32
+ color: var(--dark);
33
+ line-height: 1.6;
34
+ }
35
+
36
+ .container {
37
+ max-width: 1000px;
38
+ margin: 2rem auto;
39
+ padding: 0 1rem;
40
+ }
41
+
42
+ header {
43
+ text-align: center;
44
+ margin-bottom: 2rem;
45
+ }
46
+
47
+ .logo {
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ gap: 0.5rem;
52
+ margin-bottom: 1rem;
53
+ }
54
+
55
+ .logo i {
56
+ font-size: 2.5rem;
57
+ color: var(--primary);
58
+ }
59
+
60
+ h1 {
61
+ font-size: 2.5rem;
62
+ background: linear-gradient(to right, var(--gradient-start), var(--gradient-end));
63
+ -webkit-background-clip: text;
64
+ -webkit-text-fill-color: transparent;
65
+ font-weight: 700;
66
+ margin-bottom: 0.5rem;
67
+ }
68
+
69
+ .subtitle {
70
+ color: #718096;
71
+ font-size: 1.1rem;
72
+ max-width: 600px;
73
+ margin: 0 auto;
74
+ }
75
+
76
+ .card {
77
+ background: white;
78
+ border-radius: 12px;
79
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
80
+ padding: 2rem;
81
+ margin-bottom: 2rem;
82
+ }
83
+
84
+ .card-title {
85
+ font-size: 1.4rem;
86
+ margin-bottom: 1.5rem;
87
+ color: var(--primary-dark);
88
+ display: flex;
89
+ align-items: center;
90
+ gap: 0.8rem;
91
+ }
92
+
93
+ .card-title i {
94
+ font-size: 1.8rem;
95
+ color: var(--secondary);
96
+ }
97
+
98
+ .controls {
99
+ display: flex;
100
+ flex-direction: column;
101
+ gap: 1.5rem;
102
+ }
103
+
104
+ .input-group {
105
+ display: flex;
106
+ gap: 1rem;
107
+ }
108
+
109
+ @media (max-width: 768px) {
110
+ .input-group {
111
+ flex-direction: column;
112
+ }
113
+ }
114
+
115
+ .btn {
116
+ padding: 0.8rem 1.5rem;
117
+ border-radius: 8px;
118
+ border: none;
119
+ font-weight: 600;
120
+ cursor: pointer;
121
+ transition: all 0.3s ease;
122
+ display: flex;
123
+ align-items: center;
124
+ justify-content: center;
125
+ gap: 0.5rem;
126
+ font-size: 1rem;
127
+ }
128
+
129
+ .btn-primary {
130
+ background-color: var(--primary);
131
+ color: white;
132
+ }
133
+
134
+ .btn-primary:hover {
135
+ background-color: var(--primary-dark);
136
+ transform: translateY(-2px);
137
+ box-shadow: 0 4px 12px rgba(110, 72, 170, 0.3);
138
+ }
139
+
140
+ .btn-outline {
141
+ background-color: transparent;
142
+ border: 2px solid var(--primary);
143
+ color: var(--primary);
144
+ }
145
+
146
+ .btn-outline:hover {
147
+ background-color: var(--primary);
148
+ color: white;
149
+ }
150
+
151
+ .btn-danger {
152
+ background-color: var(--danger);
153
+ color: white;
154
+ }
155
+
156
+ .btn-danger:hover {
157
+ background-color: #c53030;
158
+ transform: translateY(-2px);
159
+ box-shadow: 0 4px 12px rgba(229, 62, 62, 0.3);
160
+ }
161
+
162
+ .btn:disabled {
163
+ opacity: 0.7;
164
+ cursor: not-allowed;
165
+ transform: none !important;
166
+ box-shadow: none !important;
167
+ }
168
+
169
+ .file-upload {
170
+ display: none;
171
+ }
172
+
173
+ .audio-visualizer {
174
+ width: 100%;
175
+ height: 100px;
176
+ background-color: #f5f3ff;
177
+ border-radius: 8px;
178
+ margin: 1rem 0;
179
+ position: relative;
180
+ overflow: hidden;
181
+ }
182
+
183
+ .visualizer-bars {
184
+ display: flex;
185
+ align-items: flex-end;
186
+ justify-content: space-around;
187
+ height: 100%;
188
+ width: 100%;
189
+ padding: 0.5rem;
190
+ }
191
+
192
+ .bar {
193
+ background-color: var(--primary);
194
+ width: 6px;
195
+ border-radius: 3px;
196
+ transition: height 0.1s ease;
197
+ }
198
+
199
+ .recording-indicator {
200
+ display: flex;
201
+ align-items: center;
202
+ gap: 0.5rem;
203
+ color: var(--danger);
204
+ font-weight: 600;
205
+ margin-bottom: 1rem;
206
+ }
207
+
208
+ .pulse {
209
+ width: 12px;
210
+ height: 12px;
211
+ border-radius: 50%;
212
+ background-color: var(--danger);
213
+ animation: pulse 1.5s infinite;
214
+ }
215
+
216
+ @keyframes pulse {
217
+ 0% {
218
+ transform: scale(0.95);
219
+ box-shadow: 0 0 0 0 rgba(229, 62, 62, 0.7);
220
+ }
221
+ 70% {
222
+ transform: scale(1);
223
+ box-shadow: 0 0 0 10px rgba(229, 62, 62, 0);
224
+ }
225
+ 100% {
226
+ transform: scale(0.95);
227
+ box-shadow: 0 0 0 0 rgba(229, 62, 62, 0);
228
+ }
229
+ }
230
+
231
+ .timer {
232
+ font-family: 'Courier New', monospace;
233
+ font-size: 1.2rem;
234
+ }
235
+
236
+ .transcription-card {
237
+ position: relative;
238
+ }
239
+
240
+ .transcription-content {
241
+ min-height: 200px;
242
+ max-height: 400px;
243
+ overflow-y: auto;
244
+ padding: 1rem;
245
+ background-color: var(--gray);
246
+ border-radius: 8px;
247
+ white-space: pre-wrap;
248
+ line-height: 1.8;
249
+ font-size: 1.1rem;
250
+ }
251
+
252
+ .copy-btn {
253
+ position: absolute;
254
+ top: 1rem;
255
+ right: 1rem;
256
+ background-color: rgba(255, 255, 255, 0.8);
257
+ border-radius: 6px;
258
+ padding: 0.5rem;
259
+ cursor: pointer;
260
+ transition: all 0.2s ease;
261
+ }
262
+
263
+ .copy-btn:hover {
264
+ background-color: white;
265
+ transform: scale(1.05);
266
+ }
267
+
268
+ .copy-btn i {
269
+ color: var(--primary);
270
+ font-size: 1.2rem;
271
+ }
272
+
273
+ .language-selector {
274
+ display: flex;
275
+ flex-direction: column;
276
+ gap: 0.5rem;
277
+ }
278
+
279
+ select {
280
+ padding: 0.8rem;
281
+ border-radius: 8px;
282
+ border: 1px solid #cbd5e0;
283
+ background-color: white;
284
+ font-size: 1rem;
285
+ color: var(--dark);
286
+ cursor: pointer;
287
+ }
288
+
289
+ select:focus {
290
+ outline: none;
291
+ border-color: var(--primary);
292
+ box-shadow: 0 0 0 3px rgba(110, 72, 170, 0.2);
293
+ }
294
+
295
+ .file-info {
296
+ display: flex;
297
+ align-items: center;
298
+ gap: 0.5rem;
299
+ margin-top: 0.5rem;
300
+ color: #4a5568;
301
+ }
302
+
303
+ .file-info i {
304
+ color: var(--primary);
305
+ }
306
+
307
+ .status-message {
308
+ padding: 1rem;
309
+ border-radius: 8px;
310
+ margin-bottom: 1rem;
311
+ display: flex;
312
+ align-items: center;
313
+ gap: 0.8rem;
314
+ }
315
+
316
+ .status-processing {
317
+ background-color: #feebc8;
318
+ color: #b7791f;
319
+ }
320
+
321
+ .status-success {
322
+ background-color: #c6f6d5;
323
+ color: #25855a;
324
+ }
325
+
326
+ .status-error {
327
+ background-color: #fed7d7;
328
+ color: #c53030;
329
+ }
330
+
331
+ .progress-container {
332
+ width: 100%;
333
+ height: 8px;
334
+ background-color: #e2e8f0;
335
+ border-radius: 4px;
336
+ margin-top: 1rem;
337
+ overflow: hidden;
338
+ }
339
+
340
+ .progress-bar {
341
+ height: 100%;
342
+ background: linear-gradient(to right, var(--gradient-start), var(--gradient-end));
343
+ border-radius: 4px;
344
+ width: 0%;
345
+ transition: width 0.3s ease;
346
+ }
347
+
348
+ .settings-toggle {
349
+ display: flex;
350
+ align-items: center;
351
+ gap: 0.5rem;
352
+ color: #4a5568;
353
+ cursor: pointer;
354
+ margin-bottom: 1rem;
355
+ }
356
+
357
+ .settings-toggle i {
358
+ transition: transform 0.3s ease;
359
+ }
360
+
361
+ .settings-container {
362
+ max-height: 0;
363
+ overflow: hidden;
364
+ transition: max-height 0.3s ease;
365
+ background-color: #f8f9fa;
366
+ border-radius: 8px;
367
+ margin-bottom: 1rem;
368
+ }
369
+
370
+ .settings-container.open {
371
+ max-height: 300px;
372
+ padding: 1rem;
373
+ margin-bottom: 1rem;
374
+ }
375
+
376
+ .setting-item {
377
+ display: flex;
378
+ justify-content: space-between;
379
+ align-items: center;
380
+ margin-bottom: 1rem;
381
+ }
382
+
383
+ .checkbox-container {
384
+ display: flex;
385
+ align-items: center;
386
+ gap: 0.5rem;
387
+ }
388
+
389
+ input[type="checkbox"] {
390
+ -webkit-appearance: none;
391
+ appearance: none;
392
+ width: 20px;
393
+ height: 20px;
394
+ border: 2px solid #cbd5e0;
395
+ border-radius: 4px;
396
+ cursor: pointer;
397
+ position: relative;
398
+ transition: all 0.2s ease;
399
+ }
400
+
401
+ input[type="checkbox"]:checked {
402
+ background-color: var(--primary);
403
+ border-color: var(--primary);
404
+ }
405
+
406
+ input[type="checkbox"]:checked::after {
407
+ content: '\f00c';
408
+ font-family: 'Font Awesome 6 Free';
409
+ font-weight: 900;
410
+ position: absolute;
411
+ top: 50%;
412
+ left: 50%;
413
+ transform: translate(-50%, -50%);
414
+ color: white;
415
+ font-size: 12px;
416
+ }
417
+
418
+ .history-item {
419
+ padding: 1rem;
420
+ border-bottom: 1px solid #e2e8f0;
421
+ cursor: pointer;
422
+ transition: background-color 0.2s ease;
423
+ }
424
+
425
+ .history-item:hover {
426
+ background-color: #f7fafc;
427
+ }
428
+
429
+ .history-item-time {
430
+ font-size: 0.9rem;
431
+ color: #718096;
432
+ }
433
+
434
+ .history-item-preview {
435
+ display: -webkit-box;
436
+ -webkit-line-clamp: 2;
437
+ -webkit-box-orient: vertical;
438
+ overflow: hidden;
439
+ text-overflow: ellipsis;
440
+ margin-top: 0.3rem;
441
+ }
442
+ </style>
443
+ </head>
444
+ <body>
445
+ <div class="container">
446
+ <header>
447
+ <div class="logo">
448
+ <i class="fas fa-comment-dots"></i>
449
+ <h1>Whisper AI</h1>
450
+ </div>
451
+ <p class="subtitle">Advanced speech recognition powered by OpenAI's Whisper model. Convert speech to text with remarkable accuracy.</p>
452
+ </header>
453
+
454
+ <div class="card">
455
+ <h2 class="card-title">
456
+ <i class="fas fa-microphone"></i>
457
+ Audio Input
458
+ </h2>
459
+
460
+ <div class="controls">
461
+ <div class="input-group">
462
+ <button id="recordBtn" class="btn btn-primary">
463
+ <i class="fas fa-microphone"></i> Start Recording
464
+ </button>
465
+ <button id="uploadBtn" class="btn btn-outline">
466
+ <i class="fas fa-upload"></i> Upload Audio
467
+ </button>
468
+ <input type="file" id="fileInput" class="file-upload" accept="audio/*,video/*,.wav,.mp3,.ogg,.m4a,.mp4,.webm">
469
+ </div>
470
+
471
+ <div class="language-selector">
472
+ <label for="language">Select Language</label>
473
+ <select id="language">
474
+ <option value="auto">Auto-detect</option>
475
+ <option value="en">English</option>
476
+ <option value="es">Spanish</option>
477
+ <option value="fr">French</option>
478
+ <option value="de">German</option>
479
+ <option value="it">Italian</option>
480
+ <option value="pt">Portuguese</option>
481
+ <option value="ru">Russian</option>
482
+ <option value="ja">Japanese</option>
483
+ <option value="zh">Chinese</option>
484
+ <option value="hi">Hindi</option>
485
+ <option value="ar">Arabic</option>
486
+ </select>
487
+ </div>
488
+
489
+ <div class="audio-visualizer" id="visualizer">
490
+ <div class="visualizer-bars" id="visualizerBars"></div>
491
+ </div>
492
+
493
+ <div id="recordingUI" style="display: none;">
494
+ <div class="recording-indicator">
495
+ <div class="pulse"></div>
496
+ <span>Recording</span>
497
+ <span class="timer" id="timer">00:00</span>
498
+ </div>
499
+ <button id="stopBtn" class="btn btn-danger">
500
+ <i class="fas fa-stop"></i> Stop & Process
501
+ </button>
502
+ </div>
503
+
504
+ <div id="fileInfo" style="display: none;">
505
+ <div class="file-info">
506
+ <i class="fas fa-file-audio"></i>
507
+ <span id="fileName"></span>
508
+ </div>
509
+ <button id="processFileBtn" class="btn btn-primary">
510
+ <i class="fas fa-cog"></i> Process File
511
+ </button>
512
+ </div>
513
+ </div>
514
+ </div>
515
+
516
+ <div class="settings-toggle" id="settingsToggle">
517
+ <i class="fas fa-cog"></i>
518
+ <span>Advanced Settings</span>
519
+ </div>
520
+
521
+ <div class="settings-container" id="settingsContainer">
522
+ <div class="setting-item">
523
+ <span>Transcription Task</span>
524
+ <select id="taskType">
525
+ <option value="transcribe">Transcribe (default)</option>
526
+ <option value="translate">Translate to English</option>
527
+ </select>
528
+ </div>
529
+ <div class="setting-item">
530
+ <span>Temperature</span>
531
+ <input type="range" id="temperature" min="0" max="1" step="0.1" value="0">
532
+ <span id="temperatureValue">0</span>
533
+ </div>
534
+ <div class="checkbox-container">
535
+ <input type="checkbox" id="timestamps" checked>
536
+ <label for="timestamps">Include timestamps</label>
537
+ </div>
538
+ <div class="checkbox-container">
539
+ <input type="checkbox" id="diarization">
540
+ <label for="diarization">Speaker diarization (beta)</label>
541
+ </div>
542
+ </div>
543
+
544
+ <div class="card transcription-card">
545
+ <h2 class="card-title">
546
+ <i class="fas fa-keyboard"></i>
547
+ Transcription
548
+ </h2>
549
+
550
+ <div id="statusMessage" style="display: none;"></div>
551
+
552
+ <div class="progress-container" id="progressContainer" style="display: none;">
553
+ <div class="progress-bar" id="progressBar"></div>
554
+ </div>
555
+
556
+ <div class="transcription-content" id="transcriptionResult">
557
+ <div style="text-align: center; padding: 4rem 0; color: #a0aec0;">
558
+ <i class="fas fa-comment-slash" style="font-size: 3rem; margin-bottom: 1rem;"></i>
559
+ <h3>No transcription yet</h3>
560
+ <p>Record audio or upload a file to get started</p>
561
+ </div>
562
+ </div>
563
+
564
+ <div class="copy-btn" id="copyBtn" title="Copy to clipboard" style="display: none;">
565
+ <i class="fas fa-copy"></i>
566
+ </div>
567
+ </div>
568
+
569
+ <div class="card">
570
+ <h2 class="card-title">
571
+ <i class="fas fa-history"></i>
572
+ Recent Transcripts
573
+ </h2>
574
+
575
+ <div id="historyList">
576
+ <div class="history-item">
577
+ <div class="history-item-time">5 minutes ago</div>
578
+ <div class="history-item-preview">Lorem ipsum dolor sit amet, consectetur adipiscing elit...</div>
579
+ </div>
580
+ <div class="history-item">
581
+ <div class="history-item-time">2 hours ago</div>
582
+ <div class="history-item-preview">Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua...</div>
583
+ </div>
584
+ </div>
585
+ </div>
586
+ </div>
587
+
588
+ <script>
589
+ document.addEventListener('DOMContentLoaded', function() {
590
+ // DOM elements
591
+ const recordBtn = document.getElementById('recordBtn');
592
+ const stopBtn = document.getElementById('stopBtn');
593
+ const uploadBtn = document.getElementById('uploadBtn');
594
+ const fileInput = document.getElementById('fileInput');
595
+ const processFileBtn = document.getElementById('processFileBtn');
596
+ const fileName = document.getElementById('fileName');
597
+ const fileInfo = document.getElementById('fileInfo');
598
+ const recordingUI = document.getElementById('recordingUI');
599
+ const timer = document.getElementById('timer');
600
+ const visualizer = document.getElementById('visualizer');
601
+ const visualizerBars = document.getElementById('visualizerBars');
602
+ const transcriptionResult = document.getElementById('transcriptionResult');
603
+ const statusMessage = document.getElementById('statusMessage');
604
+ const progressContainer = document.getElementById('progressContainer');
605
+ const progressBar = document.getElementById('progressBar');
606
+ const copyBtn = document.getElementById('copyBtn');
607
+ const settingsToggle = document.getElementById('settingsToggle');
608
+ const settingsContainer = document.getElementById('settingsContainer');
609
+ const temperature = document.getElementById('temperature');
610
+ const temperatureValue = document.getElementById('temperatureValue');
611
+
612
+ // Variables
613
+ let mediaRecorder;
614
+ let audioChunks = [];
615
+ let audioContext;
616
+ let analyser;
617
+ let timerInterval;
618
+ let seconds = 0;
619
+ let isRecording = false;
620
+
621
+ // Create visualizer bars
622
+ for (let i = 0; i < 40; i++) {
623
+ const bar = document.createElement('div');
624
+ bar.className = 'bar';
625
+ bar.style.height = '0%';
626
+ visualizerBars.appendChild(bar);
627
+ }
628
+ const bars = document.querySelectorAll('.bar');
629
+
630
+ // Event listeners
631
+ recordBtn.addEventListener('click', startRecording);
632
+ stopBtn.addEventListener('click', stopRecording);
633
+ uploadBtn.addEventListener('click', () => fileInput.click());
634
+ fileInput.addEventListener('change', handleFileUpload);
635
+ processFileBtn.addEventListener('click', processUploadedFile);
636
+ copyBtn.addEventListener('click', copyTranscription);
637
+ settingsToggle.addEventListener('click', toggleSettings);
638
+ temperature.addEventListener('input', updateTemperatureValue);
639
+
640
+ // Initialize settings
641
+ updateTemperatureValue();
642
+
643
+ async function startRecording() {
644
+ try {
645
+ // Hide the recording button and show the stop button
646
+ recordBtn.style.display = 'none';
647
+ recordingUI.style.display = 'block';
648
+
649
+ // Reset timer
650
+ seconds = 0;
651
+ updateTimer();
652
+ timerInterval = setInterval(updateTimer, 1000);
653
+
654
+ // Access the microphone
655
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
656
+ mediaRecorder = new MediaRecorder(stream);
657
+ isRecording = true;
658
+
659
+ // Set up audio context for visualization
660
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
661
+ const source = audioContext.createMediaStreamSource(stream);
662
+ analyser = audioContext.createAnalyser();
663
+ analyser.fftSize = 64;
664
+ source.connect(analyser);
665
+
666
+ // Start visualization
667
+ visualize();
668
+
669
+ // Collect audio data
670
+ mediaRecorder.ondataavailable = event => {
671
+ audioChunks.push(event.data);
672
+ };
673
+
674
+ mediaRecorder.onstop = async () => {
675
+ clearInterval(timerInterval);
676
+
677
+ // Create audio blob
678
+ const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
679
+ audioChunks = [];
680
+
681
+ // Process the audio
682
+ await processAudio(audioBlob, 'recording.wav');
683
+ };
684
+
685
+ mediaRecorder.start(100); // Collect data every 100ms
686
+
687
+ // Show status
688
+ showStatus('Processing your recording...', 'processing');
689
+
690
+ } catch (error) {
691
+ console.error('Error accessing microphone:', error);
692
+ stopRecording();
693
+ showStatus('Error accessing microphone. Please check permissions.', 'error');
694
+ recordBtn.style.display = 'block';
695
+ recordingUI.style.display = 'none';
696
+ }
697
+ }
698
+
699
+ function stopRecording() {
700
+ if (mediaRecorder && isRecording) {
701
+ mediaRecorder.stop();
702
+ isRecording = false;
703
+
704
+ // Stop all tracks in the stream
705
+ mediaRecorder.stream.getTracks().forEach(track => track.stop());
706
+
707
+ // Hide visualizer
708
+ cancelAnimationFrame(visualize);
709
+
710
+ clearInterval(timerInterval);
711
+ }
712
+ }
713
+
714
+ function updateTimer() {
715
+ seconds++;
716
+ const minutes = Math.floor(seconds / 60);
717
+ const remainingSeconds = seconds % 60;
718
+ timer.textContent = `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
719
+ }
720
+
721
+ function visualize() {
722
+ if (!isRecording) return;
723
+
724
+ const bufferLength = analyser.frequencyBinCount;
725
+ const dataArray = new Uint8Array(bufferLength);
726
+ analyser.getByteFrequencyData(dataArray);
727
+
728
+ for (let i = 0; i < bars.length; i++) {
729
+ const barHeight = (dataArray[i % bufferLength] / 255) * 100;
730
+ bars[i].style.height = `${barHeight}%`;
731
+ }
732
+
733
+ requestAnimationFrame(visualize);
734
+ }
735
+
736
+ function handleFileUpload(event) {
737
+ const file = event.target.files[0];
738
+ if (file) {
739
+ fileName.textContent = file.name;
740
+ fileInfo.style.display = 'block';
741
+
742
+ // Reset the file input to allow selecting the same file again
743
+ fileInput.value = '';
744
+ } else {
745
+ fileInfo.style.display = 'none';
746
+ }
747
+ }
748
+
749
+ async function processUploadedFile() {
750
+ const file = fileInput.files[0];
751
+ if (!file) return;
752
+
753
+ showStatus('Processing uploaded file...', 'processing');
754
+ progressContainer.style.display = 'block';
755
+
756
+ // Simulate processing (in a real app, you would upload to your backend)
757
+ simulateProcessing(() => {
758
+ processAudio(file, file.name);
759
+ });
760
+ }
761
+
762
+ async function processAudio(audioBlob, fileName) {
763
+ try {
764
+ // In a real implementation, you would upload the audio to your backend
765
+ // and call the Whisper API there. This is just a mock implementation.
766
+
767
+ // Show progress
768
+ progressBar.style.width = '40%';
769
+
770
+ // Simulate processing delay
771
+ await new Promise(resolve => setTimeout(resolve, 1500));
772
+
773
+ progressBar.style.width = '70%';
774
+
775
+ // Mock results
776
+ setTimeout(() => {
777
+ const mockResults = getMockTranscription(fileName);
778
+ displayResults(mockResults);
779
+ showStatus('Transcription completed successfully!', 'success');
780
+ }, 1000);
781
+
782
+ } catch (error) {
783
+ console.error('Error processing audio:', error);
784
+ showStatus('Error processing audio. Please try again.', 'error');
785
+ } finally {
786
+ // Reset UI
787
+ recordBtn.style.display = 'block';
788
+ recordingUI.style.display = 'none';
789
+ fileInfo.style.display = 'none';
790
+ progressBar.style.width = '100%';
791
+ }
792
+ }
793
+
794
+ function displayResults(results) {
795
+ transcriptionResult.innerHTML = results;
796
+
797
+ // Only show copy button if there's actual content
798
+ const isEmpty = results.includes('No transcription yet');
799
+ copyBtn.style.display = isEmpty ? 'none' : 'block';
800
+ }
801
+
802
+ function showStatus(message, type) {
803
+ statusMessage.style.display = 'block';
804
+ statusMessage.textContent = message;
805
+ statusMessage.className = 'status-message';
806
+
807
+ switch (type) {
808
+ case 'processing':
809
+ statusMessage.classList.add('status-processing');
810
+ progressContainer.style.display = 'block';
811
+ progressBar.style.width = '10%';
812
+ break;
813
+ case 'success':
814
+ statusMessage.classList.add('status-success');
815
+ progressContainer.style.display = 'none';
816
+ break;
817
+ case 'error':
818
+ statusMessage.classList.add('status-error');
819
+ progressContainer.style.display = 'none';
820
+ break;
821
+ }
822
+ }
823
+
824
+ function copyTranscription() {
825
+ const text = transcriptionResult.innerText;
826
+ navigator.clipboard.writeText(text).then(() => {
827
+ // Show feedback
828
+ const originalIcon = copyBtn.innerHTML;
829
+ copyBtn.innerHTML = '<i class="fas fa-check"></i>';
830
+
831
+ setTimeout(() => {
832
+ copyBtn.innerHTML = originalIcon;
833
+ }, 2000);
834
+ }).catch(err => {
835
+ console.error('Failed to copy text: ', err);
836
+ });
837
+ }
838
+
839
+ function toggleSettings() {
840
+ settingsContainer.classList.toggle('open');
841
+ const icon = settingsToggle.querySelector('i');
842
+ icon.style.transform = settingsContainer.classList.contains('open') ? 'rotate(90deg)' : 'rotate(0)';
843
+ }
844
+
845
+ function updateTemperatureValue() {
846
+ temperatureValue.textContent = temperature.value;
847
+ }
848
+
849
+ function simulateProcessing(callback) {
850
+ let progress = 0;
851
+ const interval = setInterval(() => {
852
+ progress += Math.random() * 10;
853
+ if (progress >= 90) {
854
+ progress = 90;
855
+ clearInterval(interval);
856
+ callback();
857
+ }
858
+ progressBar.style.width = `${progress}%`;
859
+ }, 300);
860
+ }
861
+
862
+ function getMockTranscription(filename) {
863
+ const now = new Date();
864
+ const languages = ['English', 'Spanish', 'French', 'German'];
865
+ const randomLanguage = languages[Math.floor(Math.random() * languages.length)];
866
+
867
+ return `Filename: ${filename}\n` +
868
+ `Detected language: ${randomLanguage}\n` +
869
+ `Transcribed at: ${now.toLocaleString()}\n\n` +
870
+ `[00:00:00 --> 00:00:03] Hello there! This is a mock transcription from the Whisper speech recognition model.\n` +
871
+ `[00:00:03 --> 00:00:07] It demonstrates what the real output would look like when using the actual Whisper API.\n` +
872
+ `[00:00:07 --> 00:00:12] In a real implementation, this text would come from OpenAI's Whisper model processing your audio.\n` +
873
+ `[00:00:12 --> 00:00:15] Whisper is great for transcribing meetings, lectures, interviews, and more.\n` +
874
+ `[00:00:15 --> 00:00:18] Thank you for trying out this demo interface!\n`;
875
+ }
876
+ });
877
+ </script>
878
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
879
+ </html>