@sridhar-mani/whisper-web-transcriber 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.bundled.js +11 -1
- package/dist/index.bundled.min.js +1 -1
- package/dist/index.esm.js +11 -1
- package/dist/index.js +11 -1
- package/dist/index.min.js +1 -1
- package/package.json +1 -1
package/dist/index.bundled.js
CHANGED
|
@@ -91,7 +91,16 @@ Current Status:
|
|
|
91
91
|
return 'Cross-Origin Isolation is already enabled! No action needed.';
|
|
92
92
|
}
|
|
93
93
|
getScriptBasePath() {
|
|
94
|
-
|
|
94
|
+
var _a;
|
|
95
|
+
try {
|
|
96
|
+
const chromeRuntime = (_a = window.chrome) === null || _a === void 0 ? void 0 : _a.runtime;
|
|
97
|
+
if (chromeRuntime && typeof chromeRuntime.getURL === 'function') {
|
|
98
|
+
return chromeRuntime.getURL('whisper-assets/');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
// ignore and fall back to default
|
|
103
|
+
}
|
|
95
104
|
return '/src/';
|
|
96
105
|
}
|
|
97
106
|
async createWorkerFromURL(url) {
|
|
@@ -186,6 +195,7 @@ Current Status:
|
|
|
186
195
|
else {
|
|
187
196
|
// Load the WASM module dynamically
|
|
188
197
|
const script = document.createElement('script');
|
|
198
|
+
script.type = "text/javascript";
|
|
189
199
|
script.src = this.getScriptBasePath() + 'libstream.js';
|
|
190
200
|
script.onerror = () => reject(new Error('Failed to load WASM module'));
|
|
191
201
|
document.head.appendChild(script);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((e="undefined"!=typeof globalThis?globalThis:e||self).WhisperTranscriber={})}(this,(function(e){"use strict";class i{constructor(e={}){this.instance=null,this.mediaRecorder=null,this.audioContext=null,this.isRecording=!1,this.audio=null,this.audio0=null,this.Module=null,this.modelLoaded=!1,this.initPromise=null,this.config={modelUrl:e.modelUrl||i.MODEL_URLS[e.modelSize||"base-en-q5_1"],modelSize:e.modelSize||"base-en-q5_1",sampleRate:e.sampleRate||16e3,audioIntervalMs:e.audioIntervalMs||5e3,onTranscription:e.onTranscription||(()=>{}),onProgress:e.onProgress||(()=>{}),onStatus:e.onStatus||(()=>{}),debug:e.debug||!1},this.registerServiceWorkerIfNeeded()}log(e){this.config.debug&&console.log("[WhisperTranscriber]",e)}async registerServiceWorkerIfNeeded(){window.crossOriginIsolated||window.COI_SERVICEWORKER_CODE&&console.warn("[WhisperTranscriber] SharedArrayBuffer is not available. To enable it, you need to serve your site with COOP/COEP headers or use a service worker.\nYou can get the service worker code by calling: transcriber.getServiceWorkerCode()")}getServiceWorkerCode(){return window.COI_SERVICEWORKER_CODE?window.COI_SERVICEWORKER_CODE:null}getCrossOriginIsolationInstructions(){const e=this.getServiceWorkerCode();return window.crossOriginIsolated?"Cross-Origin Isolation is already enabled! No action needed.":`\nCross-Origin Isolation Setup Required\n=====================================\n\nWhisperTranscriber requires SharedArrayBuffer, which needs Cross-Origin Isolation.\n\nOption 1: Server Headers (Recommended)\n--------------------------------------\nConfigure your server to send these headers:\n Cross-Origin-Embedder-Policy: require-corp\n Cross-Origin-Opener-Policy: same-origin\n\nOption 2: Service Worker\n------------------------\n1. Save the following code as 'coi-serviceworker.js' in your website root:\n\n${e?"--- START SERVICE WORKER CODE ---\n"+e+"\n--- END SERVICE WORKER CODE ---":"[Service worker code not available]"}\n\n2. Register the service worker by adding this to your HTML:\n <script src="/coi-serviceworker.js"><\/script>\n\n3. Reload the page after registration.\n\nCurrent Status:\n- crossOriginIsolated: ${window.crossOriginIsolated}\n- SharedArrayBuffer available: ${"undefined"!=typeof SharedArrayBuffer}\n `.trim()}getScriptBasePath(){return"/src/"}async createWorkerFromURL(e){const i=await fetch(e),t=await i.text(),o=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(o);return new Worker(r)}async loadWasmModule(){if(window.LIBSTREAM_WORKER_CODE){this.log("Using inlined worker code");const e=new Blob([window.LIBSTREAM_WORKER_CODE],{type:"application/javascript"}),i=URL.createObjectURL(e);window.__whisperWorkerBlobUrl=i,this.log("Worker blob URL created from inlined code")}else{const e=this.getScriptBasePath()+"libstream.worker.js";try{const i=await fetch(e),t=await i.text(),o=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(o);window.__whisperWorkerBlobUrl=r,this.log("Worker script loaded and blob URL created")}catch(e){this.log("Failed to pre-fetch worker: "+e)}}return new Promise(((e,i)=>{if(window.Module={locateFile:e=>"libstream.worker.js"===e&&window.__whisperWorkerBlobUrl?window.__whisperWorkerBlobUrl:this.getScriptBasePath()+e,onRuntimeInitialized:()=>{this.log("WASM runtime initialized"),setTimeout((()=>{const t=window.Module;t?(this.Module=t,t.init||(t.init=t.cwrap("init","number",["string"])),t.set_audio||(t.set_audio=t.cwrap("set_audio","",["number","array"])),t.get_transcribed||(t.get_transcribed=t.cwrap("get_transcribed","string",[])),t.set_status||(t.set_status=t.cwrap("set_status","",["string"])),this.log("WASM module loaded and functions initialized"),e()):i(new Error("Module not available after runtime initialized"))}),100)}},window.LIBSTREAM_CODE){this.log("Using inlined libstream code");const e=new Blob([window.LIBSTREAM_CODE],{type:"application/javascript"}),t=URL.createObjectURL(e),o=document.createElement("script");o.src=t,o.onerror=()=>i(new Error("Failed to load WASM module")),document.head.appendChild(o)}else{const e=document.createElement("script");e.src=this.getScriptBasePath()+"libstream.js",e.onerror=()=>i(new Error("Failed to load WASM module")),document.head.appendChild(e)}}))}async loadHelpers(){if(window.HELPERS_CODE){this.log("Using inlined helpers code");const e=new Blob([window.HELPERS_CODE],{type:"application/javascript"}),i=URL.createObjectURL(e),t=document.createElement("script");return t.src=i,new Promise(((e,i)=>{t.onload=()=>e(),t.onerror=()=>i(new Error("Failed to load helpers")),document.head.appendChild(t)}))}{const e=document.createElement("script");return e.src=this.getScriptBasePath()+"helpers.js",new Promise(((i,t)=>{e.onload=()=>i(),e.onerror=()=>t(new Error("Failed to load helpers")),document.head.appendChild(e)}))}}async loadCOIServiceWorker(){if("undefined"!=typeof SharedArrayBuffer)return void this.log("SharedArrayBuffer already available");const e=this.getScriptBasePath(),i=document.createElement("script");return i.src=e+"coi-serviceworker.js",new Promise((e=>{i.onload=()=>{this.log("COI service worker loaded"),e()},i.onerror=()=>{this.log("Failed to load COI service worker - SharedArrayBuffer may not be available"),e()},document.head.appendChild(i)}))}async initialize(){return this.initPromise||(this.initPromise=(async()=>{try{await this.loadCOIServiceWorker(),window.dbVersion=1,window.dbName="whisper.transcriber.models",await this.loadHelpers(),this.log("Helpers loaded"),await this.loadWasmModule(),this.log("WASM module initialized"),this.config.onStatus("Ready to load model")}catch(e){throw this.log("Failed to initialize: "+e),e}})()),this.initPromise}async loadModel(){if(!this.modelLoaded)return await this.initialize(),new Promise(((e,t)=>{const o=this.config.modelUrl,r=i.MODEL_SIZES[this.config.modelSize];this.config.onStatus("Loading model...");window.loadRemote(o,"whisper.bin",r,(e=>{this.config.onProgress(Math.round(100*e))}),((i,t)=>{try{this.Module.FS_unlink(i)}catch(e){}this.Module.FS_createDataFile("/",i,t,!0,!0),this.log(`Model stored: ${i}, size: ${t.length}`),this.modelLoaded=!0,this.config.onStatus("Model loaded successfully"),e()}),(()=>{this.config.onStatus("Model loading cancelled"),t(new Error("Model loading cancelled"))}),(e=>{this.log(e)}))}));this.log("Model already loaded")}async startRecording(){if(!this.modelLoaded)throw new Error("Model not loaded. Call loadModel() first.");if(this.isRecording)return void this.log("Already recording");if(!this.instance){const e=this.Module.init||this.Module.cwrap("init","number",["string"]);if(this.instance=e("whisper.bin"),!this.instance)throw new Error("Failed to initialize Whisper");this.log("Whisper instance initialized")}this.audioContext=new AudioContext({sampleRate:this.config.sampleRate,channelCount:1,echoCancellation:!1,autoGainControl:!0,noiseSuppression:!0});(this.Module.set_status||this.Module.cwrap("set_status","",["string"]))(""),this.isRecording=!0,this.config.onStatus("Recording...");const e=[];try{const i=await navigator.mediaDevices.getUserMedia({audio:!0,video:!1});this.mediaRecorder=new MediaRecorder(i),this.mediaRecorder.ondataavailable=i=>{e.push(i.data);const t=new Blob(e,{type:"audio/ogg; codecs=opus"}),o=new FileReader;o.onload=e=>{const i=new Uint8Array(e.target.result);this.audioContext&&this.audioContext.decodeAudioData(i.buffer,(e=>{const i=new OfflineAudioContext(e.numberOfChannels,e.length,e.sampleRate),t=i.createBufferSource();t.buffer=e,t.connect(i.destination),t.start(0),i.startRendering().then((e=>{this.audio=e.getChannelData(0);const i=new Float32Array(null==this.audio0?this.audio.length:this.audio0.length+this.audio.length);if(null!=this.audio0&&i.set(this.audio0,0),i.set(this.audio,null==this.audio0?0:this.audio0.length),this.instance){(this.Module.set_audio||this.Module.cwrap("set_audio","",["number","array"]))(this.instance,i)}}))}))},o.readAsArrayBuffer(t)},this.mediaRecorder.onstop=()=>{this.isRecording&&setTimeout((()=>this.startRecording()),0)},this.mediaRecorder.start(this.config.audioIntervalMs),this.startTranscriptionPolling()}catch(e){throw this.isRecording=!1,this.config.onStatus("Error: "+e.message),e}}startTranscriptionPolling(){const e=setInterval((()=>{if(!this.isRecording)return void clearInterval(e);const i=(this.Module.get_transcribed||this.Module.cwrap("get_transcribed","string",[]))();null!=i&&i.length>1&&this.config.onTranscription(i)}),100)}stopRecording(){if(!this.isRecording)return void this.log("Not recording");(this.Module.set_status||this.Module.cwrap("set_status","",["string"]))("paused"),this.isRecording=!1,this.audio0=null,this.audio=null,this.mediaRecorder&&(this.mediaRecorder.stop(),this.mediaRecorder=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.config.onStatus("Stopped")}destroy(){this.stopRecording(),this.instance=null,this.Module=null,this.modelLoaded=!1}}i.MODEL_URLS={"tiny.en":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin","base.en":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin","tiny-en-q5_1":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en-q5_1.bin","base-en-q5_1":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en-q5_1.bin"},i.MODEL_SIZES={"tiny.en":75,"base.en":142,"tiny-en-q5_1":31,"base-en-q5_1":57},e.WhisperTranscriber=i}));
|
|
1
|
+
!function(e,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((e="undefined"!=typeof globalThis?globalThis:e||self).WhisperTranscriber={})}(this,(function(e){"use strict";class i{constructor(e={}){this.instance=null,this.mediaRecorder=null,this.audioContext=null,this.isRecording=!1,this.audio=null,this.audio0=null,this.Module=null,this.modelLoaded=!1,this.initPromise=null,this.config={modelUrl:e.modelUrl||i.MODEL_URLS[e.modelSize||"base-en-q5_1"],modelSize:e.modelSize||"base-en-q5_1",sampleRate:e.sampleRate||16e3,audioIntervalMs:e.audioIntervalMs||5e3,onTranscription:e.onTranscription||(()=>{}),onProgress:e.onProgress||(()=>{}),onStatus:e.onStatus||(()=>{}),debug:e.debug||!1},this.registerServiceWorkerIfNeeded()}log(e){this.config.debug&&console.log("[WhisperTranscriber]",e)}async registerServiceWorkerIfNeeded(){window.crossOriginIsolated||window.COI_SERVICEWORKER_CODE&&console.warn("[WhisperTranscriber] SharedArrayBuffer is not available. To enable it, you need to serve your site with COOP/COEP headers or use a service worker.\nYou can get the service worker code by calling: transcriber.getServiceWorkerCode()")}getServiceWorkerCode(){return window.COI_SERVICEWORKER_CODE?window.COI_SERVICEWORKER_CODE:null}getCrossOriginIsolationInstructions(){const e=this.getServiceWorkerCode();return window.crossOriginIsolated?"Cross-Origin Isolation is already enabled! No action needed.":`\nCross-Origin Isolation Setup Required\n=====================================\n\nWhisperTranscriber requires SharedArrayBuffer, which needs Cross-Origin Isolation.\n\nOption 1: Server Headers (Recommended)\n--------------------------------------\nConfigure your server to send these headers:\n Cross-Origin-Embedder-Policy: require-corp\n Cross-Origin-Opener-Policy: same-origin\n\nOption 2: Service Worker\n------------------------\n1. Save the following code as 'coi-serviceworker.js' in your website root:\n\n${e?"--- START SERVICE WORKER CODE ---\n"+e+"\n--- END SERVICE WORKER CODE ---":"[Service worker code not available]"}\n\n2. Register the service worker by adding this to your HTML:\n <script src="/coi-serviceworker.js"><\/script>\n\n3. Reload the page after registration.\n\nCurrent Status:\n- crossOriginIsolated: ${window.crossOriginIsolated}\n- SharedArrayBuffer available: ${"undefined"!=typeof SharedArrayBuffer}\n `.trim()}getScriptBasePath(){var e;try{const i=null===(e=window.chrome)||void 0===e?void 0:e.runtime;if(i&&"function"==typeof i.getURL)return i.getURL("whisper-assets/")}catch(e){}return"/src/"}async createWorkerFromURL(e){const i=await fetch(e),t=await i.text(),o=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(o);return new Worker(r)}async loadWasmModule(){if(window.LIBSTREAM_WORKER_CODE){this.log("Using inlined worker code");const e=new Blob([window.LIBSTREAM_WORKER_CODE],{type:"application/javascript"}),i=URL.createObjectURL(e);window.__whisperWorkerBlobUrl=i,this.log("Worker blob URL created from inlined code")}else{const e=this.getScriptBasePath()+"libstream.worker.js";try{const i=await fetch(e),t=await i.text(),o=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(o);window.__whisperWorkerBlobUrl=r,this.log("Worker script loaded and blob URL created")}catch(e){this.log("Failed to pre-fetch worker: "+e)}}return new Promise(((e,i)=>{if(window.Module={locateFile:e=>"libstream.worker.js"===e&&window.__whisperWorkerBlobUrl?window.__whisperWorkerBlobUrl:this.getScriptBasePath()+e,onRuntimeInitialized:()=>{this.log("WASM runtime initialized"),setTimeout((()=>{const t=window.Module;t?(this.Module=t,t.init||(t.init=t.cwrap("init","number",["string"])),t.set_audio||(t.set_audio=t.cwrap("set_audio","",["number","array"])),t.get_transcribed||(t.get_transcribed=t.cwrap("get_transcribed","string",[])),t.set_status||(t.set_status=t.cwrap("set_status","",["string"])),this.log("WASM module loaded and functions initialized"),e()):i(new Error("Module not available after runtime initialized"))}),100)}},window.LIBSTREAM_CODE){this.log("Using inlined libstream code");const e=new Blob([window.LIBSTREAM_CODE],{type:"application/javascript"}),t=URL.createObjectURL(e),o=document.createElement("script");o.src=t,o.onerror=()=>i(new Error("Failed to load WASM module")),document.head.appendChild(o)}else{const e=document.createElement("script");e.type="text/javascript",e.src=this.getScriptBasePath()+"libstream.js",e.onerror=()=>i(new Error("Failed to load WASM module")),document.head.appendChild(e)}}))}async loadHelpers(){if(window.HELPERS_CODE){this.log("Using inlined helpers code");const e=new Blob([window.HELPERS_CODE],{type:"application/javascript"}),i=URL.createObjectURL(e),t=document.createElement("script");return t.src=i,new Promise(((e,i)=>{t.onload=()=>e(),t.onerror=()=>i(new Error("Failed to load helpers")),document.head.appendChild(t)}))}{const e=document.createElement("script");return e.src=this.getScriptBasePath()+"helpers.js",new Promise(((i,t)=>{e.onload=()=>i(),e.onerror=()=>t(new Error("Failed to load helpers")),document.head.appendChild(e)}))}}async loadCOIServiceWorker(){if("undefined"!=typeof SharedArrayBuffer)return void this.log("SharedArrayBuffer already available");const e=this.getScriptBasePath(),i=document.createElement("script");return i.src=e+"coi-serviceworker.js",new Promise((e=>{i.onload=()=>{this.log("COI service worker loaded"),e()},i.onerror=()=>{this.log("Failed to load COI service worker - SharedArrayBuffer may not be available"),e()},document.head.appendChild(i)}))}async initialize(){return this.initPromise||(this.initPromise=(async()=>{try{await this.loadCOIServiceWorker(),window.dbVersion=1,window.dbName="whisper.transcriber.models",await this.loadHelpers(),this.log("Helpers loaded"),await this.loadWasmModule(),this.log("WASM module initialized"),this.config.onStatus("Ready to load model")}catch(e){throw this.log("Failed to initialize: "+e),e}})()),this.initPromise}async loadModel(){if(!this.modelLoaded)return await this.initialize(),new Promise(((e,t)=>{const o=this.config.modelUrl,r=i.MODEL_SIZES[this.config.modelSize];this.config.onStatus("Loading model...");window.loadRemote(o,"whisper.bin",r,(e=>{this.config.onProgress(Math.round(100*e))}),((i,t)=>{try{this.Module.FS_unlink(i)}catch(e){}this.Module.FS_createDataFile("/",i,t,!0,!0),this.log(`Model stored: ${i}, size: ${t.length}`),this.modelLoaded=!0,this.config.onStatus("Model loaded successfully"),e()}),(()=>{this.config.onStatus("Model loading cancelled"),t(new Error("Model loading cancelled"))}),(e=>{this.log(e)}))}));this.log("Model already loaded")}async startRecording(){if(!this.modelLoaded)throw new Error("Model not loaded. Call loadModel() first.");if(this.isRecording)return void this.log("Already recording");if(!this.instance){const e=this.Module.init||this.Module.cwrap("init","number",["string"]);if(this.instance=e("whisper.bin"),!this.instance)throw new Error("Failed to initialize Whisper");this.log("Whisper instance initialized")}this.audioContext=new AudioContext({sampleRate:this.config.sampleRate,channelCount:1,echoCancellation:!1,autoGainControl:!0,noiseSuppression:!0});(this.Module.set_status||this.Module.cwrap("set_status","",["string"]))(""),this.isRecording=!0,this.config.onStatus("Recording...");const e=[];try{const i=await navigator.mediaDevices.getUserMedia({audio:!0,video:!1});this.mediaRecorder=new MediaRecorder(i),this.mediaRecorder.ondataavailable=i=>{e.push(i.data);const t=new Blob(e,{type:"audio/ogg; codecs=opus"}),o=new FileReader;o.onload=e=>{const i=new Uint8Array(e.target.result);this.audioContext&&this.audioContext.decodeAudioData(i.buffer,(e=>{const i=new OfflineAudioContext(e.numberOfChannels,e.length,e.sampleRate),t=i.createBufferSource();t.buffer=e,t.connect(i.destination),t.start(0),i.startRendering().then((e=>{this.audio=e.getChannelData(0);const i=new Float32Array(null==this.audio0?this.audio.length:this.audio0.length+this.audio.length);if(null!=this.audio0&&i.set(this.audio0,0),i.set(this.audio,null==this.audio0?0:this.audio0.length),this.instance){(this.Module.set_audio||this.Module.cwrap("set_audio","",["number","array"]))(this.instance,i)}}))}))},o.readAsArrayBuffer(t)},this.mediaRecorder.onstop=()=>{this.isRecording&&setTimeout((()=>this.startRecording()),0)},this.mediaRecorder.start(this.config.audioIntervalMs),this.startTranscriptionPolling()}catch(e){throw this.isRecording=!1,this.config.onStatus("Error: "+e.message),e}}startTranscriptionPolling(){const e=setInterval((()=>{if(!this.isRecording)return void clearInterval(e);const i=(this.Module.get_transcribed||this.Module.cwrap("get_transcribed","string",[]))();null!=i&&i.length>1&&this.config.onTranscription(i)}),100)}stopRecording(){if(!this.isRecording)return void this.log("Not recording");(this.Module.set_status||this.Module.cwrap("set_status","",["string"]))("paused"),this.isRecording=!1,this.audio0=null,this.audio=null,this.mediaRecorder&&(this.mediaRecorder.stop(),this.mediaRecorder=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.config.onStatus("Stopped")}destroy(){this.stopRecording(),this.instance=null,this.Module=null,this.modelLoaded=!1}}i.MODEL_URLS={"tiny.en":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin","base.en":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin","tiny-en-q5_1":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en-q5_1.bin","base-en-q5_1":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en-q5_1.bin"},i.MODEL_SIZES={"tiny.en":75,"base.en":142,"tiny-en-q5_1":31,"base-en-q5_1":57},e.WhisperTranscriber=i}));
|
package/dist/index.esm.js
CHANGED
|
@@ -85,7 +85,16 @@ Current Status:
|
|
|
85
85
|
return 'Cross-Origin Isolation is already enabled! No action needed.';
|
|
86
86
|
}
|
|
87
87
|
getScriptBasePath() {
|
|
88
|
-
|
|
88
|
+
var _a;
|
|
89
|
+
try {
|
|
90
|
+
const chromeRuntime = (_a = window.chrome) === null || _a === void 0 ? void 0 : _a.runtime;
|
|
91
|
+
if (chromeRuntime && typeof chromeRuntime.getURL === 'function') {
|
|
92
|
+
return chromeRuntime.getURL('whisper-assets/');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
// ignore and fall back to default
|
|
97
|
+
}
|
|
89
98
|
return '/src/';
|
|
90
99
|
}
|
|
91
100
|
async createWorkerFromURL(url) {
|
|
@@ -180,6 +189,7 @@ Current Status:
|
|
|
180
189
|
else {
|
|
181
190
|
// Load the WASM module dynamically
|
|
182
191
|
const script = document.createElement('script');
|
|
192
|
+
script.type = "text/javascript";
|
|
183
193
|
script.src = this.getScriptBasePath() + 'libstream.js';
|
|
184
194
|
script.onerror = () => reject(new Error('Failed to load WASM module'));
|
|
185
195
|
document.head.appendChild(script);
|
package/dist/index.js
CHANGED
|
@@ -91,7 +91,16 @@ Current Status:
|
|
|
91
91
|
return 'Cross-Origin Isolation is already enabled! No action needed.';
|
|
92
92
|
}
|
|
93
93
|
getScriptBasePath() {
|
|
94
|
-
|
|
94
|
+
var _a;
|
|
95
|
+
try {
|
|
96
|
+
const chromeRuntime = (_a = window.chrome) === null || _a === void 0 ? void 0 : _a.runtime;
|
|
97
|
+
if (chromeRuntime && typeof chromeRuntime.getURL === 'function') {
|
|
98
|
+
return chromeRuntime.getURL('whisper-assets/');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
// ignore and fall back to default
|
|
103
|
+
}
|
|
95
104
|
return '/src/';
|
|
96
105
|
}
|
|
97
106
|
async createWorkerFromURL(url) {
|
|
@@ -186,6 +195,7 @@ Current Status:
|
|
|
186
195
|
else {
|
|
187
196
|
// Load the WASM module dynamically
|
|
188
197
|
const script = document.createElement('script');
|
|
198
|
+
script.type = "text/javascript";
|
|
189
199
|
script.src = this.getScriptBasePath() + 'libstream.js';
|
|
190
200
|
script.onerror = () => reject(new Error('Failed to load WASM module'));
|
|
191
201
|
document.head.appendChild(script);
|
package/dist/index.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((e="undefined"!=typeof globalThis?globalThis:e||self).WhisperTranscriber={})}(this,(function(e){"use strict";class i{constructor(e={}){this.instance=null,this.mediaRecorder=null,this.audioContext=null,this.isRecording=!1,this.audio=null,this.audio0=null,this.Module=null,this.modelLoaded=!1,this.initPromise=null,this.config={modelUrl:e.modelUrl||i.MODEL_URLS[e.modelSize||"base-en-q5_1"],modelSize:e.modelSize||"base-en-q5_1",sampleRate:e.sampleRate||16e3,audioIntervalMs:e.audioIntervalMs||5e3,onTranscription:e.onTranscription||(()=>{}),onProgress:e.onProgress||(()=>{}),onStatus:e.onStatus||(()=>{}),debug:e.debug||!1},this.registerServiceWorkerIfNeeded()}log(e){this.config.debug&&console.log("[WhisperTranscriber]",e)}async registerServiceWorkerIfNeeded(){window.crossOriginIsolated||window.COI_SERVICEWORKER_CODE&&console.warn("[WhisperTranscriber] SharedArrayBuffer is not available. To enable it, you need to serve your site with COOP/COEP headers or use a service worker.\nYou can get the service worker code by calling: transcriber.getServiceWorkerCode()")}getServiceWorkerCode(){return window.COI_SERVICEWORKER_CODE?window.COI_SERVICEWORKER_CODE:null}getCrossOriginIsolationInstructions(){const e=this.getServiceWorkerCode();return window.crossOriginIsolated?"Cross-Origin Isolation is already enabled! No action needed.":`\nCross-Origin Isolation Setup Required\n=====================================\n\nWhisperTranscriber requires SharedArrayBuffer, which needs Cross-Origin Isolation.\n\nOption 1: Server Headers (Recommended)\n--------------------------------------\nConfigure your server to send these headers:\n Cross-Origin-Embedder-Policy: require-corp\n Cross-Origin-Opener-Policy: same-origin\n\nOption 2: Service Worker\n------------------------\n1. Save the following code as 'coi-serviceworker.js' in your website root:\n\n${e?"--- START SERVICE WORKER CODE ---\n"+e+"\n--- END SERVICE WORKER CODE ---":"[Service worker code not available]"}\n\n2. Register the service worker by adding this to your HTML:\n <script src="/coi-serviceworker.js"><\/script>\n\n3. Reload the page after registration.\n\nCurrent Status:\n- crossOriginIsolated: ${window.crossOriginIsolated}\n- SharedArrayBuffer available: ${"undefined"!=typeof SharedArrayBuffer}\n `.trim()}getScriptBasePath(){return"/src/"}async createWorkerFromURL(e){const i=await fetch(e),t=await i.text(),o=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(o);return new Worker(r)}async loadWasmModule(){if(window.LIBSTREAM_WORKER_CODE){this.log("Using inlined worker code");const e=new Blob([window.LIBSTREAM_WORKER_CODE],{type:"application/javascript"}),i=URL.createObjectURL(e);window.__whisperWorkerBlobUrl=i,this.log("Worker blob URL created from inlined code")}else{const e=this.getScriptBasePath()+"libstream.worker.js";try{const i=await fetch(e),t=await i.text(),o=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(o);window.__whisperWorkerBlobUrl=r,this.log("Worker script loaded and blob URL created")}catch(e){this.log("Failed to pre-fetch worker: "+e)}}return new Promise(((e,i)=>{if(window.Module={locateFile:e=>"libstream.worker.js"===e&&window.__whisperWorkerBlobUrl?window.__whisperWorkerBlobUrl:this.getScriptBasePath()+e,onRuntimeInitialized:()=>{this.log("WASM runtime initialized"),setTimeout((()=>{const t=window.Module;t?(this.Module=t,t.init||(t.init=t.cwrap("init","number",["string"])),t.set_audio||(t.set_audio=t.cwrap("set_audio","",["number","array"])),t.get_transcribed||(t.get_transcribed=t.cwrap("get_transcribed","string",[])),t.set_status||(t.set_status=t.cwrap("set_status","",["string"])),this.log("WASM module loaded and functions initialized"),e()):i(new Error("Module not available after runtime initialized"))}),100)}},window.LIBSTREAM_CODE){this.log("Using inlined libstream code");const e=new Blob([window.LIBSTREAM_CODE],{type:"application/javascript"}),t=URL.createObjectURL(e),o=document.createElement("script");o.src=t,o.onerror=()=>i(new Error("Failed to load WASM module")),document.head.appendChild(o)}else{const e=document.createElement("script");e.src=this.getScriptBasePath()+"libstream.js",e.onerror=()=>i(new Error("Failed to load WASM module")),document.head.appendChild(e)}}))}async loadHelpers(){if(window.HELPERS_CODE){this.log("Using inlined helpers code");const e=new Blob([window.HELPERS_CODE],{type:"application/javascript"}),i=URL.createObjectURL(e),t=document.createElement("script");return t.src=i,new Promise(((e,i)=>{t.onload=()=>e(),t.onerror=()=>i(new Error("Failed to load helpers")),document.head.appendChild(t)}))}{const e=document.createElement("script");return e.src=this.getScriptBasePath()+"helpers.js",new Promise(((i,t)=>{e.onload=()=>i(),e.onerror=()=>t(new Error("Failed to load helpers")),document.head.appendChild(e)}))}}async loadCOIServiceWorker(){if("undefined"!=typeof SharedArrayBuffer)return void this.log("SharedArrayBuffer already available");const e=this.getScriptBasePath(),i=document.createElement("script");return i.src=e+"coi-serviceworker.js",new Promise((e=>{i.onload=()=>{this.log("COI service worker loaded"),e()},i.onerror=()=>{this.log("Failed to load COI service worker - SharedArrayBuffer may not be available"),e()},document.head.appendChild(i)}))}async initialize(){return this.initPromise||(this.initPromise=(async()=>{try{await this.loadCOIServiceWorker(),window.dbVersion=1,window.dbName="whisper.transcriber.models",await this.loadHelpers(),this.log("Helpers loaded"),await this.loadWasmModule(),this.log("WASM module initialized"),this.config.onStatus("Ready to load model")}catch(e){throw this.log("Failed to initialize: "+e),e}})()),this.initPromise}async loadModel(){if(!this.modelLoaded)return await this.initialize(),new Promise(((e,t)=>{const o=this.config.modelUrl,r=i.MODEL_SIZES[this.config.modelSize];this.config.onStatus("Loading model...");window.loadRemote(o,"whisper.bin",r,(e=>{this.config.onProgress(Math.round(100*e))}),((i,t)=>{try{this.Module.FS_unlink(i)}catch(e){}this.Module.FS_createDataFile("/",i,t,!0,!0),this.log(`Model stored: ${i}, size: ${t.length}`),this.modelLoaded=!0,this.config.onStatus("Model loaded successfully"),e()}),(()=>{this.config.onStatus("Model loading cancelled"),t(new Error("Model loading cancelled"))}),(e=>{this.log(e)}))}));this.log("Model already loaded")}async startRecording(){if(!this.modelLoaded)throw new Error("Model not loaded. Call loadModel() first.");if(this.isRecording)return void this.log("Already recording");if(!this.instance){const e=this.Module.init||this.Module.cwrap("init","number",["string"]);if(this.instance=e("whisper.bin"),!this.instance)throw new Error("Failed to initialize Whisper");this.log("Whisper instance initialized")}this.audioContext=new AudioContext({sampleRate:this.config.sampleRate,channelCount:1,echoCancellation:!1,autoGainControl:!0,noiseSuppression:!0});(this.Module.set_status||this.Module.cwrap("set_status","",["string"]))(""),this.isRecording=!0,this.config.onStatus("Recording...");const e=[];try{const i=await navigator.mediaDevices.getUserMedia({audio:!0,video:!1});this.mediaRecorder=new MediaRecorder(i),this.mediaRecorder.ondataavailable=i=>{e.push(i.data);const t=new Blob(e,{type:"audio/ogg; codecs=opus"}),o=new FileReader;o.onload=e=>{const i=new Uint8Array(e.target.result);this.audioContext&&this.audioContext.decodeAudioData(i.buffer,(e=>{const i=new OfflineAudioContext(e.numberOfChannels,e.length,e.sampleRate),t=i.createBufferSource();t.buffer=e,t.connect(i.destination),t.start(0),i.startRendering().then((e=>{this.audio=e.getChannelData(0);const i=new Float32Array(null==this.audio0?this.audio.length:this.audio0.length+this.audio.length);if(null!=this.audio0&&i.set(this.audio0,0),i.set(this.audio,null==this.audio0?0:this.audio0.length),this.instance){(this.Module.set_audio||this.Module.cwrap("set_audio","",["number","array"]))(this.instance,i)}}))}))},o.readAsArrayBuffer(t)},this.mediaRecorder.onstop=()=>{this.isRecording&&setTimeout((()=>this.startRecording()),0)},this.mediaRecorder.start(this.config.audioIntervalMs),this.startTranscriptionPolling()}catch(e){throw this.isRecording=!1,this.config.onStatus("Error: "+e.message),e}}startTranscriptionPolling(){const e=setInterval((()=>{if(!this.isRecording)return void clearInterval(e);const i=(this.Module.get_transcribed||this.Module.cwrap("get_transcribed","string",[]))();null!=i&&i.length>1&&this.config.onTranscription(i)}),100)}stopRecording(){if(!this.isRecording)return void this.log("Not recording");(this.Module.set_status||this.Module.cwrap("set_status","",["string"]))("paused"),this.isRecording=!1,this.audio0=null,this.audio=null,this.mediaRecorder&&(this.mediaRecorder.stop(),this.mediaRecorder=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.config.onStatus("Stopped")}destroy(){this.stopRecording(),this.instance=null,this.Module=null,this.modelLoaded=!1}}i.MODEL_URLS={"tiny.en":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin","base.en":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin","tiny-en-q5_1":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en-q5_1.bin","base-en-q5_1":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en-q5_1.bin"},i.MODEL_SIZES={"tiny.en":75,"base.en":142,"tiny-en-q5_1":31,"base-en-q5_1":57},e.WhisperTranscriber=i}));
|
|
1
|
+
!function(e,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((e="undefined"!=typeof globalThis?globalThis:e||self).WhisperTranscriber={})}(this,(function(e){"use strict";class i{constructor(e={}){this.instance=null,this.mediaRecorder=null,this.audioContext=null,this.isRecording=!1,this.audio=null,this.audio0=null,this.Module=null,this.modelLoaded=!1,this.initPromise=null,this.config={modelUrl:e.modelUrl||i.MODEL_URLS[e.modelSize||"base-en-q5_1"],modelSize:e.modelSize||"base-en-q5_1",sampleRate:e.sampleRate||16e3,audioIntervalMs:e.audioIntervalMs||5e3,onTranscription:e.onTranscription||(()=>{}),onProgress:e.onProgress||(()=>{}),onStatus:e.onStatus||(()=>{}),debug:e.debug||!1},this.registerServiceWorkerIfNeeded()}log(e){this.config.debug&&console.log("[WhisperTranscriber]",e)}async registerServiceWorkerIfNeeded(){window.crossOriginIsolated||window.COI_SERVICEWORKER_CODE&&console.warn("[WhisperTranscriber] SharedArrayBuffer is not available. To enable it, you need to serve your site with COOP/COEP headers or use a service worker.\nYou can get the service worker code by calling: transcriber.getServiceWorkerCode()")}getServiceWorkerCode(){return window.COI_SERVICEWORKER_CODE?window.COI_SERVICEWORKER_CODE:null}getCrossOriginIsolationInstructions(){const e=this.getServiceWorkerCode();return window.crossOriginIsolated?"Cross-Origin Isolation is already enabled! No action needed.":`\nCross-Origin Isolation Setup Required\n=====================================\n\nWhisperTranscriber requires SharedArrayBuffer, which needs Cross-Origin Isolation.\n\nOption 1: Server Headers (Recommended)\n--------------------------------------\nConfigure your server to send these headers:\n Cross-Origin-Embedder-Policy: require-corp\n Cross-Origin-Opener-Policy: same-origin\n\nOption 2: Service Worker\n------------------------\n1. Save the following code as 'coi-serviceworker.js' in your website root:\n\n${e?"--- START SERVICE WORKER CODE ---\n"+e+"\n--- END SERVICE WORKER CODE ---":"[Service worker code not available]"}\n\n2. Register the service worker by adding this to your HTML:\n <script src="/coi-serviceworker.js"><\/script>\n\n3. Reload the page after registration.\n\nCurrent Status:\n- crossOriginIsolated: ${window.crossOriginIsolated}\n- SharedArrayBuffer available: ${"undefined"!=typeof SharedArrayBuffer}\n `.trim()}getScriptBasePath(){var e;try{const i=null===(e=window.chrome)||void 0===e?void 0:e.runtime;if(i&&"function"==typeof i.getURL)return i.getURL("whisper-assets/")}catch(e){}return"/src/"}async createWorkerFromURL(e){const i=await fetch(e),t=await i.text(),o=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(o);return new Worker(r)}async loadWasmModule(){if(window.LIBSTREAM_WORKER_CODE){this.log("Using inlined worker code");const e=new Blob([window.LIBSTREAM_WORKER_CODE],{type:"application/javascript"}),i=URL.createObjectURL(e);window.__whisperWorkerBlobUrl=i,this.log("Worker blob URL created from inlined code")}else{const e=this.getScriptBasePath()+"libstream.worker.js";try{const i=await fetch(e),t=await i.text(),o=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(o);window.__whisperWorkerBlobUrl=r,this.log("Worker script loaded and blob URL created")}catch(e){this.log("Failed to pre-fetch worker: "+e)}}return new Promise(((e,i)=>{if(window.Module={locateFile:e=>"libstream.worker.js"===e&&window.__whisperWorkerBlobUrl?window.__whisperWorkerBlobUrl:this.getScriptBasePath()+e,onRuntimeInitialized:()=>{this.log("WASM runtime initialized"),setTimeout((()=>{const t=window.Module;t?(this.Module=t,t.init||(t.init=t.cwrap("init","number",["string"])),t.set_audio||(t.set_audio=t.cwrap("set_audio","",["number","array"])),t.get_transcribed||(t.get_transcribed=t.cwrap("get_transcribed","string",[])),t.set_status||(t.set_status=t.cwrap("set_status","",["string"])),this.log("WASM module loaded and functions initialized"),e()):i(new Error("Module not available after runtime initialized"))}),100)}},window.LIBSTREAM_CODE){this.log("Using inlined libstream code");const e=new Blob([window.LIBSTREAM_CODE],{type:"application/javascript"}),t=URL.createObjectURL(e),o=document.createElement("script");o.src=t,o.onerror=()=>i(new Error("Failed to load WASM module")),document.head.appendChild(o)}else{const e=document.createElement("script");e.type="text/javascript",e.src=this.getScriptBasePath()+"libstream.js",e.onerror=()=>i(new Error("Failed to load WASM module")),document.head.appendChild(e)}}))}async loadHelpers(){if(window.HELPERS_CODE){this.log("Using inlined helpers code");const e=new Blob([window.HELPERS_CODE],{type:"application/javascript"}),i=URL.createObjectURL(e),t=document.createElement("script");return t.src=i,new Promise(((e,i)=>{t.onload=()=>e(),t.onerror=()=>i(new Error("Failed to load helpers")),document.head.appendChild(t)}))}{const e=document.createElement("script");return e.src=this.getScriptBasePath()+"helpers.js",new Promise(((i,t)=>{e.onload=()=>i(),e.onerror=()=>t(new Error("Failed to load helpers")),document.head.appendChild(e)}))}}async loadCOIServiceWorker(){if("undefined"!=typeof SharedArrayBuffer)return void this.log("SharedArrayBuffer already available");const e=this.getScriptBasePath(),i=document.createElement("script");return i.src=e+"coi-serviceworker.js",new Promise((e=>{i.onload=()=>{this.log("COI service worker loaded"),e()},i.onerror=()=>{this.log("Failed to load COI service worker - SharedArrayBuffer may not be available"),e()},document.head.appendChild(i)}))}async initialize(){return this.initPromise||(this.initPromise=(async()=>{try{await this.loadCOIServiceWorker(),window.dbVersion=1,window.dbName="whisper.transcriber.models",await this.loadHelpers(),this.log("Helpers loaded"),await this.loadWasmModule(),this.log("WASM module initialized"),this.config.onStatus("Ready to load model")}catch(e){throw this.log("Failed to initialize: "+e),e}})()),this.initPromise}async loadModel(){if(!this.modelLoaded)return await this.initialize(),new Promise(((e,t)=>{const o=this.config.modelUrl,r=i.MODEL_SIZES[this.config.modelSize];this.config.onStatus("Loading model...");window.loadRemote(o,"whisper.bin",r,(e=>{this.config.onProgress(Math.round(100*e))}),((i,t)=>{try{this.Module.FS_unlink(i)}catch(e){}this.Module.FS_createDataFile("/",i,t,!0,!0),this.log(`Model stored: ${i}, size: ${t.length}`),this.modelLoaded=!0,this.config.onStatus("Model loaded successfully"),e()}),(()=>{this.config.onStatus("Model loading cancelled"),t(new Error("Model loading cancelled"))}),(e=>{this.log(e)}))}));this.log("Model already loaded")}async startRecording(){if(!this.modelLoaded)throw new Error("Model not loaded. Call loadModel() first.");if(this.isRecording)return void this.log("Already recording");if(!this.instance){const e=this.Module.init||this.Module.cwrap("init","number",["string"]);if(this.instance=e("whisper.bin"),!this.instance)throw new Error("Failed to initialize Whisper");this.log("Whisper instance initialized")}this.audioContext=new AudioContext({sampleRate:this.config.sampleRate,channelCount:1,echoCancellation:!1,autoGainControl:!0,noiseSuppression:!0});(this.Module.set_status||this.Module.cwrap("set_status","",["string"]))(""),this.isRecording=!0,this.config.onStatus("Recording...");const e=[];try{const i=await navigator.mediaDevices.getUserMedia({audio:!0,video:!1});this.mediaRecorder=new MediaRecorder(i),this.mediaRecorder.ondataavailable=i=>{e.push(i.data);const t=new Blob(e,{type:"audio/ogg; codecs=opus"}),o=new FileReader;o.onload=e=>{const i=new Uint8Array(e.target.result);this.audioContext&&this.audioContext.decodeAudioData(i.buffer,(e=>{const i=new OfflineAudioContext(e.numberOfChannels,e.length,e.sampleRate),t=i.createBufferSource();t.buffer=e,t.connect(i.destination),t.start(0),i.startRendering().then((e=>{this.audio=e.getChannelData(0);const i=new Float32Array(null==this.audio0?this.audio.length:this.audio0.length+this.audio.length);if(null!=this.audio0&&i.set(this.audio0,0),i.set(this.audio,null==this.audio0?0:this.audio0.length),this.instance){(this.Module.set_audio||this.Module.cwrap("set_audio","",["number","array"]))(this.instance,i)}}))}))},o.readAsArrayBuffer(t)},this.mediaRecorder.onstop=()=>{this.isRecording&&setTimeout((()=>this.startRecording()),0)},this.mediaRecorder.start(this.config.audioIntervalMs),this.startTranscriptionPolling()}catch(e){throw this.isRecording=!1,this.config.onStatus("Error: "+e.message),e}}startTranscriptionPolling(){const e=setInterval((()=>{if(!this.isRecording)return void clearInterval(e);const i=(this.Module.get_transcribed||this.Module.cwrap("get_transcribed","string",[]))();null!=i&&i.length>1&&this.config.onTranscription(i)}),100)}stopRecording(){if(!this.isRecording)return void this.log("Not recording");(this.Module.set_status||this.Module.cwrap("set_status","",["string"]))("paused"),this.isRecording=!1,this.audio0=null,this.audio=null,this.mediaRecorder&&(this.mediaRecorder.stop(),this.mediaRecorder=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.config.onStatus("Stopped")}destroy(){this.stopRecording(),this.instance=null,this.Module=null,this.modelLoaded=!1}}i.MODEL_URLS={"tiny.en":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin","base.en":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin","tiny-en-q5_1":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en-q5_1.bin","base-en-q5_1":"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en-q5_1.bin"},i.MODEL_SIZES={"tiny.en":75,"base.en":142,"tiny-en-q5_1":31,"base-en-q5_1":57},e.WhisperTranscriber=i}));
|
package/package.json
CHANGED