MagicBullets commited on
Commit
ff13098
·
verified ·
1 Parent(s): 70b3455

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +741 -146
  2. prompts.txt +1 -0
index.html CHANGED
@@ -19,6 +19,16 @@
19
  background: linear-gradient(to right, #3B82F6, #8B5CF6);
20
  height: 100px;
21
  border-radius: 8px;
 
 
 
 
 
 
 
 
 
 
22
  }
23
  .speaker-1 {
24
  border-left: 4px solid #3B82F6;
@@ -60,6 +70,15 @@
60
  .animate-pulse {
61
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
62
  }
 
 
 
 
 
 
 
 
 
63
  </style>
64
  </head>
65
  <body class="bg-gray-50 text-gray-900 font-sans">
@@ -77,16 +96,8 @@
77
  </button>
78
  <div class="mb-6">
79
  <h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-2">Projects</h3>
80
- <ul class="space-y-1">
81
- <li class="px-2 py-1 rounded hover:bg-gray-100 cursor-pointer flex items-center">
82
- <i class="fas fa-file-audio text-gray-400 mr-2"></i> Interview_001
83
- </li>
84
- <li class="px-2 py-1 rounded hover:bg-gray-100 cursor-pointer flex items-center">
85
- <i class="fas fa-file-audio text-gray-400 mr-2"></i> Meeting_2023
86
- </li>
87
- <li class="px-2 py-1 rounded hover:bg-gray-100 cursor-pointer flex items-center">
88
- <i class="fas fa-file-audio text-gray-400 mr-2"></i> Podcast_Episode
89
- </li>
90
  </ul>
91
  </div>
92
  <div>
@@ -125,10 +136,10 @@
125
  <button id="sidebarToggle" class="mr-4 text-gray-500 hover:text-gray-700">
126
  <i class="fas fa-bars"></i>
127
  </button>
128
- <h2 class="text-lg font-semibold">Untitled Project</h2>
129
  </div>
130
  <div class="flex items-center space-x-2">
131
- <button class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-sm flex items-center">
132
  <i class="fas fa-save mr-1"></i> Save
133
  </button>
134
  <div class="relative">
@@ -137,11 +148,11 @@
137
  </button>
138
  <div id="exportDropdown" class="hidden absolute right-0 mt-1 w-48 bg-white rounded-md shadow-lg z-10">
139
  <div class="py-1">
140
- <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Text (.txt)</a>
141
- <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Word (.docx)</a>
142
- <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Subtitles (.srt)</a>
143
- <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">JSON (.json)</a>
144
- <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Audio (.wav)</a>
145
  </div>
146
  </div>
147
  </div>
@@ -154,13 +165,13 @@
154
  <div class="mx-auto w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center text-indigo-600 mb-4">
155
  <i class="fas fa-microphone-alt text-2xl"></i>
156
  </div>
157
- <h3 class="text-lg font-medium text-gray-900 mb-2">Drag & drop your WAV files here</h3>
158
  <p class="text-gray-500 mb-4">or</p>
159
  <label for="fileInput" class="cursor-pointer inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none">
160
  <i class="fas fa-folder-open mr-2"></i> Browse Files
161
  </label>
162
- <input id="fileInput" type="file" accept=".wav" multiple class="hidden">
163
- <p class="text-sm text-gray-500 mt-4">Supports batch processing of multiple files</p>
164
  </div>
165
 
166
  <!-- Processing Section (hidden by default) -->
@@ -168,20 +179,21 @@
168
  <div class="bg-white rounded-lg shadow-sm p-6 mb-6">
169
  <div class="flex items-center justify-between mb-4">
170
  <h3 class="text-lg font-medium">Processing Files</h3>
171
- <span class="text-sm text-gray-500">1 of 3 files completed</span>
172
  </div>
 
173
  <div class="space-y-4">
174
  <!-- Current File Progress -->
175
  <div>
176
  <div class="flex items-center justify-between mb-1">
177
- <span class="text-sm font-medium">interview_001.wav</span>
178
- <span class="text-xs text-gray-500">45%</span>
179
  </div>
180
  <div class="w-full bg-gray-200 rounded-full h-2">
181
- <div class="bg-indigo-600 h-2 rounded-full" style="width: 45%"></div>
182
  </div>
183
  <div class="mt-2 text-xs text-gray-500 flex justify-between">
184
- <span>Speaker diarization</span>
185
  <span>Noise reduction</span>
186
  <span>Transcription</span>
187
  <span>Tagging</span>
@@ -189,21 +201,8 @@
189
  </div>
190
 
191
  <!-- Queued Files -->
192
- <div class="border-t border-gray-200 pt-4">
193
- <div class="flex items-center justify-between text-sm">
194
- <div class="flex items-center">
195
- <i class="fas fa-clock text-gray-400 mr-2"></i>
196
- <span>meeting_2023.wav</span>
197
- </div>
198
- <span class="text-gray-500">Queued</span>
199
- </div>
200
- <div class="flex items-center justify-between text-sm mt-2">
201
- <div class="flex items-center">
202
- <i class="fas fa-clock text-gray-400 mr-2"></i>
203
- <span>podcast_episode.wav</span>
204
- </div>
205
- <span class="text-gray-500">Queued</span>
206
- </div>
207
  </div>
208
  </div>
209
  </div>
@@ -213,10 +212,10 @@
213
  <div class="flex items-center justify-between mb-4">
214
  <h3 class="text-lg font-medium">Transcription Preview</h3>
215
  <div class="flex space-x-2">
216
- <button class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-sm flex items-center">
217
  <i class="fas fa-headphones mr-1"></i> Play
218
  </button>
219
- <button class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-sm flex items-center">
220
  <i class="fas fa-edit mr-1"></i> Edit
221
  </button>
222
  </div>
@@ -225,22 +224,25 @@
225
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
226
  <!-- Waveform Visualization -->
227
  <div>
228
- <div class="waveform mb-4"></div>
229
- <div class="flex items-center justify-between mb-2">
 
 
 
230
  <div class="flex items-center space-x-2">
231
- <button class="p-2 rounded-full bg-gray-100 hover:bg-gray-200">
232
  <i class="fas fa-play text-gray-700"></i>
233
  </button>
234
- <span class="text-sm text-gray-500">00:45 / 02:30</span>
235
  </div>
236
  <div class="flex items-center space-x-1">
237
- <button class="p-2 rounded-full bg-gray-100 hover:bg-gray-200" title="Noise Reduction">
238
  <i class="fas fa-volume-mute text-gray-700"></i>
239
  </button>
240
- <button class="p-2 rounded-full bg-gray-100 hover:bg-gray-200" title="Diarization Settings">
241
  <i class="fas fa-users text-gray-700"></i>
242
  </button>
243
- <button class="p-2 rounded-full bg-gray-100 hover:bg-gray-200" title="Emotion Detection">
244
  <i class="fas fa-smile text-gray-700"></i>
245
  </button>
246
  </div>
@@ -248,44 +250,11 @@
248
  </div>
249
 
250
  <!-- Transcription Text -->
251
- <div class="bg-gray-50 p-4 rounded-md max-h-96 overflow-y-auto">
252
  <div class="space-y-4">
253
- <div class="speaker-1 pl-3">
254
- <div class="flex items-center mb-1">
255
- <span class="font-medium text-indigo-600">Speaker 1</span>
256
- <button class="ml-2 text-gray-400 hover:text-gray-600">
257
- <i class="fas fa-pencil-alt text-xs"></i>
258
- </button>
259
- </div>
260
- <p class="text-gray-800">
261
- Hello everyone, welcome to today's meeting. <span class="tag-emphasis">Really</span> glad you could all make it. <span class="tag-pause">[pause]</span> We have a lot to cover today.
262
- </p>
263
- </div>
264
- <div class="speaker-2 pl-3">
265
- <div class="flex items-center mb-1">
266
- <span class="font-medium text-green-600">Speaker 2</span>
267
- <button class="ml-2 text-gray-400 hover:text-gray-600">
268
- <i class="fas fa-pencil-alt text-xs"></i>
269
- </button>
270
- </div>
271
- <p class="text-gray-800">
272
- Thanks for having us! <span class="tag-laugh">[laughs]</span> I'm excited to discuss the new project updates. <span class="tag-emotion">[emotional tone: happy]</span>
273
- </p>
274
- </div>
275
- <div class="speaker-1 pl-3">
276
- <div class="flex items-center mb-1">
277
- <span class="font-medium text-indigo-600">Speaker 1</span>
278
- <button class="ml-2 text-gray-400 hover:text-gray-600">
279
- <i class="fas fa-pencil-alt text-xs"></i>
280
- </button>
281
- </div>
282
- <p class="text-gray-800">
283
- Let's start with the quarterly results. <span class="tag-emphasis">Revenue</span> is up by 15% compared to last quarter, which is <span class="tag-emotion">[emotional tone: excited]</span> fantastic news!
284
- </p>
285
- </div>
286
  <div class="animate-pulse flex items-center text-gray-500">
287
  <i class="fas fa-spinner fa-spin mr-2"></i>
288
- <span>Transcribing next segment...</span>
289
  </div>
290
  </div>
291
  </div>
@@ -300,7 +269,7 @@
300
  <div class="flex items-center justify-between mb-2">
301
  <h4 class="font-medium">Noise Reduction</h4>
302
  <label class="relative inline-flex items-center cursor-pointer">
303
- <input type="checkbox" value="" class="sr-only peer" checked>
304
  <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
305
  </label>
306
  </div>
@@ -310,27 +279,27 @@
310
  <div class="mb-2">
311
  <h4 class="font-medium">Transcription Model</h4>
312
  </div>
313
- <select class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm">
314
- <option>Whisper Small (Fastest)</option>
315
- <option selected>Whisper Medium (Balanced)</option>
316
- <option>Whisper Large (Most Accurate)</option>
317
  </select>
318
  </div>
319
  <div class="border border-gray-200 rounded-md p-4">
320
  <div class="mb-2">
321
  <h4 class="font-medium">Speaker Diarization</h4>
322
  </div>
323
- <select class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm">
324
- <option>Basic (2-3 speakers)</option>
325
- <option selected>Advanced (up to 5 speakers)</option>
326
- <option>High Precision (1-2 speakers)</option>
327
  </select>
328
  </div>
329
  <div class="border border-gray-200 rounded-md p-4">
330
  <div class="flex items-center justify-between mb-2">
331
  <h4 class="font-medium">Emotion Detection</h4>
332
  <label class="relative inline-flex items-center cursor-pointer">
333
- <input type="checkbox" value="" class="sr-only peer" checked>
334
  <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
335
  </label>
336
  </div>
@@ -344,84 +313,710 @@
344
  </div>
345
 
346
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  // Toggle sidebar
348
- document.getElementById('sidebarToggle').addEventListener('click', function() {
349
  document.querySelector('.sidebar').classList.toggle('hidden');
350
- });
351
 
352
- // Export dropdown
353
- document.getElementById('exportBtn').addEventListener('click', function(e) {
354
  e.stopPropagation();
355
- document.getElementById('exportDropdown').classList.toggle('hidden');
356
- });
357
-
358
- // Close dropdown when clicking elsewhere
359
- document.addEventListener('click', function() {
360
- document.getElementById('exportDropdown').classList.add('hidden');
361
- });
362
-
363
- // Drag and drop functionality
364
- const dropzone = document.getElementById('dropzone');
365
- const fileInput = document.getElementById('fileInput');
366
- const processingSection = document.getElementById('processingSection');
367
 
368
- ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
369
- dropzone.addEventListener(eventName, preventDefaults, false);
370
- });
 
