Team Ai
Apppublic

natasa365/whisper.cpp

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
index-tmpl.html415 linesDownload Raw Back to command.wasm
1<!doctype html>2<html lang="en-us">3    <head>4        <title>command : Voice assistant example using Whisper + WebAssembly</title>5 6        <style>7            #output {8                width: 100%;9                height: 100%;10                margin: 0 auto;11                margin-top: 10px;12                border-left: 0px;13                border-right: 0px;14                padding-left: 0px;15                padding-right: 0px;16                display: block;17                background-color: black;18                color: white;19                font-size: 10px;20                font-family: 'Lucida Console', Monaco, monospace;21                outline: none;22                white-space: pre;23                overflow-wrap: normal;24                overflow-x: scroll;25            }26        </style>27        <script src="../coi-serviceworker.js"></script>28        <link rel="icon" href="data:,">29    </head>30    <body>31        <div id="main-container">32            <b>command : Voice assistant example using Whisper + WebAssembly</b>33 34            <br><br>35 36            You can find more about this project on <a href="https://github.com/ggerganov/whisper.cpp/tree/master/examples/command.wasm">GitHub</a>.37 38            <br><br>39 40            <b>More examples:</b>41                <a href="../">main</a> |42                <a href="../bench.wasm/">bench</a> |43                <a href="../stream.wasm">stream</a> |44                <a href="../command.wasm/">command</a> |45 46            <br><br>47 48            <hr>49 50            Select the model you would like to use, click the "Start" button and follow the instructions.51 52            <br><br>53 54            <div id="model-whisper">55                Whisper model: <span id="model-whisper-status"></span>56                <button id="fetch-whisper-tiny-en" onclick="loadWhisper('tiny.en')">tiny.en (75 MB)</button>57                <button id="fetch-whisper-base-en" onclick="loadWhisper('base.en')">base.en (142 MB)</button>58                <br><br>59                Quantized models:<br><br>60                <button id="fetch-whisper-tiny-en-q5_1"   onclick="loadWhisper('tiny-en-q5_1')">tiny.en (Q5_1, 31 MB)</button>61                <button id="fetch-whisper-base-en-q5_1"   onclick="loadWhisper('base-en-q5_1')">base.en (Q5_1, 57 MB)</button>62                <span id="fetch-whisper-progress"></span>63 64                <!--65                    <input type="file" id="file" name="file" onchange="loadFile(event, 'whisper.bin')" />66                -->67            </div>68 69            <br>70 71            <div id="input">72                <button id="start" onclick="onStart()" disabled>Start</button>73                <button id="stop"  onclick="onStop()" disabled>Stop</button>74                <button id="clear" onclick="clearCache()">Clear Cache</button>75            </div>76 77            <br>78 79            <div id="state">80                Status: <b><span id="state-status">not started</span></b>81 82                <pre id="state-transcribed">[The recognized voice commands will be displayed here]</pre>83            </div>84 85            <hr>86 87            Debug output:88            <textarea id="output" rows="20"></textarea>89 90            <br>91 92            <b>Troubleshooting</b>93 94            <br><br>95 96            The page does some heavy computations, so make sure:97 98            <ul>99                <li>To use a modern web browser (e.g. Chrome, Firefox)</li>100                <li>To use a fast desktop or laptop computer (i.e. not a mobile phone)</li>101                <li>Your browser supports WASM <a href="https://webassembly.org/roadmap/">Fixed-width SIMD</a></li>102            </ul>103 104            <div class="cell-version">105                <span>106                    |107                    Build time: <span class="nav-link">@GIT_DATE@</span> |108                    Commit hash: <a class="nav-link" href="https://github.com/ggerganov/whisper.cpp/commit/@GIT_SHA1@">@GIT_SHA1@</a> |109                    Commit subject: <span class="nav-link">@GIT_COMMIT_SUBJECT@</span> |110                    <a class="nav-link" href="https://github.com/ggerganov/whisper.cpp/tree/master/examples/command.wasm">Source Code</a> |111                </span>112            </div>113        </div>114 115        <script type="text/javascript" src="helpers.js"></script>116        <script type='text/javascript'>117            // web audio context118            var context = null;119 120            // audio data121            var audio = null;122            var audio0 = null;123 124            // the command instance125            var instance = null;126 127            // model name128            var model_whisper = null;129 130            var Module = {131                print: printTextarea,132                printErr: printTextarea,133                setStatus: function(text) {134                    printTextarea('js: ' + text);135                },136                monitorRunDependencies: function(left) {137                },138                preRun: function() {139                    printTextarea('js: Preparing ...');140                },141                postRun: function() {142                    printTextarea('js: Initialized successfully!');143                }144            };145 146            //147            // fetch models148            //149 150            let dbVersion = 1151            let dbName    = 'whisper.ggerganov.com';152            let indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB153 154            function storeFS(fname, buf) {155                // write to WASM file using FS_createDataFile156                // if the file exists, delete it157                try {158                    Module.FS_unlink(fname);159                } catch (e) {160                    // ignore161                }162 163                Module.FS_createDataFile("/", fname, buf, true, true);164 165                printTextarea('storeFS: stored model: ' + fname + ' size: ' + buf.length);166 167                document.getElementById('model-whisper-status').innerHTML = 'loaded "' + model_whisper + '"!';168 169                if (model_whisper != null) {170                    document.getElementById('start').disabled = false;171                    document.getElementById('stop' ).disabled = true;172                }173            }174 175            function loadWhisper(model) {176                let urls = {177                    'tiny.en': 'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin',178                    'base.en': 'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin',179 180                    'tiny-en-q5_1':  'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en-q5_1.bin',181                    'base-en-q5_1':  'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en-q5_1.bin',182                };183 184                let sizes = {185                    'tiny.en': 75,186                    'base.en': 142,187 188                    'tiny-en-q5_1':   31,189                    'base-en-q5_1':   57,190                };191 192                let url     = urls[model];193                let dst     = 'whisper.bin';194                let size_mb = sizes[model];195 196                model_whisper = model;197 198                document.getElementById('fetch-whisper-tiny-en').style.display = 'none';199                document.getElementById('fetch-whisper-base-en').style.display = 'none';200 201                document.getElementById('fetch-whisper-tiny-en-q5_1').style.display = 'none';202                document.getElementById('fetch-whisper-base-en-q5_1').style.display = 'none';203 204                document.getElementById('model-whisper-status').innerHTML = 'loading "' + model + '" ... ';205 206                cbProgress = function(p) {207                    let el = document.getElementById('fetch-whisper-progress');208                    el.innerHTML = Math.round(100*p) + '%';209                };210 211                cbCancel = function() {212                    var el;213                    el = document.getElementById('fetch-whisper-tiny-en'); if (el) el.style.display = 'inline-block';214                    el = document.getElementById('fetch-whisper-base-en'); if (el) el.style.display = 'inline-block';215 216                    el = document.getElementById('fetch-whisper-tiny-en-q5_1'); if (el) el.style.display = 'inline-block';217                    el = document.getElementById('fetch-whisper-base-en-q5_1'); if (el) el.style.display = 'inline-block';218 219                    el = document.getElementById('model-whisper-status');  if (el) el.innerHTML = '';220                };221 222                loadRemote(url, dst, size_mb, cbProgress, storeFS, cbCancel, printTextarea);223            }224 225            //226            // microphone227            //228 229            const kSampleRate = 16000;230            const kRestartRecording_s = 120;231            const kIntervalAudio_ms = 250; // pass the recorded audio to the C++ instance at this rate232 233            var mediaRecorder = null;234            var doRecording = false;235            var startTime = 0;236 237            window.AudioContext = window.AudioContext || window.webkitAudioContext;238            window.OfflineAudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext;239 240            function stopRecording() {241                Module.set_status("paused");242                doRecording = false;243                audio0 = null;244                audio = null;245                context = null;246            }247 248            function startRecording() {249                if (!context) {250                    context = new AudioContext({251                        sampleRate: kSampleRate,252                        channelCount: 1,253                        echoCancellation: false,254                        autoGainControl:  true,255                        noiseSuppression: true,256                    });257                }258 259                Module.set_status("");260 261                document.getElementById('start').disabled = true;262                document.getElementById('stop').disabled = false;263 264                doRecording = true;265                startTime = Date.now();266 267                var chunks = [];268                var stream = null;269 270                navigator.mediaDevices.getUserMedia({audio: true, video: false})271                    .then(function(s) {272                        stream = s;273                        mediaRecorder = new MediaRecorder(stream);274                        mediaRecorder.ondataavailable = function(e) {275                            chunks.push(e.data);276 277                            var blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });278                            var reader = new FileReader();279 280                            reader.onload = function(event) {281                                var buf = new Uint8Array(reader.result);282 283                                if (!context) {284                                    return;285                                }286                                context.decodeAudioData(buf.buffer, function(audioBuffer) {287                                    var offlineContext = new OfflineAudioContext(audioBuffer.numberOfChannels, audioBuffer.length, audioBuffer.sampleRate);288                                    var source = offlineContext.createBufferSource();289                                    source.buffer = audioBuffer;290                                    source.connect(offlineContext.destination);291                                    source.start(0);292 293                                    offlineContext.startRendering().then(function(renderedBuffer) {294                                        audio = renderedBuffer.getChannelData(0);295 296                                        //printTextarea('js: audio recorded, size: ' + audio.length + ', old size: ' + (audio0 == null ? 0 : audio0.length));297 298                                        var audioAll = new Float32Array(audio0 == null ? audio.length : audio0.length + audio.length);299                                        if (audio0 != null) {300                                            audioAll.set(audio0, 0);301                                        }302                                        audioAll.set(audio, audio0 == null ? 0 : audio0.length);303 304                                        if (instance) {305                                            Module.set_audio(instance, audioAll);306                                        }307                                    });308                                }, function(e) {309                                    audio = null;310                                });311                            }312 313                            reader.readAsArrayBuffer(blob);314                        };315 316                        mediaRecorder.onstop = function(e) {317                            if (doRecording) {318                                setTimeout(function() {319                                    startRecording();320                                });321                            }322                        };323 324                        mediaRecorder.start(kIntervalAudio_ms);325                    })326                    .catch(function(err) {327                        printTextarea('js: error getting audio stream: ' + err);328                    });329 330                var interval = setInterval(function() {331                    if (!doRecording) {332                        clearInterval(interval);333                        mediaRecorder.stop();334                        stream.getTracks().forEach(function(track) {335                            track.stop();336                        });337 338                        document.getElementById('start').disabled = false;339                        document.getElementById('stop').disabled  = true;340 341                        mediaRecorder = null;342                    }343 344                    // if audio length is more than kRestartRecording_s seconds, restart recording345                    if (audio != null && audio.length > kSampleRate*kRestartRecording_s) {346                        if (doRecording) {347                            //printTextarea('js: restarting recording');348 349                            clearInterval(interval);350                            audio0 = audio;351                            audio = null;352                            mediaRecorder.stop();353                            stream.getTracks().forEach(function(track) {354                                track.stop();355                            });356                        }357                    }358                }, 100);359            }360 361            //362            // main363            //364 365            var nLines = 0;366            var intervalUpdate = null;367            var transcribedAll = '';368 369            function onStart() {370                if (!instance) {371                    instance = Module.init('whisper.bin');372 373                    if (instance) {374                        printTextarea("js: whisper initialized, instance: " + instance);375                    }376                }377 378                if (!instance) {379                    printTextarea("js: failed to initialize whisper");380                    return;381                }382 383                startRecording();384 385                intervalUpdate = setInterval(function() {386                    var transcribed = Module.get_transcribed();387 388                    if (transcribed != null && transcribed.length > 1) {389                        transcribedAll += transcribed + '<br>';390                        nLines++;391 392                        // if more than 10 lines, remove the first line393                        if (nLines > 10) {394                            var i = transcribedAll.indexOf('<br>');395                            if (i > 0) {396                                transcribedAll = transcribedAll.substring(i + 4);397                                nLines--;398                            }399                        }400                    }401 402                    document.getElementById('state-status').innerHTML = Module.get_status();403                    document.getElementById('state-transcribed').innerHTML = transcribedAll;404                }, 100);405            }406 407            function onStop() {408                stopRecording();409            }410 411        </script>412        <script type="text/javascript" src="command.js"></script>413    </body>414</html>415