@timur00kh/whisper.wasm 0.1.0 → 0.1.1-beta.whisper.cpp-v1.9.1
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/README.md +2 -2
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +1 -1
- package/dist/index.umd.js +9 -9
- package/dist/libmain-BRsjb_5x.mjs +2198 -0
- package/dist/libmain-BZ9NDZ1A.js +13 -0
- package/package.json +5 -5
- package/dist/libmain-CWYJvMY5.js +0 -13
- package/dist/libmain-D9-QM3iM.mjs +0 -2198
package/README.md
CHANGED
|
@@ -344,7 +344,7 @@ Use `skip-changelog` to exclude a PR from the generated notes.
|
|
|
344
344
|
|
|
345
345
|
### Prerequisites
|
|
346
346
|
|
|
347
|
-
- Node.js
|
|
347
|
+
- Node.js 20+
|
|
348
348
|
- npm or yarn
|
|
349
349
|
|
|
350
350
|
### Setup
|
|
@@ -380,7 +380,7 @@ MIT
|
|
|
380
380
|
|
|
381
381
|
## Acknowledgments
|
|
382
382
|
|
|
383
|
-
- [whisper.cpp](https://github.com/
|
|
383
|
+
- [whisper.cpp](https://github.com/ggml-org/whisper.cpp) - High-performance C++ implementation of Whisper
|
|
384
384
|
- [OpenAI Whisper](https://github.com/openai/whisper) - The original speech recognition model
|
|
385
385
|
- [Emscripten](https://emscripten.org/) - WebAssembly compilation toolkit
|
|
386
386
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const M=class M{constructor(t=M.levels.INFO,e=""){this.level=t,this.prefix=e}debug(...t){this.level<=M.levels.DEBUG&&console.debug(`[${this.prefix}] [DEBUG]`,...t)}info(...t){this.level<=M.levels.INFO&&console.info(`[${this.prefix}] [INFO]`,...t)}warn(...t){this.level<=M.levels.WARN&&console.warn(`[${this.prefix}] [WARN]`,...t)}error(...t){this.level<=M.levels.ERROR&&console.error(`[${this.prefix}] [ERROR]`,...t)}setLevel(t){this.level=t}getLevel(){return this.level}};M.levels={DEBUG:0,INFO:1,WARN:2,ERROR:3};let y=M;const L=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11])),W={language:"auto",threads:4,translate:!1};function F(n){const t=String(n).trim().replace(",","."),e=t.split(":").map(Number);if(e.some(Number.isNaN))throw new Error(`Bad time: "${n}"`);let r=0,o=0,i=0;if(e.length===3)[r,o]=e,i=parseFloat(t.split(":").pop()||"0");else if(e.length===2)[o]=e,i=parseFloat(t.split(":").pop()||"0");else throw new Error(`Bad time format: "${n}"`);return Math.floor(((r*60+o)*60+i)*1e3)}function D(n){const e=/^\s*\[?\s*([0-9]{1,2}:[0-9]{2}:(?:[0-9]{2}[.,][0-9]{1,3})|[0-9]{1,2}:[0-9]{2}[.,][0-9]{1,3})\s*-->\s*([0-9]{1,2}:[0-9]{2}:(?:[0-9]{2}[.,][0-9]{1,3})|[0-9]{1,2}:[0-9]{2}[.,][0-9]{1,3})\s*\]?\s*(.*)\s*$/.exec(n);if(!e)throw new Error("Line does not match VTT-like pattern: "+n);const r=e[1],o=e[2],i=e[3]||"",s=F(r),a=F(o);if(a<s)throw new Error("End time is before start time");return{startMs:s,endMs:a,start:r,end:o,text:i}}function x(n){return new Promise(t=>setTimeout(t,n))}function I(n,t){let e=null,r=!1,o=null,i=null;return{timeoutError:()=>new Promise((u,l)=>{i=u,o=l,e=setTimeout(()=>{!r&&o&&(r=!0,o(new Error(t)))},n)}),clear:()=>{e&&(clearTimeout(e),e=null),i&&(i(),i=null),r=!0,o=null}}}function $(n,t=16e3*100){const e=[];for(let r=0;r<n.length;r+=t)e.push(n.subarray(r,r+t));return e}class U{constructor(t,e){this.whisperService=t,this.logger=new y((e==null?void 0:e.logLevel)||y.levels.ERROR,"TranscriptionSession")}async*streaming(t,e={}){const{timeoutMs:r=3e4}=e,o=$(t);let i=0;for await(const s of o){const a=[];let u=null,l=!1,d,h=0;const{timeoutError:c,clear:m}=I(r,"Transcribe timeout"),w=()=>this.whisperService.transcribe(s,g=>{h=g.timeEnd,g.timeStart+=i,g.timeEnd+=i,this.logger.debug("Transcription segment in session:",g),u?(u(g),u=null):a.push(g),m()},e).then(()=>{this.logger.debug("Transcription done in session then"),l=!0,i+=h,m(),u==null||u(void 0)}).catch(g=>{this.logger.debug("Transcription error in session catch:",g),d=g,m(),u==null||u(void 0)});for(w();;){if(d){if(e.restartModelOnError){this.whisperService.restartModel(),w();continue}throw d}if(l)break;if(a.length)yield a.shift();else try{const g=await Promise.race([new Promise(f=>u=f),c()]);g&&(yield g)}catch(g){d=g}}e.sleepMsBetweenChunks&&await x(e.sleepMsBetweenChunks)}}async*streamimg(t,e={}){yield*this.streaming(t,e)}}class N extends EventTarget{on(t,e){return this.addEventListener(t,e),()=>this.removeEventListener(t,e)}emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e}))}}class j{constructor(t){this.wasmModule=null,this.instance=null,this.modelFileName="whisper.bin",this.isTranscribing=!1,this.bus=new N,this.modelData=null,this.logger=new y((t==null?void 0:t.logLevel)??y.levels.ERROR,"WhisperWasmService"),t!=null&&t.init&&this.loadWasmScript()}async checkWasmSupport(){return await L()}async loadWasmScript(){this.wasmModule=await(await Promise.resolve().then(()=>require("./libmain-CWYJvMY5.js"))).default({print:(t,...e)=>{e.length>0&&this.logger.debug(e),t.startsWith("[")?(this.logger.info(t),this.bus.emit("transcribe",t)):(this.logger.debug(t),this.bus.emit("system_info",t))},printErr:(t,...e)=>{e.length>0&&this.logger.debug(e),this.logger.warn(t),this.bus.emit("transcribeError",t)}})}async initModel(t){if(!await this.checkWasmSupport())throw new Error("WASM is not supported");return this.modelData=t,this.wasmModule&&(this.wasmModule.FS_unlink(this.modelFileName),this.wasmModule.free()),await this.loadWasmScript(),await x(100),this.storeFS(this.modelFileName,t),this.instance=this.wasmModule.init(this.modelFileName),Promise.resolve()}restartModel(){if(!this.modelData)throw new Error("Model not loaded");return this.initModel(this.modelData)}storeFS(t,e){if(!this.wasmModule)throw new Error("WASM module not loaded");try{this.wasmModule.FS_unlink(t)}catch{}this.wasmModule.FS_createDataFile("/",t,e,!0,!0,!0)}async transcribe(t,e,r={}){if(this.isTranscribing)throw new Error("Already transcribing");if(!this.wasmModule)throw new Error("WASM module not loaded");if(!this.instance)throw new Error("WASM instance not loaded");const o=120;t.length>16e3*o&&this.logger.warn("It's not recommended to transcribe audio data that is longer than 120 seconds"),this.isTranscribing=!0;const{language:i="auto",threads:s=4,translate:a=!1}={...W,...r},u=[],l=Date.now();return this.wasmModule.full_default(this.instance,t,i,s,a),await new Promise((d,h)=>{const c=this.bus.on("transcribe",g=>{const{startMs:f,endMs:v,text:B}=D(g.detail),q={timeStart:f,timeEnd:v,text:B,raw:g.detail};u.push(q),e==null||e(q)}),m=setTimeout(()=>{this.isTranscribing=!1,c(),w(),this.logger.error("Transcribe timeout"),h(new Error("Transcribe timeout")),this.bus.emit("transcribeError","Transcribe timeout")},o*2*1e3),w=this.bus.on("transcribeError",g=>{this.isTranscribing=!1,c(),w(),clearTimeout(m),this.logger.debug("Transcribe error",g.detail),d({segments:u,transcribeDurationMs:Date.now()-l})})})}createSession(){return new U(this,{logLevel:this.logger.getLevel()})}}const O={"tiny.en":{id:"tiny.en",name:"Tiny English",size:75,language:"en",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin"},tiny:{id:"tiny",name:"Tiny Multilingual",size:75,language:"multilingual",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.bin"},"base.en":{id:"base.en",name:"Base English",size:142,language:"en",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin"},base:{id:"base",name:"Base Multilingual",size:142,language:"multilingual",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin"},"small.en":{id:"small.en",name:"Small English",size:466,language:"en",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.en.bin"},small:{id:"small",name:"Small Multilingual",size:466,language:"multilingual",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.bin"},"tiny.en-q5_1":{id:"tiny.en-q5_1",name:"Tiny English (Q5_1)",size:31,language:"en",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en-q5_1.bin"},"tiny-q5_1":{id:"tiny-q5_1",name:"Tiny Multilingual (Q5_1)",size:31,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny-q5_1.bin"},"base.en-q5_1":{id:"base.en-q5_1",name:"Base English (Q5_1)",size:57,language:"en",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en-q5_1.bin"},"base-q5_1":{id:"base-q5_1",name:"Base Multilingual (Q5_1)",size:57,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base-q5_1.bin"},"small.en-q5_1":{id:"small.en-q5_1",name:"Small English (Q5_1)",size:182,language:"en",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.en-q5_1.bin"},"small-q5_1":{id:"small-q5_1",name:"Small Multilingual (Q5_1)",size:182,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small-q5_1.bin"},"medium.en-q5_0":{id:"medium.en-q5_0",name:"Medium English (Q5_0)",size:515,language:"en",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium.en-q5_0.bin"},"medium-q5_0":{id:"medium-q5_0",name:"Medium Multilingual (Q5_0)",size:515,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium-q5_0.bin"},"large-q5_0":{id:"large-q5_0",name:"Large Multilingual (Q5_0)",size:1030,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-q5_0.bin"}};function _(){return Object.values(O).map(({url:n,...t})=>t)}function z(n){return O[n]}class H{constructor(t={logLevel:y.levels.ERROR}){this.cacheEnabled=!0,this.models=_(),this.logger=new y(t.logLevel,"ModelManager")}async loadModel(t,e=!0,r){var w;const o=z(t);if(!o)throw new Error(`Model ${t} not found in config`);if(this.cacheEnabled&&e){const g=await this.getCachedModel(t);if(g)return this.logger.info(`Model ${t} loaded from cache`),r&&r(100),g}this.logger.info(`Loading model ${t} from ${o.url}`);const i=await fetch(o.url);if(!i.ok)throw new Error(`Failed to load model: ${i.statusText}`);const s=i.headers.get("content-length"),a=s?parseInt(s,10):0;let u=0;const l=(w=i.body)==null?void 0:w.getReader();if(!l)throw new Error("Response body is not readable");const d=[];try{let g=!1;for(;!g;){const f=await l.read();if(g=f.done,!g&&f.value&&(d.push(f.value),u+=f.value.length,r&&a>0)){const v=Math.round(u/a*100);r(v)}}}finally{l.releaseLock()}const h=d.reduce((g,f)=>g+f.length,0),c=new Uint8Array(h);let m=0;for(const g of d)c.set(g,m),m+=g.length;return this.cacheEnabled&&e&&await this.saveModelToCache(t,c),r&&r(100),c}async loadModelByUrl(t,e){var r;try{if(this.cacheEnabled){const m=await this.getCachedModelByUrl(t);if(m)return this.logger.info(`WASM module loaded from cache by URL: ${t}`),e&&e(100),m}this.logger.info(`Loading WASM module from URL: ${t}`);const o=await fetch(t);if(!o.ok)throw new Error(`Failed to load WASM module: ${o.statusText}`);const i=o.headers.get("content-length"),s=i?parseInt(i,10):0;let a=0;const u=(r=o.body)==null?void 0:r.getReader();if(!u)throw new Error("Response body is not readable");const l=[];try{let m=!1;for(;!m;){const w=await u.read();if(m=w.done,!m&&w.value&&(l.push(w.value),a+=w.value.length,e&&s>0)){const g=Math.round(a/s*100);e(g)}}}finally{u.releaseLock()}const d=l.reduce((m,w)=>m+w.length,0),h=new Uint8Array(d);let c=0;for(const m of l)h.set(m,c),c+=m.length;return this.cacheEnabled&&await this.saveModelToCacheByUrl(t,h),e&&e(100),h}catch(o){throw this.logger.error(o),new Error("Failed to load WASM module")}}async getCachedModelByUrl(t){try{const o=(await this.openIndexedDB()).transaction(["modelsByUrl"],"readonly").objectStore("modelsByUrl");return new Promise((i,s)=>{const a=o.get(t);a.onsuccess=()=>{const u=a.result;u&&u.data?i(u.data):i(null)},a.onerror=()=>s(a.error)})}catch(e){return this.logger.error("Error reading model from cache by URL:",e),null}}async saveModelToCacheByUrl(t,e){try{const i=(await this.openIndexedDB()).transaction(["modelsByUrl"],"readwrite").objectStore("modelsByUrl");await new Promise((s,a)=>{const u=i.put({url:t,data:e,timestamp:Date.now(),size:e.length});u.onsuccess=()=>s(),u.onerror=()=>a(u.error)}),this.logger.info(`Model saved to cache by URL: ${t}`)}catch(r){this.logger.error("Error saving model to cache by URL:",r)}}async getAvailableModels(){const t=[...this.models];if(!this.cacheEnabled)return t;try{const e=await this.getCachedModelNames();return t.map(r=>({...r,cached:e.includes(r.id)}))}catch(e){return this.logger.error("Error checking cache status:",e),t}}getAvailableModelsSync(){return[...this.models]}getModelConfig(t){return z(t)}async saveModelToCache(t,e){try{const i=(await this.openIndexedDB()).transaction(["models"],"readwrite").objectStore("models");await new Promise((s,a)=>{const u=i.put({name:t,data:e,timestamp:Date.now(),size:e.length});u.onsuccess=()=>s(),u.onerror=()=>a(u.error)}),this.logger.info(`Model ${t} saved to cache`)}catch(r){this.logger.error("Error saving model to cache:",r)}}async getCachedModel(t){try{const o=(await this.openIndexedDB()).transaction(["models"],"readonly").objectStore("models");return new Promise((i,s)=>{const a=o.get(t);a.onsuccess=()=>{const u=a.result;u&&u.data?i(u.data):i(null)},a.onerror=()=>s(a.error)})}catch(e){return this.logger.error("Error getting cached model:",e),null}}async getCachedModelNames(){try{const r=(await this.openIndexedDB()).transaction(["models"],"readonly").objectStore("models");return new Promise((o,i)=>{const s=r.getAllKeys();s.onsuccess=()=>{const a=s.result;o(a)},s.onerror=()=>i(s.error)})}catch(t){return this.logger.error("Error getting cached model names:",t),[]}}async openIndexedDB(){return new Promise((t,e)=>{const r=indexedDB.open("WhisperModels",2);r.onerror=()=>e(r.error),r.onsuccess=()=>t(r.result),r.onupgradeneeded=o=>{const i=o.target.result;if(!i.objectStoreNames.contains("models")){const s=i.createObjectStore("models",{keyPath:"name"});s.createIndex("timestamp","timestamp",{unique:!1}),s.createIndex("size","size",{unique:!1})}if(!i.objectStoreNames.contains("modelsByUrl")){const s=i.createObjectStore("modelsByUrl",{keyPath:"url"});s.createIndex("timestamp","timestamp",{unique:!1}),s.createIndex("size","size",{unique:!1})}}})}async clearCache(){try{const e=(await this.openIndexedDB()).transaction(["models","modelsByUrl"],"readwrite"),r=e.objectStore("models");await new Promise((i,s)=>{const a=r.clear();a.onsuccess=()=>i(),a.onerror=()=>s(a.error)});const o=e.objectStore("modelsByUrl");await new Promise((i,s)=>{const a=o.clear();a.onsuccess=()=>i(),a.onerror=()=>s(a.error)}),this.logger.info("Model cache cleared")}catch(t){this.logger.error("Error clearing cache:",t)}}async getCacheInfo(){try{const r=(await this.openIndexedDB()).transaction(["models"],"readonly").objectStore("models");return new Promise((o,i)=>{const s=r.getAll();s.onsuccess=()=>{const a=s.result,u=a.reduce((l,d)=>l+(d.size||0),0);o({count:a.length,totalSize:u})},s.onerror=()=>i(s.error)})}catch(t){return this.logger.error("Error getting cache info:",t),{count:0,totalSize:0}}}}var p=(n=>(n.MP3="mp3",n.WAV="wav",n.OGG="ogg",n.M4A="m4a",n.AAC="aac",n.FLAC="flac",n.MP4="mp4",n.WEBM="webm",n.AVI="avi",n.MOV="mov",n.MKV="mkv",n.RAW_PCM="raw_pcm",n.MICROPHONE="microphone",n.AUDIO_ELEMENT="audio_element",n))(p||{});const S={targetSampleRate:16e3,targetChannels:1,inputSampleRate:16e3,normalize:!0,noiseReduction:!1,logLevel:y.levels.ERROR,signal:void 0,recordingDurationMs:1e4};function Q(n){return typeof n=="number"?n:n?y.levels[n]:y.levels.ERROR}function R(n){return new y(Q(n.logLevel),"AudioConverter")}function E(n){if(n!=null&&n.aborted)throw new DOMException("Aborted","AbortError")}function A(){return typeof window>"u"?!1:!!(window.AudioContext||window.webkitAudioContext||window.OfflineAudioContext||window.webkitOfflineAudioContext)}function V(){return[p.MP3,p.WAV,p.OGG,p.M4A,p.AAC,p.FLAC,p.MP4,p.WEBM,p.AVI,p.MOV,p.MKV,p.RAW_PCM,p.MICROPHONE,p.AUDIO_ELEMENT]}async function G(n,t={},e={}){var s,a,u,l,d;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r),i=[];try{E(r.signal),o.info(`Converting file: ${n.name}`),(s=e.onProgress)==null||s.call(e,0,`Loading file: ${n.name}`);const h=await Y(n);(a=e.onProgress)==null||a.call(e,20,"File loaded, decoding..."),E(r.signal);const c=await C(h,r,e,o);(u=e.onProgress)==null||u.call(e,40,"Audio decoded, processing...");const m=await P(c,r,e,o,i);return(l=e.onProgress)==null||l.call(e,100,"Conversion completed"),o.info("File conversion completed successfully"),m}catch(h){throw o.error("File conversion failed:",h),(d=e.onError)==null||d.call(e,h),h}}async function T(n,t={},e={}){var s,a,u,l,d;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r),i=[];try{E(r.signal),o.info("Converting from MediaStream"),(s=e.onProgress)==null||s.call(e,0,"Starting recording...");const h=await re(n,r,e,o);(a=e.onProgress)==null||a.call(e,50,"Recording completed, decoding...");const c=await h.arrayBuffer(),m=await C(c,r,e,o);(u=e.onProgress)==null||u.call(e,70,"Audio decoded, processing...");const w=await P(m,r,e,o,i);return(l=e.onProgress)==null||l.call(e,100,"Conversion completed"),w}catch(h){throw o.error("MediaStream conversion failed:",h),(d=e.onError)==null||d.call(e,h),h}}async function K(n,t={},e={}){var s,a,u,l,d,h;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r),i=[];try{E(r.signal),o.info("Converting from HTMLAudioElement"),(s=e.onProgress)==null||s.call(e,0,"Capturing audio from element...");const c=n.srcObject;if(c&&c instanceof MediaStream){i.push("Using HTMLAudioElement.srcObject MediaStream");const f=await T(c,r,e);return{...f,warnings:[...i,...f.warnings??[]]}}const m=n.currentSrc||n.src;if(m)try{(a=e.onProgress)==null||a.call(e,10,"Fetching audio source...");const f=await ne(m,r.signal);(u=e.onProgress)==null||u.call(e,30,"Fetched, decoding...");const v=await C(f,r,e,o);(l=e.onProgress)==null||l.call(e,60,"Decoded, processing...");const B=await P(v,r,e,o,i);return(d=e.onProgress)==null||d.call(e,100,"Conversion completed"),B}catch(f){if((f==null?void 0:f.name)==="AbortError")throw f;i.push(`Failed to fetch element src (CORS?) – falling back to captureStream: ${f.message}`)}const w=n.captureStream||n.mozCaptureStream;if(typeof w!="function")throw new Error("Unable to capture audio from HTMLAudioElement: no srcObject, fetch failed, and captureStream() is not supported");i.push("Using HTMLAudioElement.captureStream() fallback");const g=w.call(n);try{const f=await T(g,r,e);return{...f,warnings:[...i,...f.warnings??[]]}}finally{g.getTracks().forEach(f=>f.stop())}}catch(c){throw o.error("HTMLAudioElement conversion failed:",c),(h=e.onError)==null||h.call(e,c),c}}async function J(n,t={},e={}){var i,s,a,u;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r);try{E(r.signal),o.info("Converting from Float32Array"),(i=e.onProgress)==null||i.call(e,0,"Processing Float32Array...");const l=window.AudioContext||window.webkitAudioContext,d=r.inputSampleRate??r.targetSampleRate,h=new l({sampleRate:d});try{const c=h.createBuffer(1,n.length,h.sampleRate);c.getChannelData(0).set(n),(s=e.onProgress)==null||s.call(e,30,"AudioBuffer created, processing...");const w=[];d!==r.targetSampleRate&&w.push(`Float32Array sample rate (${d}Hz) will be converted to ${r.targetSampleRate}Hz`);const g=await P(c,r,e,o,w);return(a=e.onProgress)==null||a.call(e,100,"Conversion completed"),o.info("Float32Array conversion completed successfully"),g}finally{try{await h.close()}catch{}}}catch(l){throw o.error("Float32Array conversion failed:",l),(u=e.onError)==null||u.call(e,l),l}}async function X(n,t={},e={}){var s,a,u,l;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r),i=[];try{E(r.signal),o.info("Converting from ArrayBuffer"),(s=e.onProgress)==null||s.call(e,0,"Processing ArrayBuffer...");const d=await C(n,r,e,o);(a=e.onProgress)==null||a.call(e,40,"Audio decoded, processing...");const h=await P(d,r,e,o,i);return(u=e.onProgress)==null||u.call(e,100,"Conversion completed"),o.info("ArrayBuffer conversion completed successfully"),h}catch(d){throw o.error("ArrayBuffer conversion failed:",d),(l=e.onError)==null||l.call(e,d),d}}async function Y(n){return new Promise((t,e)=>{const r=new FileReader;r.onload=o=>{var i;return t((i=o.target)==null?void 0:i.result)},r.onerror=o=>e(o),r.readAsArrayBuffer(n)})}async function C(n,t,e,r){var s;(s=e.onProgress)==null||s.call(e,15,"Decoding audio data");const o=window.AudioContext||window.webkitAudioContext,i=new o({sampleRate:t.targetSampleRate});try{return await i.decodeAudioData(n)}catch(a){throw r.error("Audio decoding failed:",a),new Error(`Failed to decode audio: ${a.message}`)}finally{try{await i.close()}catch{}}}async function P(n,t,e,r,o){var a,u,l,d;(a=e.onProgress)==null||a.call(e,50,"Converting audio format..."),te(n,t,o);const i=await Z(n,t,e);(u=e.onProgress)==null||u.call(e,70,"Converting to Float32Array...");const s=b(i);return(l=e.onProgress)==null||l.call(e,80,"Applying effects..."),t.normalize&&k(s),t.noiseReduction&&ee(s),(d=e.onProgress)==null||d.call(e,90,"Finalizing..."),{audioData:s,audioInfo:{sampleRate:i.sampleRate,duration:i.duration,channels:i.numberOfChannels,bitDepth:32,format:"float32"},warnings:o.length>0?o:void 0}}async function Z(n,t,e){var s;(s=e.onProgress)==null||s.call(e,60,"Converting audio format...");const r=window.OfflineAudioContext||window.webkitOfflineAudioContext,o=new r(t.targetChannels,Math.floor(n.length*t.targetSampleRate/n.sampleRate),t.targetSampleRate),i=o.createBufferSource();return i.buffer=n,i.connect(o.destination),i.start(0),await o.startRendering()}function b(n){if(n.numberOfChannels===1)return n.getChannelData(0);{const t=n.getChannelData(0),e=n.getChannelData(1),r=new Float32Array(t.length);for(let o=0;o<t.length;o++)r[o]=(t[o]+e[o])/2;return r}}function k(n){let t=0;for(let e=0;e<n.length;e++)t=Math.max(t,Math.abs(n[e]));if(t>0){const e=.95/t;for(let r=0;r<n.length;r++)n[r]*=e}}function ee(n){const t=new Float32Array(n.length),e=3;for(let r=0;r<n.length;r++){let o=0,i=0;for(let s=Math.max(0,r-e);s<=Math.min(n.length-1,r+e);s++)o+=n[s],i++;t[r]=o/i}n.set(t)}function te(n,t,e){n.numberOfChannels>2&&e.push(`Audio has ${n.numberOfChannels} channels, will be mixed to mono`),n.sampleRate!==t.targetSampleRate&&e.push(`Audio sample rate (${n.sampleRate}Hz) will be converted to ${t.targetSampleRate}Hz`)}async function re(n,t,e,r){var w;if(typeof window>"u")throw new Error("MediaStream recording is only supported in browser environments");if(!window.MediaRecorder)throw new Error("MediaRecorder is not supported in this browser");const o=window.MediaRecorder,s=["audio/webm;codecs=opus","audio/webm","audio/ogg;codecs=opus","audio/ogg"].find(g=>o.isTypeSupported(g)),a=new o(n,s?{mimeType:s}:void 0),u=[],l=new Promise((g,f)=>{a.ondataavailable=v=>{v.data&&v.data.size>0&&u.push(v.data)},a.onerror=()=>f(new Error("MediaRecorder error")),a.onstop=()=>{const v=s||a.mimeType||"application/octet-stream";g(new Blob(u,{type:v}))}}),d=t.signal,h=()=>{try{a.state!=="inactive"&&a.stop()}catch{}};d==null||d.addEventListener("abort",h,{once:!0});const c=t.recordingDurationMs??1e4,m=setTimeout(()=>{try{a.state!=="inactive"&&a.stop()}catch{}},c);(w=e.onProgress)==null||w.call(e,20,"Recording audio..."),r.debug("Starting MediaRecorder",{mimeType:s??a.mimeType,durationMs:c}),a.start(250);try{return await l}finally{clearTimeout(m),d==null||d.removeEventListener("abort",h)}}async function ne(n,t){E(t);const e=await fetch(n,{signal:t});if(!e.ok)throw new Error(`Failed to fetch (${e.status}): ${e.statusText}`);return await e.arrayBuffer()}exports.AudioFormat=p;exports.ModelManager=H;exports.WhisperWasmService=j;exports.convertFromArrayBuffer=X;exports.convertFromAudioElement=K;exports.convertFromFile=G;exports.convertFromFloat32Array=J;exports.convertFromMediaStream=T;exports.getAllModels=_;exports.getSupportedFormats=V;exports.isWebAudioSupported=A;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const M=class M{constructor(t=M.levels.INFO,e=""){this.level=t,this.prefix=e}debug(...t){this.level<=M.levels.DEBUG&&console.debug(`[${this.prefix}] [DEBUG]`,...t)}info(...t){this.level<=M.levels.INFO&&console.info(`[${this.prefix}] [INFO]`,...t)}warn(...t){this.level<=M.levels.WARN&&console.warn(`[${this.prefix}] [WARN]`,...t)}error(...t){this.level<=M.levels.ERROR&&console.error(`[${this.prefix}] [ERROR]`,...t)}setLevel(t){this.level=t}getLevel(){return this.level}};M.levels={DEBUG:0,INFO:1,WARN:2,ERROR:3};let y=M;const L=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11])),W={language:"auto",threads:4,translate:!1};function F(n){const t=String(n).trim().replace(",","."),e=t.split(":").map(Number);if(e.some(Number.isNaN))throw new Error(`Bad time: "${n}"`);let r=0,o=0,i=0;if(e.length===3)[r,o]=e,i=parseFloat(t.split(":").pop()||"0");else if(e.length===2)[o]=e,i=parseFloat(t.split(":").pop()||"0");else throw new Error(`Bad time format: "${n}"`);return Math.floor(((r*60+o)*60+i)*1e3)}function D(n){const e=/^\s*\[?\s*([0-9]{1,2}:[0-9]{2}:(?:[0-9]{2}[.,][0-9]{1,3})|[0-9]{1,2}:[0-9]{2}[.,][0-9]{1,3})\s*-->\s*([0-9]{1,2}:[0-9]{2}:(?:[0-9]{2}[.,][0-9]{1,3})|[0-9]{1,2}:[0-9]{2}[.,][0-9]{1,3})\s*\]?\s*(.*)\s*$/.exec(n);if(!e)throw new Error("Line does not match VTT-like pattern: "+n);const r=e[1],o=e[2],i=e[3]||"",s=F(r),a=F(o);if(a<s)throw new Error("End time is before start time");return{startMs:s,endMs:a,start:r,end:o,text:i}}function x(n){return new Promise(t=>setTimeout(t,n))}function I(n,t){let e=null,r=!1,o=null,i=null;return{timeoutError:()=>new Promise((u,l)=>{i=u,o=l,e=setTimeout(()=>{!r&&o&&(r=!0,o(new Error(t)))},n)}),clear:()=>{e&&(clearTimeout(e),e=null),i&&(i(),i=null),r=!0,o=null}}}function $(n,t=16e3*100){const e=[];for(let r=0;r<n.length;r+=t)e.push(n.subarray(r,r+t));return e}class U{constructor(t,e){this.whisperService=t,this.logger=new y((e==null?void 0:e.logLevel)||y.levels.ERROR,"TranscriptionSession")}async*streaming(t,e={}){const{timeoutMs:r=3e4}=e,o=$(t);let i=0;for await(const s of o){const a=[];let u=null,l=!1,d,h=0;const{timeoutError:c,clear:m}=I(r,"Transcribe timeout"),w=()=>this.whisperService.transcribe(s,g=>{h=g.timeEnd,g.timeStart+=i,g.timeEnd+=i,this.logger.debug("Transcription segment in session:",g),u?(u(g),u=null):a.push(g),m()},e).then(()=>{this.logger.debug("Transcription done in session then"),l=!0,i+=h,m(),u==null||u(void 0)}).catch(g=>{this.logger.debug("Transcription error in session catch:",g),d=g,m(),u==null||u(void 0)});for(w();;){if(d){if(e.restartModelOnError){this.whisperService.restartModel(),w();continue}throw d}if(l)break;if(a.length)yield a.shift();else try{const g=await Promise.race([new Promise(f=>u=f),c()]);g&&(yield g)}catch(g){d=g}}e.sleepMsBetweenChunks&&await x(e.sleepMsBetweenChunks)}}async*streamimg(t,e={}){yield*this.streaming(t,e)}}class N extends EventTarget{on(t,e){return this.addEventListener(t,e),()=>this.removeEventListener(t,e)}emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e}))}}class j{constructor(t){this.wasmModule=null,this.instance=null,this.modelFileName="whisper.bin",this.isTranscribing=!1,this.bus=new N,this.modelData=null,this.logger=new y((t==null?void 0:t.logLevel)??y.levels.ERROR,"WhisperWasmService"),t!=null&&t.init&&this.loadWasmScript()}async checkWasmSupport(){return await L()}async loadWasmScript(){this.wasmModule=await(await Promise.resolve().then(()=>require("./libmain-BZ9NDZ1A.js"))).default({print:(t,...e)=>{e.length>0&&this.logger.debug(e),t.startsWith("[")?(this.logger.info(t),this.bus.emit("transcribe",t)):(this.logger.debug(t),this.bus.emit("system_info",t))},printErr:(t,...e)=>{e.length>0&&this.logger.debug(e),this.logger.warn(t),this.bus.emit("transcribeError",t)}})}async initModel(t){if(!await this.checkWasmSupport())throw new Error("WASM is not supported");return this.modelData=t,this.wasmModule&&(this.wasmModule.FS_unlink(this.modelFileName),this.wasmModule.free()),await this.loadWasmScript(),await x(100),this.storeFS(this.modelFileName,t),this.instance=this.wasmModule.init(this.modelFileName),Promise.resolve()}restartModel(){if(!this.modelData)throw new Error("Model not loaded");return this.initModel(this.modelData)}storeFS(t,e){if(!this.wasmModule)throw new Error("WASM module not loaded");try{this.wasmModule.FS_unlink(t)}catch{}this.wasmModule.FS_createDataFile("/",t,e,!0,!0,!0)}async transcribe(t,e,r={}){if(this.isTranscribing)throw new Error("Already transcribing");if(!this.wasmModule)throw new Error("WASM module not loaded");if(!this.instance)throw new Error("WASM instance not loaded");const o=120;t.length>16e3*o&&this.logger.warn("It's not recommended to transcribe audio data that is longer than 120 seconds"),this.isTranscribing=!0;const{language:i="auto",threads:s=4,translate:a=!1}={...W,...r},u=[],l=Date.now();return this.wasmModule.full_default(this.instance,t,i,s,a),await new Promise((d,h)=>{const c=this.bus.on("transcribe",g=>{const{startMs:f,endMs:v,text:B}=D(g.detail),q={timeStart:f,timeEnd:v,text:B,raw:g.detail};u.push(q),e==null||e(q)}),m=setTimeout(()=>{this.isTranscribing=!1,c(),w(),this.logger.error("Transcribe timeout"),h(new Error("Transcribe timeout")),this.bus.emit("transcribeError","Transcribe timeout")},o*2*1e3),w=this.bus.on("transcribeError",g=>{this.isTranscribing=!1,c(),w(),clearTimeout(m),this.logger.debug("Transcribe error",g.detail),d({segments:u,transcribeDurationMs:Date.now()-l})})})}createSession(){return new U(this,{logLevel:this.logger.getLevel()})}}const O={"tiny.en":{id:"tiny.en",name:"Tiny English",size:75,language:"en",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin"},tiny:{id:"tiny",name:"Tiny Multilingual",size:75,language:"multilingual",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.bin"},"base.en":{id:"base.en",name:"Base English",size:142,language:"en",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin"},base:{id:"base",name:"Base Multilingual",size:142,language:"multilingual",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin"},"small.en":{id:"small.en",name:"Small English",size:466,language:"en",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.en.bin"},small:{id:"small",name:"Small Multilingual",size:466,language:"multilingual",quantized:!1,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.bin"},"tiny.en-q5_1":{id:"tiny.en-q5_1",name:"Tiny English (Q5_1)",size:31,language:"en",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en-q5_1.bin"},"tiny-q5_1":{id:"tiny-q5_1",name:"Tiny Multilingual (Q5_1)",size:31,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny-q5_1.bin"},"base.en-q5_1":{id:"base.en-q5_1",name:"Base English (Q5_1)",size:57,language:"en",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en-q5_1.bin"},"base-q5_1":{id:"base-q5_1",name:"Base Multilingual (Q5_1)",size:57,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base-q5_1.bin"},"small.en-q5_1":{id:"small.en-q5_1",name:"Small English (Q5_1)",size:182,language:"en",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.en-q5_1.bin"},"small-q5_1":{id:"small-q5_1",name:"Small Multilingual (Q5_1)",size:182,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small-q5_1.bin"},"medium.en-q5_0":{id:"medium.en-q5_0",name:"Medium English (Q5_0)",size:515,language:"en",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium.en-q5_0.bin"},"medium-q5_0":{id:"medium-q5_0",name:"Medium Multilingual (Q5_0)",size:515,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium-q5_0.bin"},"large-q5_0":{id:"large-q5_0",name:"Large Multilingual (Q5_0)",size:1030,language:"multilingual",quantized:!0,url:"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-q5_0.bin"}};function _(){return Object.values(O).map(({url:n,...t})=>t)}function z(n){return O[n]}class H{constructor(t={logLevel:y.levels.ERROR}){this.cacheEnabled=!0,this.models=_(),this.logger=new y(t.logLevel,"ModelManager")}async loadModel(t,e=!0,r){var w;const o=z(t);if(!o)throw new Error(`Model ${t} not found in config`);if(this.cacheEnabled&&e){const g=await this.getCachedModel(t);if(g)return this.logger.info(`Model ${t} loaded from cache`),r&&r(100),g}this.logger.info(`Loading model ${t} from ${o.url}`);const i=await fetch(o.url);if(!i.ok)throw new Error(`Failed to load model: ${i.statusText}`);const s=i.headers.get("content-length"),a=s?parseInt(s,10):0;let u=0;const l=(w=i.body)==null?void 0:w.getReader();if(!l)throw new Error("Response body is not readable");const d=[];try{let g=!1;for(;!g;){const f=await l.read();if(g=f.done,!g&&f.value&&(d.push(f.value),u+=f.value.length,r&&a>0)){const v=Math.round(u/a*100);r(v)}}}finally{l.releaseLock()}const h=d.reduce((g,f)=>g+f.length,0),c=new Uint8Array(h);let m=0;for(const g of d)c.set(g,m),m+=g.length;return this.cacheEnabled&&e&&await this.saveModelToCache(t,c),r&&r(100),c}async loadModelByUrl(t,e){var r;try{if(this.cacheEnabled){const m=await this.getCachedModelByUrl(t);if(m)return this.logger.info(`WASM module loaded from cache by URL: ${t}`),e&&e(100),m}this.logger.info(`Loading WASM module from URL: ${t}`);const o=await fetch(t);if(!o.ok)throw new Error(`Failed to load WASM module: ${o.statusText}`);const i=o.headers.get("content-length"),s=i?parseInt(i,10):0;let a=0;const u=(r=o.body)==null?void 0:r.getReader();if(!u)throw new Error("Response body is not readable");const l=[];try{let m=!1;for(;!m;){const w=await u.read();if(m=w.done,!m&&w.value&&(l.push(w.value),a+=w.value.length,e&&s>0)){const g=Math.round(a/s*100);e(g)}}}finally{u.releaseLock()}const d=l.reduce((m,w)=>m+w.length,0),h=new Uint8Array(d);let c=0;for(const m of l)h.set(m,c),c+=m.length;return this.cacheEnabled&&await this.saveModelToCacheByUrl(t,h),e&&e(100),h}catch(o){throw this.logger.error(o),new Error("Failed to load WASM module")}}async getCachedModelByUrl(t){try{const o=(await this.openIndexedDB()).transaction(["modelsByUrl"],"readonly").objectStore("modelsByUrl");return new Promise((i,s)=>{const a=o.get(t);a.onsuccess=()=>{const u=a.result;u&&u.data?i(u.data):i(null)},a.onerror=()=>s(a.error)})}catch(e){return this.logger.error("Error reading model from cache by URL:",e),null}}async saveModelToCacheByUrl(t,e){try{const i=(await this.openIndexedDB()).transaction(["modelsByUrl"],"readwrite").objectStore("modelsByUrl");await new Promise((s,a)=>{const u=i.put({url:t,data:e,timestamp:Date.now(),size:e.length});u.onsuccess=()=>s(),u.onerror=()=>a(u.error)}),this.logger.info(`Model saved to cache by URL: ${t}`)}catch(r){this.logger.error("Error saving model to cache by URL:",r)}}async getAvailableModels(){const t=[...this.models];if(!this.cacheEnabled)return t;try{const e=await this.getCachedModelNames();return t.map(r=>({...r,cached:e.includes(r.id)}))}catch(e){return this.logger.error("Error checking cache status:",e),t}}getAvailableModelsSync(){return[...this.models]}getModelConfig(t){return z(t)}async saveModelToCache(t,e){try{const i=(await this.openIndexedDB()).transaction(["models"],"readwrite").objectStore("models");await new Promise((s,a)=>{const u=i.put({name:t,data:e,timestamp:Date.now(),size:e.length});u.onsuccess=()=>s(),u.onerror=()=>a(u.error)}),this.logger.info(`Model ${t} saved to cache`)}catch(r){this.logger.error("Error saving model to cache:",r)}}async getCachedModel(t){try{const o=(await this.openIndexedDB()).transaction(["models"],"readonly").objectStore("models");return new Promise((i,s)=>{const a=o.get(t);a.onsuccess=()=>{const u=a.result;u&&u.data?i(u.data):i(null)},a.onerror=()=>s(a.error)})}catch(e){return this.logger.error("Error getting cached model:",e),null}}async getCachedModelNames(){try{const r=(await this.openIndexedDB()).transaction(["models"],"readonly").objectStore("models");return new Promise((o,i)=>{const s=r.getAllKeys();s.onsuccess=()=>{const a=s.result;o(a)},s.onerror=()=>i(s.error)})}catch(t){return this.logger.error("Error getting cached model names:",t),[]}}async openIndexedDB(){return new Promise((t,e)=>{const r=indexedDB.open("WhisperModels",2);r.onerror=()=>e(r.error),r.onsuccess=()=>t(r.result),r.onupgradeneeded=o=>{const i=o.target.result;if(!i.objectStoreNames.contains("models")){const s=i.createObjectStore("models",{keyPath:"name"});s.createIndex("timestamp","timestamp",{unique:!1}),s.createIndex("size","size",{unique:!1})}if(!i.objectStoreNames.contains("modelsByUrl")){const s=i.createObjectStore("modelsByUrl",{keyPath:"url"});s.createIndex("timestamp","timestamp",{unique:!1}),s.createIndex("size","size",{unique:!1})}}})}async clearCache(){try{const e=(await this.openIndexedDB()).transaction(["models","modelsByUrl"],"readwrite"),r=e.objectStore("models");await new Promise((i,s)=>{const a=r.clear();a.onsuccess=()=>i(),a.onerror=()=>s(a.error)});const o=e.objectStore("modelsByUrl");await new Promise((i,s)=>{const a=o.clear();a.onsuccess=()=>i(),a.onerror=()=>s(a.error)}),this.logger.info("Model cache cleared")}catch(t){this.logger.error("Error clearing cache:",t)}}async getCacheInfo(){try{const r=(await this.openIndexedDB()).transaction(["models"],"readonly").objectStore("models");return new Promise((o,i)=>{const s=r.getAll();s.onsuccess=()=>{const a=s.result,u=a.reduce((l,d)=>l+(d.size||0),0);o({count:a.length,totalSize:u})},s.onerror=()=>i(s.error)})}catch(t){return this.logger.error("Error getting cache info:",t),{count:0,totalSize:0}}}}var p=(n=>(n.MP3="mp3",n.WAV="wav",n.OGG="ogg",n.M4A="m4a",n.AAC="aac",n.FLAC="flac",n.MP4="mp4",n.WEBM="webm",n.AVI="avi",n.MOV="mov",n.MKV="mkv",n.RAW_PCM="raw_pcm",n.MICROPHONE="microphone",n.AUDIO_ELEMENT="audio_element",n))(p||{});const S={targetSampleRate:16e3,targetChannels:1,inputSampleRate:16e3,normalize:!0,noiseReduction:!1,logLevel:y.levels.ERROR,signal:void 0,recordingDurationMs:1e4};function Q(n){return typeof n=="number"?n:n?y.levels[n]:y.levels.ERROR}function R(n){return new y(Q(n.logLevel),"AudioConverter")}function E(n){if(n!=null&&n.aborted)throw new DOMException("Aborted","AbortError")}function A(){return typeof window>"u"?!1:!!(window.AudioContext||window.webkitAudioContext||window.OfflineAudioContext||window.webkitOfflineAudioContext)}function V(){return[p.MP3,p.WAV,p.OGG,p.M4A,p.AAC,p.FLAC,p.MP4,p.WEBM,p.AVI,p.MOV,p.MKV,p.RAW_PCM,p.MICROPHONE,p.AUDIO_ELEMENT]}async function G(n,t={},e={}){var s,a,u,l,d;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r),i=[];try{E(r.signal),o.info(`Converting file: ${n.name}`),(s=e.onProgress)==null||s.call(e,0,`Loading file: ${n.name}`);const h=await Y(n);(a=e.onProgress)==null||a.call(e,20,"File loaded, decoding..."),E(r.signal);const c=await C(h,r,e,o);(u=e.onProgress)==null||u.call(e,40,"Audio decoded, processing...");const m=await P(c,r,e,o,i);return(l=e.onProgress)==null||l.call(e,100,"Conversion completed"),o.info("File conversion completed successfully"),m}catch(h){throw o.error("File conversion failed:",h),(d=e.onError)==null||d.call(e,h),h}}async function T(n,t={},e={}){var s,a,u,l,d;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r),i=[];try{E(r.signal),o.info("Converting from MediaStream"),(s=e.onProgress)==null||s.call(e,0,"Starting recording...");const h=await re(n,r,e,o);(a=e.onProgress)==null||a.call(e,50,"Recording completed, decoding...");const c=await h.arrayBuffer(),m=await C(c,r,e,o);(u=e.onProgress)==null||u.call(e,70,"Audio decoded, processing...");const w=await P(m,r,e,o,i);return(l=e.onProgress)==null||l.call(e,100,"Conversion completed"),w}catch(h){throw o.error("MediaStream conversion failed:",h),(d=e.onError)==null||d.call(e,h),h}}async function K(n,t={},e={}){var s,a,u,l,d,h;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r),i=[];try{E(r.signal),o.info("Converting from HTMLAudioElement"),(s=e.onProgress)==null||s.call(e,0,"Capturing audio from element...");const c=n.srcObject;if(c&&c instanceof MediaStream){i.push("Using HTMLAudioElement.srcObject MediaStream");const f=await T(c,r,e);return{...f,warnings:[...i,...f.warnings??[]]}}const m=n.currentSrc||n.src;if(m)try{(a=e.onProgress)==null||a.call(e,10,"Fetching audio source...");const f=await ne(m,r.signal);(u=e.onProgress)==null||u.call(e,30,"Fetched, decoding...");const v=await C(f,r,e,o);(l=e.onProgress)==null||l.call(e,60,"Decoded, processing...");const B=await P(v,r,e,o,i);return(d=e.onProgress)==null||d.call(e,100,"Conversion completed"),B}catch(f){if((f==null?void 0:f.name)==="AbortError")throw f;i.push(`Failed to fetch element src (CORS?) – falling back to captureStream: ${f.message}`)}const w=n.captureStream||n.mozCaptureStream;if(typeof w!="function")throw new Error("Unable to capture audio from HTMLAudioElement: no srcObject, fetch failed, and captureStream() is not supported");i.push("Using HTMLAudioElement.captureStream() fallback");const g=w.call(n);try{const f=await T(g,r,e);return{...f,warnings:[...i,...f.warnings??[]]}}finally{g.getTracks().forEach(f=>f.stop())}}catch(c){throw o.error("HTMLAudioElement conversion failed:",c),(h=e.onError)==null||h.call(e,c),c}}async function J(n,t={},e={}){var i,s,a,u;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r);try{E(r.signal),o.info("Converting from Float32Array"),(i=e.onProgress)==null||i.call(e,0,"Processing Float32Array...");const l=window.AudioContext||window.webkitAudioContext,d=r.inputSampleRate??r.targetSampleRate,h=new l({sampleRate:d});try{const c=h.createBuffer(1,n.length,h.sampleRate);c.getChannelData(0).set(n),(s=e.onProgress)==null||s.call(e,30,"AudioBuffer created, processing...");const w=[];d!==r.targetSampleRate&&w.push(`Float32Array sample rate (${d}Hz) will be converted to ${r.targetSampleRate}Hz`);const g=await P(c,r,e,o,w);return(a=e.onProgress)==null||a.call(e,100,"Conversion completed"),o.info("Float32Array conversion completed successfully"),g}finally{try{await h.close()}catch{}}}catch(l){throw o.error("Float32Array conversion failed:",l),(u=e.onError)==null||u.call(e,l),l}}async function X(n,t={},e={}){var s,a,u,l;if(!A())throw new Error("Web Audio API is not supported in this browser");const r={...S,...t},o=R(r),i=[];try{E(r.signal),o.info("Converting from ArrayBuffer"),(s=e.onProgress)==null||s.call(e,0,"Processing ArrayBuffer...");const d=await C(n,r,e,o);(a=e.onProgress)==null||a.call(e,40,"Audio decoded, processing...");const h=await P(d,r,e,o,i);return(u=e.onProgress)==null||u.call(e,100,"Conversion completed"),o.info("ArrayBuffer conversion completed successfully"),h}catch(d){throw o.error("ArrayBuffer conversion failed:",d),(l=e.onError)==null||l.call(e,d),d}}async function Y(n){return new Promise((t,e)=>{const r=new FileReader;r.onload=o=>{var i;return t((i=o.target)==null?void 0:i.result)},r.onerror=o=>e(o),r.readAsArrayBuffer(n)})}async function C(n,t,e,r){var s;(s=e.onProgress)==null||s.call(e,15,"Decoding audio data");const o=window.AudioContext||window.webkitAudioContext,i=new o({sampleRate:t.targetSampleRate});try{return await i.decodeAudioData(n)}catch(a){throw r.error("Audio decoding failed:",a),new Error(`Failed to decode audio: ${a.message}`)}finally{try{await i.close()}catch{}}}async function P(n,t,e,r,o){var a,u,l,d;(a=e.onProgress)==null||a.call(e,50,"Converting audio format..."),te(n,t,o);const i=await Z(n,t,e);(u=e.onProgress)==null||u.call(e,70,"Converting to Float32Array...");const s=b(i);return(l=e.onProgress)==null||l.call(e,80,"Applying effects..."),t.normalize&&k(s),t.noiseReduction&&ee(s),(d=e.onProgress)==null||d.call(e,90,"Finalizing..."),{audioData:s,audioInfo:{sampleRate:i.sampleRate,duration:i.duration,channels:i.numberOfChannels,bitDepth:32,format:"float32"},warnings:o.length>0?o:void 0}}async function Z(n,t,e){var s;(s=e.onProgress)==null||s.call(e,60,"Converting audio format...");const r=window.OfflineAudioContext||window.webkitOfflineAudioContext,o=new r(t.targetChannels,Math.floor(n.length*t.targetSampleRate/n.sampleRate),t.targetSampleRate),i=o.createBufferSource();return i.buffer=n,i.connect(o.destination),i.start(0),await o.startRendering()}function b(n){if(n.numberOfChannels===1)return n.getChannelData(0);{const t=n.getChannelData(0),e=n.getChannelData(1),r=new Float32Array(t.length);for(let o=0;o<t.length;o++)r[o]=(t[o]+e[o])/2;return r}}function k(n){let t=0;for(let e=0;e<n.length;e++)t=Math.max(t,Math.abs(n[e]));if(t>0){const e=.95/t;for(let r=0;r<n.length;r++)n[r]*=e}}function ee(n){const t=new Float32Array(n.length),e=3;for(let r=0;r<n.length;r++){let o=0,i=0;for(let s=Math.max(0,r-e);s<=Math.min(n.length-1,r+e);s++)o+=n[s],i++;t[r]=o/i}n.set(t)}function te(n,t,e){n.numberOfChannels>2&&e.push(`Audio has ${n.numberOfChannels} channels, will be mixed to mono`),n.sampleRate!==t.targetSampleRate&&e.push(`Audio sample rate (${n.sampleRate}Hz) will be converted to ${t.targetSampleRate}Hz`)}async function re(n,t,e,r){var w;if(typeof window>"u")throw new Error("MediaStream recording is only supported in browser environments");if(!window.MediaRecorder)throw new Error("MediaRecorder is not supported in this browser");const o=window.MediaRecorder,s=["audio/webm;codecs=opus","audio/webm","audio/ogg;codecs=opus","audio/ogg"].find(g=>o.isTypeSupported(g)),a=new o(n,s?{mimeType:s}:void 0),u=[],l=new Promise((g,f)=>{a.ondataavailable=v=>{v.data&&v.data.size>0&&u.push(v.data)},a.onerror=()=>f(new Error("MediaRecorder error")),a.onstop=()=>{const v=s||a.mimeType||"application/octet-stream";g(new Blob(u,{type:v}))}}),d=t.signal,h=()=>{try{a.state!=="inactive"&&a.stop()}catch{}};d==null||d.addEventListener("abort",h,{once:!0});const c=t.recordingDurationMs??1e4,m=setTimeout(()=>{try{a.state!=="inactive"&&a.stop()}catch{}},c);(w=e.onProgress)==null||w.call(e,20,"Recording audio..."),r.debug("Starting MediaRecorder",{mimeType:s??a.mimeType,durationMs:c}),a.start(250);try{return await l}finally{clearTimeout(m),d==null||d.removeEventListener("abort",h)}}async function ne(n,t){E(t);const e=await fetch(n,{signal:t});if(!e.ok)throw new Error(`Failed to fetch (${e.status}): ${e.statusText}`);return await e.arrayBuffer()}exports.AudioFormat=p;exports.ModelManager=H;exports.WhisperWasmService=j;exports.convertFromArrayBuffer=X;exports.convertFromAudioElement=K;exports.convertFromFile=G;exports.convertFromFloat32Array=J;exports.convertFromMediaStream=T;exports.getAllModels=_;exports.getSupportedFormats=V;exports.isWebAudioSupported=A;
|
package/dist/index.es.js
CHANGED
|
@@ -150,7 +150,7 @@ class Z {
|
|
|
150
150
|
return await F();
|
|
151
151
|
}
|
|
152
152
|
async loadWasmScript() {
|
|
153
|
-
this.wasmModule = await (await import("./libmain-
|
|
153
|
+
this.wasmModule = await (await import("./libmain-BRsjb_5x.mjs")).default({
|
|
154
154
|
print: (t, ...e) => {
|
|
155
155
|
e.length > 0 && this.logger.debug(e), t.startsWith("[") ? (this.logger.info(t), this.bus.emit("transcribe", t)) : (this.logger.debug(t), this.bus.emit("system_info", t));
|
|
156
156
|
},
|