radames/whisper.cpp-wasm
16
1<!doctype html>2<html lang="en-us">3 <head>4 <title>whisper.cpp : WASM example</title>5 <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>6 7 <style>8 #output {9 width: 100%;10 height: 100%;11 margin: 0 auto;12 margin-top: 10px;13 border-left: 0px;14 border-right: 0px;15 padding-left: 0px;16 padding-right: 0px;17 display: block;18 background-color: black;19 color: white;20 font-size: 10px;21 font-family: "Lucida Console", Monaco, monospace;22 outline: none;23 white-space: pre;24 overflow-wrap: normal;25 overflow-x: scroll;26 } 27 </style>28 </head>29 <body>30 <div id="main-container">31 <div id="warning" style="display: none; padding: 1rem">32 <b style="color: red; font-size: large"33 >Warning: your browser does not support SharedArrayBuffer please try34 open the page in a new tab.35 </b>36<!-- <a target="_blank" href="https://radames-whisper-wasm.hf.space" target="_blank"37 >https://radames-whisper-wasm.hf.space</a38 > -->39 </div>40 <b41 >Minimal42 <a target="_blank" href="https://github.com/ggerganov/whisper.cpp">whisper.cpp</a>43 example running fully in the browser</b44 >45 46 <br /><br />47 48 Usage instructions:<br />49 <ul>50 <li>51 Load a ggml model file (you can obtain one from52 <a target="_blank" href="https://ggml.ggerganov.com/">here</a>, recommended:53 <b>tiny</b> or <b>base</b>)54 </li>55 <li>56 Select audio file to transcribe or record audio from the microphone57 (sample: <a target="_blank" href="https://whisper.ggerganov.com/jfk.wav">jfk.wav</a>)58 </li>59 <li>Click on the "Transcribe" button to start the transcription</li>60 </ul>61 62 Note that the computation is quite heavy and may take a few seconds to63 complete.<br />64 The transcription results will be displayed in the text area below.<br /><br />65 <b>Important:</b>66 <ul>67 <li>68 your browser must support WASM SIMD instructions for this to work69 </li>70 <li>71 Firefox cannot load files larger than 256 MB - use Chrome instead72 </li>73 </ul>74 75 <b>More examples:</b>76 <a target="_blank" href="https://whisper.ggerganov.com/">main</a> |77 <a target="_blank" href="https://whisper.ggerganov.com/bench">bench</a> |78 <a target="_blank" href="https://whisper.ggerganov.com/stream">stream</a> |79 <a target="_blank" href="https://whisper.ggerganov.com/command">command</a> |80 <a target="_blank" href="https://whisper.ggerganov.com/talk">talk</a> |81 82 <hr />83 84 <div id="model">85 Whisper models: <span id="model-whisper-status"></span><br /><br />86 <button id="fetch-whisper-tiny-en" onclick="loadWhisper('tiny.en')">87 tiny.en (75 MB)88 </button>89 <button id="fetch-whisper-tiny" onclick="loadWhisper('tiny')">90 tiny (75 MB)91 </button>92 <button id="fetch-whisper-base-en" onclick="loadWhisper('base.en')">93 base.en (142 MB)94 </button>95 <button id="fetch-whisper-base" onclick="loadWhisper('base')">96 base (142 MB)97 </button>98 <button id="fetch-whisper-small-en" onclick="loadWhisper('small.en')">99 small.en (466 MB)100 </button>101 <button id="fetch-whisper-small" onclick="loadWhisper('small')">102 small (466 MB)103 </button>104 <input105 type="file"106 id="whisper-file"107 name="file"108 onchange="loadFile(event, 'whisper.bin')"109 />110 <br /><br />111 Quantized models:<br /><br />112 <button113 id="fetch-whisper-tiny-en-q5_1"114 onclick="loadWhisper('tiny-en-q5_1')"115 >116 tiny.en (Q5_1, 31 MB)117 </button>118 <button id="fetch-whisper-tiny-q5_1" onclick="loadWhisper('tiny-q5_1')">119 tiny (Q5_1, 31 MB)120 </button>121 <button122 id="fetch-whisper-base-en-q5_1"123 onclick="loadWhisper('base-en-q5_1')"124 >125 base.en (Q5_1, 57 MB)126 </button>127 <button id="fetch-whisper-base-q5_1" onclick="loadWhisper('base-q5_1')">128 base (Q5_1, 57 MB)129 </button>130 <button131 id="fetch-whisper-small-en-q5_1"132 onclick="loadWhisper('small-en-q5_1')"133 >134 small.en (Q5_1, 182 MB)135 </button>136 <button137 id="fetch-whisper-small-q5_1"138 onclick="loadWhisper('small-q5_1')"139 >140 small (Q5_1, 182 MB)</button141 ><br />142 <button143 id="fetch-whisper-medium-en-q5_0"144 onclick="loadWhisper('medium-en-q5_0')"145 >146 medium.en (Q5_0, 515 MB)147 </button>148 <button149 id="fetch-whisper-medium-q5_0"150 onclick="loadWhisper('medium-q5_0')"151 >152 medium (Q5_0, 515 MB)153 </button>154 <button155 id="fetch-whisper-large-q5_0"156 onclick="loadWhisper('large-q5_0')"157 >158 large (Q5_0, 1030 MB)159 </button>160 <span id="fetch-whisper-progress"></span>161 </div>162 163 <br />164 165 <!-- radio button to select between file upload or microphone -->166 <div id="input">167 Input:168 <input169 type="radio"170 id="file"171 name="input"172 value="file"173 checked="checked"174 onchange="changeInput('file')"175 />176 <label for="file">File</label>177 <input178 type="radio"179 id="mic"180 name="input"181 value="mic"182 onchange="changeInput('mic')"183 />184 <label for="mic">Microphone</label>185 </div>186 187 <br />188 189 <div id="input_file">190 Audio file:191 <input type="file" id="file" name="file" onchange="loadAudio(event)" />192 </div>193 194 <div id="input_mic" style="display: none">195 Microphone:196 <button id="start" onclick="startRecording()">Start</button>197 <button id="stop" onclick="stopRecording()" disabled>Stop</button>198 199 <!-- progress bar to show recording progress -->200 <br /><br />201 <div id="progress" style="display: none">202 <div203 id="progress-bar"204 style="width: 0%; height: 10px; background-color: #4caf50"205 ></div>206 <div id="progress-text">0%</div>207 </div>208 </div>209 210 <a target="_blank"udio controls="controls" id="audio" loop hidden>211 Your browser does not support the <audio> tag.212 <source id="source" src="" type="audio/wav" />213 </audio>214 215 <hr />216 <br />217 218 <table>219 <tr>220 <td>221 Language:222 <select id="language" name="language">223 <option value="en">English</option>224 <option value="ar">Arabic</option>225 <option value="hy">Armenian</option>226 <option value="az">Azerbaijani</option>227 <option value="eu">Basque</option>228 <option value="be">Belarusian</option>229 <option value="bn">Bengali</option>230 <option value="bg">Bulgarian</option>231 <option value="ca">Catalan</option>232 <option value="zh">Chinese</option>233 <option value="hr">Croatian</option>234 <option value="cs">Czech</option>235 <option value="da">Danish</option>236 <option value="nl">Dutch</option>237 <option value="en">English</option>238 <option value="et">Estonian</option>239 <option value="tl">Filipino</option>240 <option value="fi">Finnish</option>241 <option value="fr">French</option>242 <option value="gl">Galician</option>243 <option value="ka">Georgian</option>244 <option value="de">German</option>245 <option value="el">Greek</option>246 <option value="gu">Gujarati</option>247 <option value="iw">Hebrew</option>248 <option value="hi">Hindi</option>249 <option value="hu">Hungarian</option>250 <option value="is">Icelandic</option>251 <option value="id">Indonesian</option>252 <option value="ga">Irish</option>253 <option value="it">Italian</option>254 <option value="ja">Japanese</option>255 <option value="kn">Kannada</option>256 <option value="ko">Korean</option>257 <option value="la">Latin</option>258 <option value="lv">Latvian</option>259 <option value="lt">Lithuanian</option>260 <option value="mk">Macedonian</option>261 <option value="ms">Malay</option>262 <option value="mt">Maltese</option>263 <option value="no">Norwegian</option>264 <option value="fa">Persian</option>265 <option value="pl">Polish</option>266 <option value="pt">Portuguese</option>267 <option value="ro">Romanian</option>268 <option value="ru">Russian</option>269 <option value="sr">Serbian</option>270 <option value="sk">Slovak</option>271 <option value="sl">Slovenian</option>272 <option value="es">Spanish</option>273 <option value="sw">Swahili</option>274 <option value="sv">Swedish</option>275 <option value="ta">Tamil</option>276 <option value="te">Telugu</option>277 <option value="th">Thai</option>278 <option value="tr">Turkish</option>279 <option value="uk">Ukrainian</option>280 <option value="ur">Urdu</option>281 <option value="vi">Vietnamese</option>282 <option value="cy">Welsh</option>283 <option value="yi">Yiddish</option>284 </select>285 </td>286 <!-- Slider to select number of threads between 1 and 16 -->287 <td>288 Threads:289 <input290 type="range"291 id="threads"292 name="threads"293 min="1"294 max="16"295 value="8"296 onchange="changeThreads(this.value)"297 />298 <span id="threads-value">8</span>299 </td>300 <td>301 <button onclick="onProcess(false);">Transcribe</button>302 </td>303 <td>304 <button onclick="onProcess(true);">Translate</button>305 </td>306 </tr>307 </table>308 309 <br />310 311 <!-- textarea with height filling the rest of the page -->312 <textarea id="output" rows="20"></textarea>313 314 <br /><br />315 316 <div class="cell-version">317 <span>318 | Build time: <span class="nav-link">@GIT_DATE@</span> | Commit hash:319 <a target="_blank"320 class="nav-link"321 href="https://github.com/ggerganov/whisper.cpp/commit/@GIT_SHA1@"322 >@GIT_SHA1@</a323 >324 | Commit subject: <span class="nav-link">@GIT_COMMIT_SUBJECT@</span> |325 <a target="_blank"326 class="nav-link"327 href="https://github.com/ggerganov/whisper.cpp/tree/master/examples/whisper.wasm"328 >Source Code</a329 >330 |331 </span>332 </div>333 </div>334 335 <script type="text/javascript" src="helpers.js"></script>336 <script type="text/javascript">337 document.addEventListener("DOMContentLoaded", () => {338 //check is shared array buffer is supported339 if (!window.SharedArrayBuffer) {340 document.querySelector("#warning").style.display = "block";341 }342 });343 // TODO: convert audio buffer to WAV344 function setAudio(audio) {345 //if (audio) {346 // // convert to 16-bit PCM347 // var blob = new Blob([audio], { type: 'audio/wav' });348 // var url = URL.createObjectURL(blob);349 // document.getElementById('source').src = url;350 // document.getElementById('audio').hidden = false;351 // document.getElementById('audio').loop = false;352 // document.getElementById('audio').load();353 //} else {354 // document.getElementById('audio').hidden = true;355 //}356 }357 358 function changeInput(input) {359 if (input == "file") {360 document.getElementById("input_file").style.display = "block";361 document.getElementById("input_mic").style.display = "none";362 document.getElementById("progress").style.display = "none";363 } else {364 document.getElementById("input_file").style.display = "none";365 document.getElementById("input_mic").style.display = "block";366 document.getElementById("progress").style.display = "block";367 }368 }369 370 var Module = {371 print: printTextarea,372 printErr: printTextarea,373 setStatus: function (text) {374 printTextarea("js: " + text);375 },376 monitorRunDependencies: function (left) {},377 };378 379 // web audio context380 var context = null;381 382 // audio data383 var audio = null;384 385 // the whisper instance386 var instance = null;387 var model_whisper = "";388 389 // helper function390 function convertTypedArray(src, type) {391 var buffer = new ArrayBuffer(src.byteLength);392 var baseView = new src.constructor(buffer).set(src);393 return new type(buffer);394 }395 396 //397 // load model398 //399 400 let dbVersion = 1;401 let dbName = "whisper.ggerganov.com";402 let indexedDB =403 window.indexedDB ||404 window.mozIndexedDB ||405 window.webkitIndexedDB ||406 window.msIndexedDB;407 408 function storeFS(fname, buf) {409 // write to WASM file using FS_createDataFile410 // if the file exists, delete it411 try {412 Module.FS_unlink(fname);413 } catch (e) {414 // ignore415 }416 417 Module.FS_createDataFile("/", fname, buf, true, true);418 419 //model_whisper = fname;420 421 document.getElementById("model-whisper-status").innerHTML =422 'loaded "' + model_whisper + '"!';423 424 printTextarea(425 "storeFS: stored model: " + fname + " size: " + buf.length426 );427 428 document.getElementById("model").innerHTML =429 "Model fetched: " + model_whisper;430 }431 432 function loadFile(event, fname) {433 var file = event.target.files[0] || null;434 if (file == null) {435 return;436 }437 438 printTextarea(439 "loadFile: loading model: " +440 file.name +441 ", size: " +442 file.size +443 " bytes"444 );445 printTextarea("loadFile: please wait ...");446 447 var reader = new FileReader();448 reader.onload = function (event) {449 var buf = new Uint8Array(reader.result);450 storeFS(fname, buf);451 };452 reader.readAsArrayBuffer(file);453 454 document.getElementById("fetch-whisper-tiny-en").style.display = "none";455 document.getElementById("fetch-whisper-base-en").style.display = "none";456 document.getElementById("fetch-whisper-small-en").style.display =457 "none";458 document.getElementById("fetch-whisper-tiny").style.display = "none";459 document.getElementById("fetch-whisper-base").style.display = "none";460 document.getElementById("fetch-whisper-small").style.display = "none";461 462 document.getElementById("fetch-whisper-tiny-en-q5_1").style.display =463 "none";464 document.getElementById("fetch-whisper-tiny-q5_1").style.display =465 "none";466 document.getElementById("fetch-whisper-base-en-q5_1").style.display =467 "none";468 document.getElementById("fetch-whisper-base-q5_1").style.display =469 "none";470 document.getElementById("fetch-whisper-small-en-q5_1").style.display =471 "none";472 document.getElementById("fetch-whisper-small-q5_1").style.display =473 "none";474 document.getElementById("fetch-whisper-medium-en-q5_0").style.display =475 "none";476 document.getElementById("fetch-whisper-medium-q5_0").style.display =477 "none";478 document.getElementById("fetch-whisper-large-q5_0").style.display =479 "none";480 481 document.getElementById("whisper-file").style.display = "none";482 document.getElementById("model-whisper-status").innerHTML =483 "loaded model: " + file.name;484 }485 486 function loadWhisper(model) {487 const baseURL =488 "https://huggingface.co/ggerganov/whisper.cpp/resolve/main";489 let urls = {490 "tiny.en": `${baseURL}/ggml-tiny.en.bin`,491 tiny: `${baseURL}/ggml-tiny.bin`,492 "base.en": `${baseURL}/ggml-base.en.bin`,493 base: `${baseURL}/ggml-base.bin`,494 "small.en": `${baseURL}/ggml-small.en.bin`,495 small: `${baseURL}/ggml-small.bin`,496 497 "tiny-en-q5_1": `${baseURL}/ggml-model-whisper-tiny.en-q5_1.bin`,498 "tiny-q5_1": `${baseURL}/ggml-model-whisper-tiny-q5_1.bin`,499 "base-en-q5_1": `${baseURL}/ggml-model-whisper-base.en-q5_1.bin`,500 "base-q5_1": `${baseURL}/ggml-model-whisper-base-q5_1.bin`,501 "small-en-q5_1": `${baseURL}/ggml-model-whisper-small.en-q5_1.bin`,502 "small-q5_1": `${baseURL}/ggml-model-whisper-small-q5_1.bin`,503 "medium-en-q5_0": `${baseURL}/ggml-model-whisper-medium.en-q5_0.bin`,504 "medium-q5_0": `${baseURL}/ggml-model-whisper-medium-q5_0.bin`,505 "large-q5_0": `${baseURL}/ggml-model-whisper-large-q5_0.bin`,506 };507 508 let sizes = {509 "tiny.en": 75,510 tiny: 75,511 "base.en": 142,512 base: 142,513 "small.en": 466,514 small: 466,515 516 "tiny-en-q5_1": 31,517 "tiny-q5_1": 31,518 "base-en-q5_1": 57,519 "base-q5_1": 57,520 "small-en-q5_1": 182,521 "small-q5_1": 182,522 "medium-en-q5_0": 515,523 "medium-q5_0": 515,524 "large-q5_0": 1030,525 };526 527 let url = urls[model];528 let dst = "whisper.bin";529 let size_mb = sizes[model];530 531 model_whisper = model;532 533 document.getElementById("fetch-whisper-tiny-en").style.display = "none";534 document.getElementById("fetch-whisper-base-en").style.display = "none";535 document.getElementById("fetch-whisper-small-en").style.display =536 "none";537 document.getElementById("fetch-whisper-tiny").style.display = "none";538 document.getElementById("fetch-whisper-base").style.display = "none";539 document.getElementById("fetch-whisper-small").style.display = "none";540 541 document.getElementById("fetch-whisper-tiny-en-q5_1").style.display =542 "none";543 document.getElementById("fetch-whisper-tiny-q5_1").style.display =544 "none";545 document.getElementById("fetch-whisper-base-en-q5_1").style.display =546 "none";547 document.getElementById("fetch-whisper-base-q5_1").style.display =548 "none";549 document.getElementById("fetch-whisper-small-en-q5_1").style.display =550 "none";551 document.getElementById("fetch-whisper-small-q5_1").style.display =552 "none";553 document.getElementById("fetch-whisper-medium-en-q5_0").style.display =554 "none";555 document.getElementById("fetch-whisper-medium-q5_0").style.display =556 "none";557 document.getElementById("fetch-whisper-large-q5_0").style.display =558 "none";559 560 document.getElementById("whisper-file").style.display = "none";561 document.getElementById("model-whisper-status").innerHTML =562 "loading model: " + model;563 564 cbProgress = function (p) {565 let el = document.getElementById("fetch-whisper-progress");566 el.innerHTML = Math.round(100 * p) + "%";567 };568 569 cbCancel = function () {570 var el;571 572 el = document.getElementById("fetch-whisper-tiny-en");573 if (el) el.style.display = "inline-block";574 el = document.getElementById("fetch-whisper-base-en");575 if (el) el.style.display = "inline-block";576 el = document.getElementById("fetch-whisper-small-en");577 if (el) el.style.display = "inline-block";578 el = document.getElementById("fetch-whisper-tiny");579 if (el) el.style.display = "inline-block";580 el = document.getElementById("fetch-whisper-base");581 if (el) el.style.display = "inline-block";582 el = document.getElementById("fetch-whisper-small");583 if (el) el.style.display = "inline-block";584 585 el = document.getElementById("fetch-whisper-tiny-en-q5_1");586 if (el) el.style.display = "inline-block";587 el = document.getElementById("fetch-whisper-tiny-q5_1");588 if (el) el.style.display = "inline-block";589 el = document.getElementById("fetch-whisper-base-en-q5_1");590 if (el) el.style.display = "inline-block";591 el = document.getElementById("fetch-whisper-base-q5_1");592 if (el) el.style.display = "inline-block";593 el = document.getElementById("fetch-whisper-small-en-q5_1");594 if (el) el.style.display = "inline-block";595 el = document.getElementById("fetch-whisper-small-q5_1");596 if (el) el.style.display = "inline-block";597 el = document.getElementById("fetch-whisper-medium-en-q5_0");598 if (el) el.style.display = "inline-block";599 el = document.getElementById("fetch-whisper-medium-q5_0");600 if (el) el.style.display = "inline-block";601 el = document.getElementById("fetch-whisper-large-q5_0");602 if (el) el.style.display = "inline-block";603 604 el = document.getElementById("whisper-file");605 if (el) el.style.display = "inline-block";606 el = document.getElementById("model-whisper-status");607 if (el) el.innerHTML = "";608 };609 610 loadRemote(611 url,612 dst,613 size_mb,614 cbProgress,615 storeFS,616 cbCancel,617 printTextarea618 );619 }620 621 //622 // audio file623 //624 625 const kMaxAudio_s = 30 * 60;626 const kMaxRecording_s = 2 * 60;627 const kSampleRate = 16000;628 629 window.AudioContext = window.AudioContext || window.webkitAudioContext;630 window.OfflineAudioContext =631 window.OfflineAudioContext || window.webkitOfflineAudioContext;632 633 function loadAudio(event) {634 if (!context) {635 context = new AudioContext({636 sampleRate: kSampleRate,637 channelCount: 1,638 echoCancellation: false,639 autoGainControl: true,640 noiseSuppression: true,641 });642 }643 644 var file = event.target.files[0] || null;645 if (file == null) {646 return;647 }648 649 printTextarea(650 "js: loading audio: " + file.name + ", size: " + file.size + " bytes"651 );652 printTextarea("js: please wait ...");653 654 var reader = new FileReader();655 reader.onload = function (event) {656 var buf = new Uint8Array(reader.result);657 658 context.decodeAudioData(659 buf.buffer,660 function (audioBuffer) {661 var offlineContext = new OfflineAudioContext(662 audioBuffer.numberOfChannels,663 audioBuffer.length,664 audioBuffer.sampleRate665 );666 var source = offlineContext.createBufferSource();667 source.buffer = audioBuffer;668 source.connect(offlineContext.destination);669 source.start(0);670 671 offlineContext.startRendering().then(function (renderedBuffer) {672 audio = renderedBuffer.getChannelData(0);673 printTextarea("js: audio loaded, size: " + audio.length);674 675 // truncate to first 30 seconds676 if (audio.length > kMaxAudio_s * kSampleRate) {677 audio = audio.slice(0, kMaxAudio_s * kSampleRate);678 printTextarea(679 "js: truncated audio to first " + kMaxAudio_s + " seconds"680 );681 }682 683 setAudio(audio);684 });685 },686 function (e) {687 printTextarea("js: error decoding audio: " + e);688 audio = null;689 setAudio(audio);690 }691 );692 };693 reader.readAsArrayBuffer(file);694 }695 696 //697 // microphone698 //699 700 var mediaRecorder = null;701 var doRecording = false;702 var startTime = 0;703 704 function stopRecording() {705 doRecording = false;706 }707 708 // record up to kMaxRecording_s seconds of audio from the microphone709 // check if doRecording is false every 1000 ms and stop recording if so710 // update progress information711 function startRecording() {712 if (!context) {713 context = new AudioContext({714 sampleRate: kSampleRate,715 channelCount: 1,716 echoCancellation: false,717 autoGainControl: true,718 noiseSuppression: true,719 });720 }721 722 document.getElementById("start").disabled = true;723 document.getElementById("stop").disabled = false;724 725 document.getElementById("progress-bar").style.width = "0%";726 document.getElementById("progress-text").innerHTML = "0%";727 728 doRecording = true;729 startTime = Date.now();730 731 var chunks = [];732 var stream = null;733 734 navigator.mediaDevices735 .getUserMedia({ audio: true, video: false })736 .then(function (s) {737 stream = s;738 mediaRecorder = new MediaRecorder(stream);739 mediaRecorder.ondataavailable = function (e) {740 chunks.push(e.data);741 };742 mediaRecorder.onstop = function (e) {743 var blob = new Blob(chunks, { type: "audio/ogg; codecs=opus" });744 chunks = [];745 746 document.getElementById("start").disabled = false;747 document.getElementById("stop").disabled = true;748 749 var reader = new FileReader();750 reader.onload = function (event) {751 var buf = new Uint8Array(reader.result);752 753 context.decodeAudioData(754 buf.buffer,755 function (audioBuffer) {756 var offlineContext = new OfflineAudioContext(757 audioBuffer.numberOfChannels,758 audioBuffer.length,759 audioBuffer.sampleRate760 );761 var source = offlineContext.createBufferSource();762 source.buffer = audioBuffer;763 source.connect(offlineContext.destination);764 source.start(0);765 766 offlineContext767 .startRendering()768 .then(function (renderedBuffer) {769 audio = renderedBuffer.getChannelData(0);770 printTextarea(771 "js: audio recorded, size: " + audio.length772 );773 774 // truncate to first 30 seconds775 if (audio.length > kMaxRecording_s * kSampleRate) {776 audio = audio.slice(0, kMaxRecording_s * kSampleRate);777 printTextarea(778 "js: truncated audio to first " +779 kMaxRecording_s +780 " seconds"781 );782 }783 setAudio(audio);784 });785 },786 function (e) {787 printTextarea("js: error decoding audio: " + e);788 audio = null;789 setAudio(audio);790 }791 );792 };793 794 reader.readAsArrayBuffer(blob);795 };796 mediaRecorder.start();797 })798 .catch(function (err) {799 printTextarea("js: error getting audio stream: " + err);800 });801 802 var interval = setInterval(function () {803 if (!doRecording) {804 clearInterval(interval);805 mediaRecorder.stop();806 stream.getTracks().forEach(function (track) {807 track.stop();808 });809 }810 811 document.getElementById("progress-bar").style.width =812 (100 * (Date.now() - startTime)) / 1000 / kMaxRecording_s + "%";813 document.getElementById("progress-text").innerHTML =814 ((100 * (Date.now() - startTime)) / 1000 / kMaxRecording_s).toFixed(815 0816 ) + "%";817 }, 1000);818 819 printTextarea("js: recording ...");820 821 setTimeout(function () {822 if (doRecording) {823 printTextarea(824 "js: recording stopped after " + kMaxRecording_s + " seconds"825 );826 stopRecording();827 }828 }, kMaxRecording_s * 1000);829 }830 831 //832 // transcribe833 //834 835 var nthreads = 8;836 837 function changeThreads(value) {838 nthreads = value;839 document.getElementById("threads-value").innerHTML = nthreads;840 }841 842 function onProcess(translate) {843 if (!instance) {844 instance = Module.init("whisper.bin");845 846 if (instance) {847 printTextarea("js: whisper initialized, instance: " + instance);848 document.getElementById("model").innerHTML =849 "Model loaded: " + model_whisper;850 }851 }852 853 if (!instance) {854 printTextarea("js: failed to initialize whisper");855 return;856 }857 858 if (!audio) {859 printTextarea("js: no audio data");860 return;861 }862 863 if (instance) {864 printTextarea("");865 printTextarea("js: processing - this might take a while ...");866 printTextarea("");867 868 setTimeout(function () {869 var ret = Module.full_default(870 instance,871 audio,872 document.getElementById("language").value,873 nthreads,874 translate875 );876 console.log("js: full_default returned: " + ret);877 if (ret) {878 printTextarea("js: whisper returned: " + ret);879 }880 }, 100);881 }882 }883 </script>884 <script type="text/javascript" src="main.js"></script>885 </body>886</html>887 