371
 
 
372
  function preventDefaults(e) {
373
  e.preventDefault();
374
  e.stopPropagation();
375
  }
376
 
377
- ['dragenter', 'dragover'].forEach(eventName => {
378
- dropzone.addEventListener(eventName, highlight, false);
379
- });
380
-
381
- ['dragleave', 'drop'].forEach(eventName => {
382
- dropzone.addEventListener(eventName, unhighlight, false);
383
- });
384
-
385
- function highlight() {
386
- dropzone.classList.add('active');
387
  }
388
 
389
- function unhighlight() {
390
- dropzone.classList.remove('active');
 
391
  }
392
 
393
- dropzone.addEventListener('drop', handleDrop, false);
394
- fileInput.addEventListener('change', handleFiles);
395
-
396
  function handleDrop(e) {
397
  const dt = e.dataTransfer;
398
  const files = dt.files;
399
- handleFiles({ target: { files } });
400
  }
401
 
402
- function handleFiles(e) {
 
403
  const files = e.target.files;
404
- if (files.length > 0) {
405
- // Show processing section
406
- dropzone.classList.add('hidden');
407
- processingSection.classList.remove('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
 
409
- // Here you would normally process the files
410
- console.log('Files to process:', files);
 
 
 
 
 
 
 
 
 
 
 
 
411
  }
 
 
412
  }
413
 
414
- // Click on dropzone triggers file input
415
- dropzone.addEventListener('click', () => {
416
- fileInput.click();
417
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
419
- // New project button
420
- document.getElementById('newProjectBtn').addEventListener('click', function() {
421
- dropzone.classList.remove('hidden');
422
- processingSection.classList.add('hidden');
423
- fileInput.value = ''; // Reset file input
424
- });
425
  </script>
426
  <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 <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MagicBullets/tts" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
427
  </html>
 
19
  background: linear-gradient(to right, #3B82F6, #8B5CF6);
20
  height: 100px;
21
  border-radius: 8px;
22
+ position: relative;
23
+ overflow: hidden;
24
+ }
25
+ .waveform-bar {
26
+ position: absolute;
27
+ bottom: 0;
28
+ width: 4px;
29
+ background-color: white;
30
+ opacity: 0.7;
31
+ border-radius: 2px;
32
  }
33
  .speaker-1 {
34
  border-left: 4px solid #3B82F6;
 
70
  .animate-pulse {
71
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
72
  }
73
+ .progress-indicator {
74
+ width: 0;
75
+ height: 2px;
76
+ background-color: #3B82F6;
77
+ transition: width 0.1s linear;
78
+ }
79
+ #audioPlayer {
80
+ width: 100%;
81
+ }
82
  </style>
83
  </head>
84
  <body class="bg-gray-50 text-gray-900 font-sans">
 
96
  </button>
97
  <div class="mb-6">
98
  <h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-2">Projects</h3>
99
+ <ul id="projectList" class="space-y-1">
100
+ <!-- Projects will be added here dynamically -->
 
 
 
 
 
 
 
 
101
  </ul>
102
  </div>
103
  <div>
 
136
  <button id="sidebarToggle" class="mr-4 text-gray-500 hover:text-gray-700">
137
  <i class="fas fa-bars"></i>
138
  </button>
139
+ <h2 id="projectTitle" class="text-lg font-semibold">Untitled Project</h2>
140
  </div>
141
  <div class="flex items-center space-x-2">
142
+ <button id="saveBtn" class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-sm flex items-center">
143
  <i class="fas fa-save mr-1"></i> Save
144
  </button>
145
  <div class="relative">
 
148
  </button>
149
  <div id="exportDropdown" class="hidden absolute right-0 mt-1 w-48 bg-white rounded-md shadow-lg z-10">
150
  <div class="py-1">
151
+ <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" id="exportTxt">Text (.txt)</a>
152
+ <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" id="exportDocx">Word (.docx)</a>
153
+ <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" id="exportSrt">Subtitles (.srt)</a>
154
+ <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" id="exportJson">JSON (.json)</a>
155
+ <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" id="exportAudio">Audio (.wav)</a>
156
  </div>
157
  </div>
158
  </div>
 
165
  <div class="mx-auto w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center text-indigo-600 mb-4">
166
  <i class="fas fa-microphone-alt text-2xl"></i>
167
  </div>
168
+ <h3 class="text-lg font-medium text-gray-900 mb-2">Drag & drop your audio files here</h3>
169
  <p class="text-gray-500 mb-4">or</p>
170
  <label for="fileInput" class="cursor-pointer inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none">
171
  <i class="fas fa-folder-open mr-2"></i> Browse Files
172
  </label>
173
+ <input id="fileInput" type="file" accept="audio/*" class="hidden">
174
+ <p class="text-sm text-gray-500 mt-4">Supports WAV, MP3, and other common audio formats</p>
175
  </div>
176
 
177
  <!-- Processing Section (hidden by default) -->
 
179
  <div class="bg-white rounded-lg shadow-sm p-6 mb-6">
180
  <div class="flex items-center justify-between mb-4">
181
  <h3 class="text-lg font-medium">Processing Files</h3>
182
+ <span id="progressStatus" class="text-sm text-gray-500">0% completed</span>
183
  </div>
184
+ <div class="progress-indicator mb-2"></div>
185
  <div class="space-y-4">
186
  <!-- Current File Progress -->
187
  <div>
188
  <div class="flex items-center justify-between mb-1">
189
+ <span id="currentFileName" class="text-sm font-medium">No file selected</span>
190
+ <span id="fileProgress" class="text-xs text-gray-500">0%</span>
191
  </div>
192
  <div class="w-full bg-gray-200 rounded-full h-2">
193
+ <div id="fileProgressBar" class="bg-indigo-600 h-2 rounded-full" style="width: 0%"></div>
194
  </div>
195
  <div class="mt-2 text-xs text-gray-500 flex justify-between">
196
+ <span>Audio analysis</span>
197
  <span>Noise reduction</span>
198
  <span>Transcription</span>
199
  <span>Tagging</span>
 
201
  </div>
202
 
203
  <!-- Queued Files -->
204
+ <div id="queuedFiles" class="border-t border-gray-200 pt-4">
205
+ <!-- Files will be added here dynamically -->
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  </div>
207
  </div>
208
  </div>
 
212
  <div class="flex items-center justify-between mb-4">
213
  <h3 class="text-lg font-medium">Transcription Preview</h3>
214
  <div class="flex space-x-2">
215
+ <button id="playBtn" class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-sm flex items-center">
216
  <i class="fas fa-headphones mr-1"></i> Play
217
  </button>
218
+ <button id="editBtn" class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-sm flex items-center">
219
  <i class="fas fa-edit mr-1"></i> Edit
220
  </button>
221
  </div>
 
224
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
225
  <!-- Waveform Visualization -->
226
  <div>
227
+ <div class="waveform mb-4" id="waveform">
228
+ <!-- Waveform bars will be added here dynamically -->
229
+ </div>
230
+ <audio id="audioPlayer" controls></audio>
231
+ <div class="flex items-center justify-between mb-2 mt-2">
232
  <div class="flex items-center space-x-2">
233
+ <button id="playPauseBtn" class="p-2 rounded-full bg-gray-100 hover:bg-gray-200">
234
  <i class="fas fa-play text-gray-700"></i>
235
  </button>
236
+ <span id="timeDisplay" class="text-sm text-gray-500">00:00 / 00:00</span>
237
  </div>
238
  <div class="flex items-center space-x-1">
239
+ <button id="noiseReductionBtn" class="p-2 rounded-full bg-gray-100 hover:bg-gray-200" title="Noise Reduction">
240
  <i class="fas fa-volume-mute text-gray-700"></i>
241
  </button>
242
+ <button id="diarizationBtn" class="p-2 rounded-full bg-gray-100 hover:bg-gray-200" title="Diarization Settings">
243
  <i class="fas fa-users text-gray-700"></i>
244
  </button>
245
+ <button id="emotionBtn" class="p-2 rounded-full bg-gray-100 hover:bg-gray-200" title="Emotion Detection">
246
  <i class="fas fa-smile text-gray-700"></i>
247
  </button>
248
  </div>
 
250
  </div>
251
 
252
  <!-- Transcription Text -->
253
+ <div id="transcriptionText" class="bg-gray-50 p-4 rounded-md max-h-96 overflow-y-auto">
254
  <div class="space-y-4">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  <div class="animate-pulse flex items-center text-gray-500">
256
  <i class="fas fa-spinner fa-spin mr-2"></i>
257
+ <span>Waiting for audio to process...</span>
258
  </div>
259
  </div>
260
  </div>
 
269
  <div class="flex items-center justify-between mb-2">
270
  <h4 class="font-medium">Noise Reduction</h4>
271
  <label class="relative inline-flex items-center cursor-pointer">
272
+ <input type="checkbox" id="noiseReductionToggle" class="sr-only peer" checked>
273
  <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
274
  </label>
275
  </div>
 
279
  <div class="mb-2">
280
  <h4 class="font-medium">Transcription Model</h4>
281
  </div>
282
+ <select id="modelSelect" class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm">
283
+ <option value="fast">Whisper Small (Fastest)</option>
284
+ <option value="balanced" selected>Whisper Medium (Balanced)</option>
285
+ <option value="accurate">Whisper Large (Most Accurate)</option>
286
  </select>
287
  </div>
288
  <div class="border border-gray-200 rounded-md p-4">
289
  <div class="mb-2">
290
  <h4 class="font-medium">Speaker Diarization</h4>
291
  </div>
292
+ <select id="diarizationSelect" class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm">
293
+ <option value="basic">Basic (2-3 speakers)</option>
294
+ <option value="advanced" selected>Advanced (up to 5 speakers)</option>
295
+ <option value="precision">High Precision (1-2 speakers)</option>
296
  </select>
297
  </div>
298
  <div class="border border-gray-200 rounded-md p-4">
299
  <div class="flex items-center justify-between mb-2">
300
  <h4 class="font-medium">Emotion Detection</h4>
301
  <label class="relative inline-flex items-center cursor-pointer">
302
+ <input type="checkbox" id="emotionToggle" class="sr-only peer" checked>
303
  <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
304
  </label>
305
  </div>
 
313
  </div>
314
 
315
  <script>
316
+ // App state
317
+ const state = {
318
+ currentProject: {
319
+ id: Date.now(),
320
+ name: 'Untitled Project',
321
+ audioFile: null,
322
+ transcription: [],
323
+ settings: {
324
+ noiseReduction: true,
325
+ model: 'balanced',
326
+ diarization: 'advanced',
327
+ emotionDetection: true
328
+ },
329
+ processed: false
330
+ },
331
+ projects: [],
332
+ isProcessing: false,
333
+ currentAudioTime: 0,
334
+ isPlaying: false,
335
+ recognition: null
336
+ };
337
+
338
+ // DOM elements
339
+ const elements = {
340
+ dropzone: document.getElementById('dropzone'),
341
+ fileInput: document.getElementById('fileInput'),
342
+ processingSection: document.getElementById('processingSection'),
343
+ sidebarToggle: document.getElementById('sidebarToggle'),
344
+ exportBtn: document.getElementById('exportBtn'),
345
+ exportDropdown: document.getElementById('exportDropdown'),
346
+ newProjectBtn: document.getElementById('newProjectBtn'),
347
+ projectTitle: document.getElementById('projectTitle'),
348
+ projectList: document.getElementById('projectList'),
349
+ progressStatus: document.getElementById('progressStatus'),
350
+ currentFileName: document.getElementById('currentFileName'),
351
+ fileProgress: document.getElementById('fileProgress'),
352
+ fileProgressBar: document.getElementById('fileProgressBar'),
353
+ queuedFiles: document.getElementById('queuedFiles'),
354
+ playBtn: document.getElementById('playBtn'),
355
+ editBtn: document.getElementById('editBtn'),
356
+ waveform: document.getElementById('waveform'),
357
+ audioPlayer: document.getElementById('audioPlayer'),
358
+ playPauseBtn: document.getElementById('playPauseBtn'),
359
+ timeDisplay: document.getElementById('timeDisplay'),
360
+ noiseReductionBtn: document.getElementById('noiseReductionBtn'),
361
+ diarizationBtn: document.getElementById('diarizationBtn'),
362
+ emotionBtn: document.getElementById('emotionBtn'),
363
+ transcriptionText: document.getElementById('transcriptionText'),
364
+ noiseReductionToggle: document.getElementById('noiseReductionToggle'),
365
+ modelSelect: document.getElementById('modelSelect'),
366
+ diarizationSelect: document.getElementById('diarizationSelect'),
367
+ emotionToggle: document.getElementById('emotionToggle'),
368
+ saveBtn: document.getElementById('saveBtn'),
369
+ exportTxt: document.getElementById('exportTxt'),
370
+ exportDocx: document.getElementById('exportDocx'),
371
+ exportSrt: document.getElementById('exportSrt'),
372
+ exportJson: document.getElementById('exportJson'),
373
+ exportAudio: document.getElementById('exportAudio')
374
+ };
375
+
376
+ // Initialize the app
377
+ function init() {
378
+ setupEventListeners();
379
+ updateUI();
380
+ checkSpeechRecognitionSupport();
381
+ loadProjects();
382
+ }
383
+
384
+ // Check if speech recognition is supported
385
+ function checkSpeechRecognitionSupport() {
386
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
387
+ if (!SpeechRecognition) {
388
+ alert('Speech recognition is not supported in your browser. This app will not be able to transcribe audio.');
389
+ return false;
390
+ }
391
+ state.recognition = new SpeechRecognition();
392
+ state.recognition.continuous = true;
393
+ state.recognition.interimResults = true;
394
+ state.recognition.onresult = handleRecognitionResult;
395
+ state.recognition.onerror = handleRecognitionError;
396
+ state.recognition.onend = handleRecognitionEnd;
397
+ return true;
398
+ }
399
+
400
+ // Set up event listeners
401
+ function setupEventListeners() {
402
+ // Sidebar toggle
403
+ elements.sidebarToggle.addEventListener('click', toggleSidebar);
404
+
405
+ // Export dropdown
406
+ elements.exportBtn.addEventListener('click', toggleExportDropdown);
407
+ document.addEventListener('click', closeExportDropdown);
408
+
409
+ // Drag and drop
410
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
411
+ elements.dropzone.addEventListener(eventName, preventDefaults, false);
412
+ });
413
+
414
+ ['dragenter', 'dragover'].forEach(eventName => {
415
+ elements.dropzone.addEventListener(eventName, highlightDropzone, false);
416
+ });
417
+
418
+ ['dragleave', 'drop'].forEach(eventName => {
419
+ elements.dropzone.addEventListener(eventName, unhighlightDropzone, false);
420
+ });
421
+
422
+ elements.dropzone.addEventListener('drop', handleDrop, false);
423
+ elements.fileInput.addEventListener('change', handleFileSelect);
424
+
425
+ // Click on dropzone triggers file input
426
+ elements.dropzone.addEventListener('click', () => {
427
+ elements.fileInput.click();
428
+ });
429
+
430
+ // New project button
431
+ elements.newProjectBtn.addEventListener('click', createNewProject);
432
+
433
+ // Audio player controls
434
+ elements.playPauseBtn.addEventListener('click', togglePlayPause);
435
+ elements.audioPlayer.addEventListener('timeupdate', updateTimeDisplay);
436
+ elements.audioPlayer.addEventListener('play', () => {
437
+ state.isPlaying = true;
438
+ updatePlayPauseButton();
439
+ });
440
+ elements.audioPlayer.addEventListener('pause', () => {
441
+ state.isPlaying = false;
442
+ updatePlayPauseButton();
443
+ });
444
+ elements.audioPlayer.addEventListener('ended', () => {
445
+ state.isPlaying = false;
446
+ updatePlayPauseButton();
447
+ });
448
+
449
+ // Processing settings
450
+ elements.noiseReductionToggle.addEventListener('change', updateSettings);
451
+ elements.modelSelect.addEventListener('change', updateSettings);
452
+ elements.diarizationSelect.addEventListener('change', updateSettings);
453
+ elements.emotionToggle.addEventListener('change', updateSettings);
454
+
455
+ // Save button
456
+ elements.saveBtn.addEventListener('click', saveProject);
457
+
458
+ // Export buttons
459
+ elements.exportTxt.addEventListener('click', exportAsTxt);
460
+ elements.exportDocx.addEventListener('click', exportAsDocx);
461
+ elements.exportSrt.addEventListener('click', exportAsSrt);
462
+ elements.exportJson.addEventListener('click', exportAsJson);
463
+ elements.exportAudio.addEventListener('click', exportAudio);
464
+ }
465
+
466
  // Toggle sidebar
467
+ function toggleSidebar() {
468
  document.querySelector('.sidebar').classList.toggle('hidden');
469
+ }
470
 
471
+ // Toggle export dropdown
472
+ function toggleExportDropdown(e) {
473
  e.stopPropagation();
474
+ elements.exportDropdown.classList.toggle('hidden');
475
+ }
 
 
 
 
 
 
 
 
 
 
476
 
477
+ // Close export dropdown
478
+ function closeExportDropdown() {
479
+ elements.exportDropdown.classList.add('hidden');
480
+ }
481
 
482
+ // Prevent default behavior for drag and drop
483
  function preventDefaults(e) {
484
  e.preventDefault();
485
  e.stopPropagation();
486
  }
487
 
488
+ // Highlight dropzone
489
+ function highlightDropzone() {
490
+ elements.dropzone.classList.add('active');
 
 
 
 
 
 
 
491
  }
492
 
493
+ // Unhighlight dropzone
494
+ function unhighlightDropzone() {
495
+ elements.dropzone.classList.remove('active');
496
  }
497
 
498
+ // Handle dropped files
 
 
499
  function handleDrop(e) {
500
  const dt = e.dataTransfer;
501
  const files = dt.files;
502
+ handleFiles(files);
503
  }
504
 
505
+ // Handle selected files
506
+ function handleFileSelect(e) {
507
  const files = e.target.files;
508
+ handleFiles(files);
509
+ }
510
+
511
+ // Process files
512
+ function handleFiles(files) {
513
+ if (files.length === 0) return;
514
+
515
+ const audioFile = files[0];
516
+ state.currentProject.audioFile = audioFile;
517
+ state.currentProject.name = audioFile.name.replace(/\.[^/.]+$/, ""); // Remove extension
518
+ updateUI();
519
+
520
+ // Show processing section
521
+ elements.dropzone.classList.add('hidden');
522
+ elements.processingSection.classList.remove('hidden');
523
+
524
+ // Start processing
525
+ processAudioFile(audioFile);
526
+ }
527
+
528
+ // Process audio file
529
+ function processAudioFile(file) {
530
+ state.isProcessing = true;
531
+ elements.currentFileName.textContent = file.name;
532
+ elements.fileProgress.textContent = '0%';
533
+ elements.fileProgressBar.style.width = '0%';
534
+ elements.progressStatus.textContent = 'Starting processing...';
535
+
536
+ // Create audio player source
537
+ const audioURL = URL.createObjectURL(file);
538
+ elements.audioPlayer.src = audioURL;
539
+
540
+ // Generate waveform visualization
541
+ generateWaveform();
542
+
543
+ // Simulate processing (in a real app, this would be actual audio processing)
544
+ simulateProcessing();
545
+
546
+ // Start speech recognition
547
+ startSpeechRecognition();
548
+ }
549
+
550
+ // Simulate processing with progress updates
551
+ function simulateProcessing() {
552
+ let progress = 0;
553
+ const interval = setInterval(() => {
554
+ progress += Math.random() * 5;
555
+ if (progress >= 100) {
556
+ progress = 100;
557
+ clearInterval(interval);
558
+ state.isProcessing = false;
559
+ state.currentProject.processed = true;
560
+ elements.progressStatus.textContent = 'Processing complete!';
561
+ updateUI();
562
+ }
563
+ updateProgress(progress);
564
+ }, 300);
565
+ }
566
+
567
+ // Update progress indicators
568
+ function updateProgress(progress) {
569
+ elements.fileProgress.textContent = `${Math.round(progress)}%`;
570
+ elements.fileProgressBar.style.width = `${progress}%`;
571
+ elements.progressStatus.textContent = `${Math.round(progress)}% completed`;
572
+ }
573
+
574
+ // Generate waveform visualization
575
+ function generateWaveform() {
576
+ elements.waveform.innerHTML = '';
577
+ const barCount = 100;
578
+ for (let i = 0; i < barCount; i++) {
579
+ const bar = document.createElement('div');
580
+ bar.className = 'waveform-bar';
581
+ bar.style.left = `${(i / barCount) * 100}%`;
582
+ bar.style.height = `${Math.random() * 80 + 20}%`;
583
+ elements.waveform.appendChild(bar);
584
+ }
585
+ }
586
+
587
+ // Start speech recognition
588
+ function startSpeechRecognition() {
589
+ if (!state.recognition) return;
590
+
591
+ // In a real app, we would process the audio file with the Web Speech API
592
+ // For this demo, we'll simulate transcription with sample data
593
+ setTimeout(() => {
594
+ const sampleTranscription = [
595
+ {
596
+ speaker: 1,
597
+ text: "Hello everyone, welcome to today's meeting. Really glad you could all make it. [pause] We have a lot to cover today.",
598
+ time: 0,
599
+ tags: [
600
+ { type: 'emphasis', text: 'Really', start: 28, end: 34 },
601
+ { type: 'pause', text: '[pause]', start: 52, end: 59 }
602
+ ]
603
+ },
604
+ {
605
+ speaker: 2,
606
+ text: "Thanks for having us! [laughs] I'm excited to discuss the new project updates. [emotional tone: happy]",
607
+ time: 6,
608
+ tags: [
609
+ { type: 'laugh', text: '[laughs]', start: 19, end: 27 },
610
+ { type: 'emotion', text: '[emotional tone: happy]', start: 64, end: 86 }
611
+ ]
612
+ },
613
+ {
614
+ speaker: 1,
615
+ text: "Let's start with the quarterly results. Revenue is up by 15% compared to last quarter, which is [emotional tone: excited] fantastic news!",
616
+ time: 12,
617
+ tags: [
618
+ { type: 'emphasis', text: 'Revenue', start: 32, end: 39 },
619
+ { type: 'emotion', text: '[emotional tone: excited]', start: 84, end: 107 }
620
+ ]
621
+ }
622
+ ];
623
+
624
+ state.currentProject.transcription = sampleTranscription;
625
+ renderTranscription();
626
+ }, 2000);
627
+ }
628
+
629
+ // Handle recognition result (not fully implemented in this demo)
630
+ function handleRecognitionResult(event) {
631
+ // In a real app, this would process the recognition results
632
+ }
633
+
634
+ // Handle recognition error
635
+ function handleRecognitionError(event) {
636
+ console.error('Speech recognition error', event.error);
637
+ }
638
+
639
+ // Handle recognition end
640
+ function handleRecognitionEnd() {
641
+ if (state.isProcessing) {
642
+ state.recognition.start(); // Restart if still processing
643
+ }
644
+ }
645
+
646
+ // Render transcription
647
+ function renderTranscription() {
648
+ elements.transcriptionText.innerHTML = '';
649
+
650
+ if (state.currentProject.transcription.length === 0) {
651
+ elements.transcriptionText.innerHTML = `
652
+ <div class="text-gray-500 text-center py-4">
653
+ No transcription available yet.
654
+ </div>
655
+ `;
656
+ return;
657
+ }
658
+
659
+ const container = document.createElement('div');
660
+ container.className = 'space-y-4';
661
+
662
+ state.currentProject.transcription.forEach((segment, index) => {
663
+ const segmentDiv = document.createElement('div');
664
+ segmentDiv.className = `speaker-${segment.speaker} pl-3`;
665
+
666
+ const speakerDiv = document.createElement('div');
667
+ speakerDiv.className = 'flex items-center mb-1';
668
+
669
+ const speakerColor = segment.speaker === 1 ? 'indigo' : segment.speaker === 2 ? 'green' : 'yellow';
670
+ speakerDiv.innerHTML = `
671
+ <span class="font-medium text-${speakerColor}-600">Speaker ${segment.speaker}</span>
672
+ <button class="ml-2 text-gray-400 hover:text-gray-600">
673
+ <i class="fas fa-pencil-alt text-xs"></i>
674
+ </button>
675
+ `;
676
+
677
+ const textDiv = document.createElement('p');
678
+ textDiv.className = 'text-gray-800';
679
+
680
+ // Process text with tags
681
+ let processedText = segment.text;
682
+ if (segment.tags && segment.tags.length > 0) {
683
+ // Sort tags by start position in reverse order to avoid offset issues when inserting HTML
684
+ const sortedTags = [...segment.tags].sort((a, b) => b.start - a.start);
685
+
686
+ sortedTags.forEach(tag => {
687
+ const before = processedText.substring(0, tag.start);
688
+ const after = processedText.substring(tag.end);
689
+ const tagClass =
690
+ tag.type === 'emphasis' ? 'tag-emphasis' :
691
+ tag.type === 'pause' ? 'tag-pause' :
692
+ tag.type === 'emotion' ? 'tag-emotion' :
693
+ tag.type === 'laugh' ? 'tag-laugh' : '';
694
+
695
+ processedText = `${before}<span class="${tagClass}">${tag.text}</span>${after}`;
696
+ });
697
+ }
698
+
699
+ textDiv.innerHTML = processedText;
700
 
701
+ segmentDiv.appendChild(speakerDiv);
702
+ segmentDiv.appendChild(textDiv);
703
+ container.appendChild(segmentDiv);
704
+ });
705
+
706
+ elements.transcriptionText.appendChild(container);
707
+ }
708
+
709
+ // Toggle play/pause
710
+ function togglePlayPause() {
711
+ if (state.isPlaying) {
712
+ elements.audioPlayer.pause();
713
+ } else {
714
+ elements.audioPlayer.play();
715
  }
716
+ state.isPlaying = !state.isPlaying;
717
+ updatePlayPauseButton();
718
  }
719
 
720
+ // Update play/pause button
721
+ function updatePlayPauseButton() {
722
+ const icon = elements.playPauseBtn.querySelector('i');
723
+ if (state.isPlaying) {
724
+ icon.classList.remove('fa-play');
725
+ icon.classList.add('fa-pause');
726
+ } else {
727
+ icon.classList.remove('fa-pause');
728
+ icon.classList.add('fa-play');
729
+ }
730
+ }
731
+
732
+ // Update time display
733
+ function updateTimeDisplay() {
734
+ const currentTime = elements.audioPlayer.currentTime;
735
+ const duration = elements.audioPlayer.duration || 1;
736
+ state.currentAudioTime = currentTime;
737
+
738
+ const currentMinutes = Math.floor(currentTime / 60);
739
+ const currentSeconds = Math.floor(currentTime % 60);
740
+ const durationMinutes = Math.floor(duration / 60);
741
+ const durationSeconds = Math.floor(duration % 60);
742
+
743
+ elements.timeDisplay.textContent =
744
+ `${currentMinutes.toString().padStart(2, '0')}:${currentSeconds.toString().padStart(2, '0')} / ` +
745
+ `${durationMinutes.toString().padStart(2, '0')}:${durationSeconds.toString().padStart(2, '0')}`;
746
+
747
+ // Update waveform visualization (simplified)
748
+ const progressPercent = (currentTime / duration) * 100;
749
+ document.querySelector('.progress-indicator').style.width = `${progressPercent}%`;
750
+ }
751
+
752
+ // Create new project
753
+ function createNewProject() {
754
+ // Save current project if it has content
755
+ if (state.currentProject.audioFile || state.currentProject.transcription.length > 0) {
756
+ saveProject();
757
+ }
758
+
759
+ // Reset state for new project
760
+ state.currentProject = {
761
+ id: Date.now(),
762
+ name: 'Untitled Project',
763
+ audioFile: null,
764
+ transcription: [],
765
+ settings: {
766
+ noiseReduction: true,
767
+ model: 'balanced',
768
+ diarization: 'advanced',
769
+ emotionDetection: true
770
+ },
771
+ processed: false
772
+ };
773
+
774
+ // Reset UI
775
+ elements.dropzone.classList.remove('hidden');
776
+ elements.processingSection.classList.add('hidden');
777
+ elements.fileInput.value = '';
778
+ elements.projectTitle.textContent = 'Untitled Project';
779
+
780
+ // Stop any ongoing processing
781
+ state.isProcessing = false;
782
+ if (state.recognition) {
783
+ state.recognition.stop();
784
+ }
785
+ }
786
+
787
+ // Update settings from UI
788
+ function updateSettings() {
789
+ state.currentProject.settings = {
790
+ noiseReduction: elements.noiseReductionToggle.checked,
791
+ model: elements.modelSelect.value,
792
+ diarization: elements.diarizationSelect.value,
793
+ emotionDetection: elements.emotionToggle.checked
794
+ };
795
+ }
796
+
797
+ // Save project
798
+ function saveProject() {
799
+ if (!state.currentProject.audioFile && state.currentProject.transcription.length === 0) {
800
+ alert('Nothing to save! Please upload an audio file first.');
801
+ return;
802
+ }
803
+
804
+ // Check if this project already exists in the projects array
805
+ const existingIndex = state.projects.findIndex(p => p.id === state.currentProject.id);
806
+
807
+ if (existingIndex >= 0) {
808
+ // Update existing project
809
+ state.projects[existingIndex] = {...state.currentProject};
810
+ } else {
811
+ // Add new project
812
+ state.projects.push({...state.currentProject});
813
+ }
814
+
815
+ // Update UI
816
+ updateProjectsList();
817
+ alert('Project saved successfully!');
818
+ }
819
+
820
+ // Load projects (simulated - in a real app this would be from storage)
821
+ function loadProjects() {
822
+ // Sample projects for demo
823
+ state.projects = [
824
+ {
825
+ id: 1,
826
+ name: 'Interview_001',
827
+ audioFile: { name: 'interview_001.wav' },
828
+ transcription: [],
829
+ settings: {
830
+ noiseReduction: true,
831
+ model: 'balanced',
832
+ diarization: 'advanced',
833
+ emotionDetection: true
834
+ },
835
+ processed: true
836
+ },
837
+ {
838
+ id: 2,
839
+ name: 'Meeting_2023',
840
+ audioFile: { name: 'meeting_2023.wav' },
841
+ transcription: [],
842
+ settings: {
843
+ noiseReduction: false,
844
+ model: 'fast',
845
+ diarization: 'basic',
846
+ emotionDetection: false
847
+ },
848
+ processed: true
849
+ },
850
+ {
851
+ id: 3,
852
+ name: 'Podcast_Episode',
853
+ audioFile: { name: 'podcast_episode.wav' },
854
+ transcription: [],
855
+ settings: {
856
+ noiseReduction: true,
857
+ model: 'accurate',
858
+ diarization: 'precision',
859
+ emotionDetection: true
860
+ },
861
+ processed: false
862
+ }
863
+ ];
864
+
865
+ updateProjectsList();
866
+ }
867
+
868
+ // Update projects list in sidebar
869
+ function updateProjectsList() {
870
+ elements.projectList.innerHTML = '';
871
+
872
+ state.projects.forEach(project => {
873
+ const li = document.createElement('li');
874
+ li.className = 'px-2 py-1 rounded hover:bg-gray-100 cursor-pointer flex items-center';
875
+ li.innerHTML = `
876
+ <i class="fas fa-file-audio text-gray-400 mr-2"></i> ${project.name}
877
+ `;
878
+
879
+ li.addEventListener('click', () => loadProject(project.id));
880
+ elements.projectList.appendChild(li);
881
+ });
882
+ }
883
+
884
+ // Load project
885
+ function loadProject(id) {
886
+ const project = state.projects.find(p => p.id === id);
887
+ if (!project) return;
888
+
889
+ state.currentProject = {...project};
890
+ updateUI();
891
+
892
+ if (project.audioFile) {
893
+ elements.dropzone.classList.add('hidden');
894
+ elements.processingSection.classList.remove('hidden');
895
+ elements.currentFileName.textContent = project.audioFile.name;
896
+
897
+ // In a real app, we would load the actual audio file and transcription
898
+ if (project.processed) {
899
+ elements.fileProgress.textContent = '100%';
900
+ elements.fileProgressBar.style.width = '100%';
901
+ elements.progressStatus.textContent = 'Processing complete!';
902
+
903
+ // Simulate loading the audio and transcription
904
+ setTimeout(() => {
905
+ renderTranscription();
906
+ generateWaveform();
907
+ }, 500);
908
+ } else {
909
+ // Simulate processing if not already processed
910
+ simulateProcessing();
911
+ }
912
+ }
913
+ }
914
+
915
+ // Export as text
916
+ function exportAsTxt(e) {
917
+ e.preventDefault();
918
+ if (!state.currentProject.processed) {
919
+ alert('Please process the audio first!');
920
+ return;
921
+ }
922
+
923
+ let textContent = `Transcription for ${state.currentProject.name}\n\n`;
924
+
925
+ state.currentProject.transcription.forEach(segment => {
926
+ textContent += `Speaker ${segment.speaker}: ${segment.text}\n\n`;
927
+ });
928
+
929
+ downloadFile(textContent, `${state.currentProject.name}.txt`, 'text/plain');
930
+ }
931
+
932
+ // Export as Word (simulated)
933
+ function exportAsDocx(e) {
934
+ e.preventDefault();
935
+ alert('In a real application, this would export as a Word document.');
936
+ }
937
+
938
+ // Export as subtitles
939
+ function exportAsSrt(e) {
940
+ e.preventDefault();
941
+ if (!state.currentProject.processed) {
942
+ alert('Please process the audio first!');
943
+ return;
944
+ }
945
+
946
+ let srtContent = '';
947
+ let counter = 1;
948
+
949
+ state.currentProject.transcription.forEach(segment => {
950
+ const startTime = formatTimeForSrt(segment.time);
951
+ const endTime = formatTimeForSrt(segment.time + 5); // Assuming 5 seconds per segment for demo
952
+
953
+ srtContent += `${counter++}\n`;
954
+ srtContent += `${startTime} --> ${endTime}\n`;
955
+ srtContent += `${segment.text}\n\n`;
956
+ });
957
+
958
+ downloadFile(srtContent, `${state.currentProject.name}.srt`, 'text/plain');
959
+ }
960
+
961
+ // Format time for SRT
962
+ function formatTimeForSrt(seconds) {
963
+ const hours = Math.floor(seconds / 3600);
964
+ const minutes = Math.floor((seconds % 3600) / 60);
965
+ const secs = Math.floor(seconds % 60);
966
+ const millis = Math.floor((seconds % 1) * 1000);
967
+
968
+ return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')},${millis.toString().padStart(3, '0')}`;
969
+ }
970
+
971
+ // Export as JSON
972
+ function exportAsJson(e) {
973
+ e.preventDefault();
974
+ const jsonContent = JSON.stringify(state.currentProject, null, 2);
975
+ downloadFile(jsonContent, `${state.currentProject.name}.json`, 'application/json');
976
+ }
977
+
978
+ // Export audio
979
+ function exportAudio(e) {
980
+ e.preventDefault();
981
+ if (!state.currentProject.audioFile) {
982
+ alert('No audio file to export!');
983
+ return;
984
+ }
985
+
986
+ // In a real app, we would use the actual audio file
987
+ alert('In a real application, this would export the audio file.');
988
+ }
989
+
990
+ // Download helper function
991
+ function downloadFile(content, filename, mimeType) {
992
+ const blob = new Blob([content], { type: mimeType });
993
+ const url = URL.createObjectURL(blob);
994
+
995
+ const a = document.createElement('a');
996
+ a.href = url;
997
+ a.download = filename;
998
+ document.body.appendChild(a);
999
+ a.click();
1000
+
1001
+ setTimeout(() => {
1002
+ document.body.removeChild(a);
1003
+ URL.revokeObjectURL(url);
1004
+ }, 100);
1005
+ }
1006
+
1007
+ // Update UI based on state
1008
+ function updateUI() {
1009
+ elements.projectTitle.textContent = state.currentProject.name;
1010
+
1011
+ // Update settings toggles
1012
+ elements.noiseReductionToggle.checked = state.currentProject.settings.noiseReduction;
1013
+ elements.modelSelect.value = state.currentProject.settings.model;
1014
+ elements.diarizationSelect.value = state.currentProject.settings.diarization;
1015
+ elements.emotionToggle.checked = state.currentProject.settings.emotionDetection;
1016
+ }
1017
 
1018
+ // Initialize the app
1019
+ init();
 
 
 
 
1020
  </script>
1021
  <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 <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MagicBullets/tts" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1022
  </html>
prompts.txt CHANGED
@@ -0,0 +1 @@
 
 
1
+ can you make this work and not just a preview?