Spaces:
Running
Running
Add 2 files
Browse files- index.html +741 -146
- 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 |
-
<
|
| 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
|
| 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="
|
| 163 |
-
<p class="text-sm text-gray-500 mt-4">Supports
|
| 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">
|
| 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">
|
| 178 |
-
<span class="text-xs text-gray-500">
|
| 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:
|
| 182 |
</div>
|
| 183 |
<div class="mt-2 text-xs text-gray-500 flex justify-between">
|
| 184 |
-
<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 |
-
<
|
| 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">
|
| 229 |
-
|
|
|
|
|
|
|
|
|
|
| 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:
|
| 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>
|
| 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"
|
| 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"
|
| 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 |
-
|
| 349 |
document.querySelector('.sidebar').classList.toggle('hidden');
|
| 350 |
-
}
|
| 351 |
|
| 352 |
-
//
|
| 353 |
-
|
| 354 |
e.stopPropagation();
|
| 355 |
-
|
| 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 |
-
|
| 369 |
-
|
| 370 |
-
|
|
|
|
| 371 |
|
|
|
|
| 372 |
function preventDefaults(e) {
|
| 373 |
e.preventDefault();
|
| 374 |
e.stopPropagation();
|
| 375 |
}
|
| 376 |
|
| 377 |
-
|
| 378 |
-
|
| 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 |
-
|
| 390 |
-
|
|
|
|
| 391 |
}
|
| 392 |
|
| 393 |
-
|
| 394 |
-
fileInput.addEventListener('change', handleFiles);
|
| 395 |
-
|
| 396 |
function handleDrop(e) {
|
| 397 |
const dt = e.dataTransfer;
|
| 398 |
const files = dt.files;
|
| 399 |
-
handleFiles(
|
| 400 |
}
|
| 401 |
|
| 402 |
-
|
|
|
|
| 403 |
const files = e.target.files;
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
|
| 409 |
-
|
| 410 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 411 |
}
|
|
|
|
|
|
|
| 412 |
}
|
| 413 |
|
| 414 |
-
//
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 418 |
|
| 419 |
-
//
|
| 420 |
-
|
| 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?
|