mellon 0.0.4 → 0.0.6
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 +5 -9
- package/dist/mellon.cjs +2 -2
- package/dist/mellon.mjs +34 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# mellon
|
|
2
2
|
|
|
3
|
-
Offline, fully in-browser **hotword / wake-word detection** powered by [EfficientWord-Net](https://github.com/Ant-Brain/EfficientWord-Net) (ResNet-50 ArcFace).
|
|
3
|
+
Offline, fully in-browser **hotword / wake-word detection** powered by [EfficientWord-Net](https://github.com/Ant-Brain/EfficientWord-Net) (ResNet-50 ArcFace).
|
|
4
4
|
|
|
5
5
|
- **100% offline** — ONNX inference runs in the browser via WebAssembly; no server, no cloud.
|
|
6
6
|
- **Speaker-independent** — the model generalises across voices out of the box.
|
|
7
|
-
- **Custom words** — enroll any phrase with ≥ 3 audio samples
|
|
7
|
+
- **Custom words** — enroll any phrase with ≥ 3 audio samples.
|
|
8
8
|
- **TypeScript-ready** — ships with full `.d.ts` declarations.
|
|
9
|
-
- **Tiny API surface** — one class, zero config.
|
|
10
9
|
|
|
11
10
|
---
|
|
12
11
|
|
|
@@ -81,16 +80,14 @@ Refs are fetched automatically during `start()`. You can enroll your own words
|
|
|
81
80
|
By default, the WASM runtime and model load from the jsDelivr CDN — no setup needed. For air-gapped or private-network deployments, copy the assets locally and tell the library where to find them:
|
|
82
81
|
|
|
83
82
|
```bash
|
|
84
|
-
cp -r node_modules/mellon/dist/
|
|
85
|
-
cp node_modules/mellon/dist/models/model.onnx public/mellon-assets/model.onnx
|
|
83
|
+
cp -r node_modules/mellon/dist/assets public/mellon-assets/
|
|
86
84
|
```
|
|
87
85
|
|
|
88
86
|
Then pass the paths to the constructor:
|
|
89
87
|
|
|
90
88
|
```js
|
|
91
89
|
new Mellon({
|
|
92
|
-
|
|
93
|
-
modelUrl: '/mellon-assets/model.onnx',
|
|
90
|
+
assetsPath: '/mellon-assets', // trailing slash required
|
|
94
91
|
})
|
|
95
92
|
```
|
|
96
93
|
|
|
@@ -104,8 +101,7 @@ export default {
|
|
|
104
101
|
plugins: [
|
|
105
102
|
viteStaticCopy({
|
|
106
103
|
targets: [
|
|
107
|
-
{ src: 'node_modules/mellon/dist/
|
|
108
|
-
{ src: 'node_modules/mellon/dist/models/model.onnx', dest: 'mellon-assets' },
|
|
104
|
+
{ src: 'node_modules/mellon/dist/assets/*', dest: 'mellon-assets' }
|
|
109
105
|
],
|
|
110
106
|
}),
|
|
111
107
|
],
|
package/dist/mellon.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Jt="0.0.
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Jt="0.0.6",Kt=[1,1,149,64],Yt=`https://cdn.jsdelivr.net/npm/mellon@${Jt}/dist/assets`,st={assetsPath:`${Yt}`};let I=null,q=null,tt=null;function Qt({assetsPath:i}={}){i!==void 0&&(st.assetsPath=i),I=null,q=null,tt=null}async function Vt(i){return I?(i==null||i(1),I):q||(q=(async()=>{const n=st.assetsPath.endsWith("/")?st.assetsPath:st.assetsPath+"/",t=n+"ort.all.min.mjs",e=n+"model.onnx";tt=await new Function("url","return import(url)")(t),tt.env.wasm.wasmPaths=n;const s=await fetch(e);if(!s.ok)throw new Error(`Failed to fetch model: ${s.status}`);const a=parseInt(s.headers.get("content-length")||"0",10),r=s.body.getReader(),c=[];let l=0;for(;;){const{done:m,value:_}=await r.read();if(m)break;c.push(_),l+=_.byteLength,a>0&&(i==null||i(l/a))}const h=new Uint8Array(l);let d=0;for(const m of c)h.set(m,d),d+=m.byteLength;return I=await tt.InferenceSession.create(h.buffer,{executionProviders:["wasm"],graphOptimizationLevel:"all"}),i==null||i(1),I})(),q)}async function St(i){if(!I)throw new Error("Model not loaded — call loadModel() first");const n=new tt.Tensor("float32",i,Kt),t=await I.run({input:n}),e=Object.keys(t)[0];return t[e].data}function Xt(i){return i&&i.__esModule&&Object.prototype.hasOwnProperty.call(i,"default")?i.default:i}var mt,Et;function Zt(){if(Et)return mt;Et=1;function i(n){if(this.size=n|0,this.size<=1||(this.size&this.size-1)!==0)throw new Error("FFT size must be a power of two and bigger than 1");this._csize=n<<1;for(var t=new Array(this.size*2),e=0;e<t.length;e+=2){const l=Math.PI*e/this.size;t[e]=Math.cos(l),t[e+1]=-Math.sin(l)}this.table=t;for(var o=0,s=1;this.size>s;s<<=1)o++;this._width=o%2===0?o-1:o,this._bitrev=new Array(1<<this._width);for(var a=0;a<this._bitrev.length;a++){this._bitrev[a]=0;for(var r=0;r<this._width;r+=2){var c=this._width-r-2;this._bitrev[a]|=(a>>>r&3)<<c}}this._out=null,this._data=null,this._inv=0}return mt=i,i.prototype.fromComplexArray=function(t,e){for(var o=e||new Array(t.length>>>1),s=0;s<t.length;s+=2)o[s>>>1]=t[s];return o},i.prototype.createComplexArray=function(){const t=new Array(this._csize);for(var e=0;e<t.length;e++)t[e]=0;return t},i.prototype.toComplexArray=function(t,e){for(var o=e||this.createComplexArray(),s=0;s<o.length;s+=2)o[s]=t[s>>>1],o[s+1]=0;return o},i.prototype.completeSpectrum=function(t){for(var e=this._csize,o=e>>>1,s=2;s<o;s+=2)t[e-s]=t[s],t[e-s+1]=-t[s+1]},i.prototype.transform=function(t,e){if(t===e)throw new Error("Input and output buffers must be different");this._out=t,this._data=e,this._inv=0,this._transform4(),this._out=null,this._data=null},i.prototype.realTransform=function(t,e){if(t===e)throw new Error("Input and output buffers must be different");this._out=t,this._data=e,this._inv=0,this._realTransform4(),this._out=null,this._data=null},i.prototype.inverseTransform=function(t,e){if(t===e)throw new Error("Input and output buffers must be different");this._out=t,this._data=e,this._inv=1,this._transform4();for(var o=0;o<t.length;o++)t[o]/=this.size;this._out=null,this._data=null},i.prototype._transform4=function(){var t=this._out,e=this._csize,o=this._width,s=1<<o,a=e/s<<1,r,c,l=this._bitrev;if(a===4)for(r=0,c=0;r<e;r+=a,c++){const u=l[c];this._singleTransform2(r,u,s)}else for(r=0,c=0;r<e;r+=a,c++){const u=l[c];this._singleTransform4(r,u,s)}var h=this._inv?-1:1,d=this.table;for(s>>=2;s>=2;s>>=2){a=e/s<<1;var m=a>>>2;for(r=0;r<e;r+=a)for(var _=r+m,g=r,f=0;g<_;g+=2,f+=s){const u=g,p=u+m,v=p+m,w=v+m,b=t[u],A=t[u+1],E=t[p],y=t[p+1],F=t[v],M=t[v+1],C=t[w],T=t[w+1],x=b,R=A,z=d[f],S=h*d[f+1],N=E*z-y*S,k=E*S+y*z,P=d[2*f],L=h*d[2*f+1],G=F*P-M*L,H=F*L+M*P,J=d[3*f],K=h*d[3*f+1],Y=C*J-T*K,Q=C*K+T*J,V=x+G,W=R+H,B=x-G,X=R-H,Z=N+Y,U=k+Q,$=h*(N-Y),O=h*(k-Q),et=V+Z,ot=W+U,at=V-Z,it=W-U,ct=B+O,lt=X-$,ht=B-O,dt=X+$;t[u]=et,t[u+1]=ot,t[p]=ct,t[p+1]=lt,t[v]=at,t[v+1]=it,t[w]=ht,t[w+1]=dt}}},i.prototype._singleTransform2=function(t,e,o){const s=this._out,a=this._data,r=a[e],c=a[e+1],l=a[e+o],h=a[e+o+1],d=r+l,m=c+h,_=r-l,g=c-h;s[t]=d,s[t+1]=m,s[t+2]=_,s[t+3]=g},i.prototype._singleTransform4=function(t,e,o){const s=this._out,a=this._data,r=this._inv?-1:1,c=o*2,l=o*3,h=a[e],d=a[e+1],m=a[e+o],_=a[e+o+1],g=a[e+c],f=a[e+c+1],u=a[e+l],p=a[e+l+1],v=h+g,w=d+f,b=h-g,A=d-f,E=m+u,y=_+p,F=r*(m-u),M=r*(_-p),C=v+E,T=w+y,x=b+M,R=A-F,z=v-E,S=w-y,N=b-M,k=A+F;s[t]=C,s[t+1]=T,s[t+2]=x,s[t+3]=R,s[t+4]=z,s[t+5]=S,s[t+6]=N,s[t+7]=k},i.prototype._realTransform4=function(){var t=this._out,e=this._csize,o=this._width,s=1<<o,a=e/s<<1,r,c,l=this._bitrev;if(a===4)for(r=0,c=0;r<e;r+=a,c++){const ut=l[c];this._singleRealTransform2(r,ut>>>1,s>>>1)}else for(r=0,c=0;r<e;r+=a,c++){const ut=l[c];this._singleRealTransform4(r,ut>>>1,s>>>1)}var h=this._inv?-1:1,d=this.table;for(s>>=2;s>=2;s>>=2){a=e/s<<1;var m=a>>>1,_=m>>>1,g=_>>>1;for(r=0;r<e;r+=a)for(var f=0,u=0;f<=g;f+=2,u+=s){var p=r+f,v=p+_,w=v+_,b=w+_,A=t[p],E=t[p+1],y=t[v],F=t[v+1],M=t[w],C=t[w+1],T=t[b],x=t[b+1],R=A,z=E,S=d[u],N=h*d[u+1],k=y*S-F*N,P=y*N+F*S,L=d[2*u],G=h*d[2*u+1],H=M*L-C*G,J=M*G+C*L,K=d[3*u],Y=h*d[3*u+1],Q=T*K-x*Y,V=T*Y+x*K,W=R+H,B=z+J,X=R-H,Z=z-J,U=k+Q,$=P+V,O=h*(k-Q),et=h*(P-V),ot=W+U,at=B+$,it=X+et,ct=Z-O;if(t[p]=ot,t[p+1]=at,t[v]=it,t[v+1]=ct,f===0){var lt=W-U,ht=B-$;t[w]=lt,t[w+1]=ht;continue}if(f!==g){var dt=X,It=-Z,Dt=W,jt=-B,Wt=-h*et,Bt=-h*O,Ut=-h*$,$t=-h*U,Pt=dt+Wt,Lt=It+Bt,Gt=Dt+$t,Ht=jt-Ut,yt=r+_-f,bt=r+m-f;t[yt]=Pt,t[yt+1]=Lt,t[bt]=Gt,t[bt+1]=Ht}}}},i.prototype._singleRealTransform2=function(t,e,o){const s=this._out,a=this._data,r=a[e],c=a[e+o],l=r+c,h=r-c;s[t]=l,s[t+1]=0,s[t+2]=h,s[t+3]=0},i.prototype._singleRealTransform4=function(t,e,o){const s=this._out,a=this._data,r=this._inv?-1:1,c=o*2,l=o*3,h=a[e],d=a[e+o],m=a[e+c],_=a[e+l],g=h+m,f=h-m,u=d+_,p=r*(d-_),v=g+u,w=f,b=-p,A=g-u,E=f,y=p;s[t]=v,s[t+1]=0,s[t+2]=w,s[t+3]=b,s[t+4]=A,s[t+5]=0,s[t+6]=E,s[t+7]=y},mt}var Ot=Zt();const qt=Xt(Ot),nt=16e3,j=512,D=64,At=Math.floor(.025*nt),Ft=Math.floor(.01*nt);function Mt(i){return 2595*Math.log10(1+i/700)}function te(i){return 700*(10**(i/2595)-1)}function ee(){const i=Mt(0),n=Mt(nt/2),t=new Float64Array(D+2);for(let r=0;r<D+2;r++)t[r]=i+r*(n-i)/(D+1);const o=t.map(r=>te(r)).map(r=>Math.floor((j+1)*r/nt)),s=[],a=Math.floor(j/2)+1;for(let r=0;r<D;r++){const c=new Float32Array(a);for(let l=o[r];l<o[r+1];l++)c[l]=(l-o[r])/(o[r+1]-o[r]);for(let l=o[r+1];l<o[r+2];l++)c[l]=(o[r+2]-l)/(o[r+2]-o[r+1]);s.push(c)}return s}const se=ee(),rt=new qt(j),ft=new Float32Array(j),Ct=rt.createComplexArray(),_t=rt.createComplexArray(),Tt=new Float32Array(Math.floor(j/2)+1);function Nt(i){const n=1+Math.ceil((i.length-At)/Ft),t=new Float32Array(n*D),e=Math.floor(j/2)+1;for(let o=0;o<n;o++){const s=o*Ft;ft.fill(0);for(let a=0;a<At&&s+a<i.length;a++)ft[a]=i[s+a];rt.toComplexArray(ft,Ct),rt.transform(_t,Ct);for(let a=0;a<e;a++){const r=_t[2*a],c=_t[2*a+1],l=(r*r+c*c)/j;Tt[a]=l===0?1e-30:l}for(let a=0;a<D;a++){const r=se[a];let c=0;for(let l=0;l<e;l++)c+=Tt[l]*r[l];t[o*D+a]=Math.log(c===0?1e-30:c)}}return t}function ne(i,n){let t=0;for(let e=0;e<i.length;e++)t+=i[e]*n[e];return(t+1)/2}function re(i,n){let t=0;for(const e of n){const o=ne(i,e);o>t&&(t=o)}return t}class xt extends EventTarget{constructor({name:n,refEmbeddings:t,threshold:e=.65,relaxationMs:o=2e3,inferenceGapMs:s=300}){super(),this.name=n,this.refEmbeddings=t,this.threshold=e,this.relaxationMs=o,this.inferenceGapMs=s,this._lastDetectionAt=0,this._lastInferenceAt=0,this._lastScore=0}get lastScore(){return this._lastScore}async scoreFrame(n){const t=Date.now();if(t-this._lastInferenceAt<this.inferenceGapMs)return null;this._lastInferenceAt=t;const e=Nt(n),o=await St(e),s=re(o,this.refEmbeddings);return this._lastScore=s,s>=this.threshold&&t-this._lastDetectionAt>=this.relaxationMs&&(this._lastDetectionAt=t,this.dispatchEvent(new CustomEvent("match",{detail:{name:this.name,confidence:s,timestamp:t}}))),s}}const Rt=16e3,oe=1500,pt=24e3;function zt(i){if(i.length===pt)return i;const n=new Float32Array(pt);return n.set(i.subarray(0,pt)),n}class kt extends EventTarget{constructor(n){super(),this.wordName=n.trim().toLowerCase(),this.samples=[]}get sampleCount(){return this.samples.length}async recordSample(){const n=await navigator.mediaDevices.getUserMedia({audio:!0});return new Promise((t,e)=>{const o=new AudioContext({sampleRate:Rt}),s=new MediaRecorder(n),a=[];this.dispatchEvent(new CustomEvent("recording-start")),s.ondataavailable=r=>{r.data.size>0&&a.push(r.data)},s.onstop=async()=>{n.getTracks().forEach(r=>r.stop());try{const c=await new Blob(a,{type:"audio/webm"}).arrayBuffer(),l=await o.decodeAudioData(c);await o.close();const h=l.getChannelData(0),d=zt(new Float32Array(h)),m=this._push(d,`Recorded #${this.samples.length}`);t(m)}catch(r){await o.close().catch(()=>{}),e(r)}},s.start(),setTimeout(()=>s.stop(),oe)})}async addAudioFile(n){const t=await n.arrayBuffer(),e=new AudioContext({sampleRate:Rt}),o=await e.decodeAudioData(t);await e.close();const s=o.getChannelData(0),a=zt(new Float32Array(s));return this._push(a,n.name)}removeSample(n){this.samples.splice(n,1),this.dispatchEvent(new CustomEvent("samples-changed",{detail:{count:this.samples.length}}))}clearSamples(){this.samples=[],this.dispatchEvent(new CustomEvent("samples-changed",{detail:{count:0}}))}async generateRef(){if(this.samples.length<3)throw new Error(`Need at least 3 samples (currently have ${this.samples.length})`);this.dispatchEvent(new CustomEvent("generating",{detail:{total:this.samples.length}}));const n=[];for(let t=0;t<this.samples.length;t++){const e=Nt(this.samples[t].audioBuffer),o=await St(e);n.push(Array.from(o)),this.dispatchEvent(new CustomEvent("progress",{detail:{done:t+1,total:this.samples.length}}))}return{word_name:this.wordName,model_type:"resnet_50_arc",embeddings:n}}_push(n,t){this.samples.push({audioBuffer:n,name:t});const e=this.samples.length;return this.dispatchEvent(new CustomEvent("sample-added",{detail:{count:e,name:t}})),e}}const ae=`/**
|
|
2
2
|
* public/audio-processor.js
|
|
3
3
|
* AudioWorklet that runs at 16 kHz and continuously emits the last
|
|
4
4
|
* 1.5-second window (24 000 samples) via a circular buffer.
|
|
@@ -35,4 +35,4 @@ class AudioProcessor extends AudioWorkletProcessor {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
registerProcessor('audio-processor', AudioProcessor)
|
|
38
|
-
`;let vt=null;function ie(){if(!vt){const i=new Blob([ae],{type:"application/javascript"});vt=URL.createObjectURL(i)}return vt}const wt="mellon_custom_refs";function gt(){try{const i=localStorage.getItem(wt);return i?JSON.parse(i):[]}catch{return[]}}function ce(i){const n=gt().filter(t=>t.word_name!==i.word_name);n.push(i),localStorage.setItem(wt,JSON.stringify(n))}function le(i){const n=gt().filter(t=>t.word_name!==i);localStorage.setItem(wt,JSON.stringify(n))}function he(i){const n=JSON.stringify(i,null,2),t=new Blob([n],{type:"application/json"}),e=URL.createObjectURL(t),o=Object.assign(document.createElement("a"),{href:e,download:`${i.word_name}_ref.json`});document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(e)}async function de(i){const n=await i.text();let t;try{t=JSON.parse(n)}catch{throw new Error("Invalid JSON")}if(!t.embeddings||!Array.isArray(t.embeddings)||!t.embeddings.length)throw new Error('Missing or empty "embeddings" array');if(!Array.isArray(t.embeddings[0]))throw new Error('"embeddings" must be a 2D array');return t.word_name||(t.word_name=i.name.replace(/_ref\.json$/i,"").replace(/\.json$/i,"")),t}class ue extends EventTarget{constructor(n={}){super(),this._opts={words:n.words??[],refs:n.refs??[],threshold:n.threshold??.65,relaxationMs:n.relaxationMs??2e3,inferenceGapMs:n.inferenceGapMs??300,
|
|
38
|
+
`;let vt=null;function ie(){if(!vt){const i=new Blob([ae],{type:"application/javascript"});vt=URL.createObjectURL(i)}return vt}const wt="mellon_custom_refs";function gt(){try{const i=localStorage.getItem(wt);return i?JSON.parse(i):[]}catch{return[]}}function ce(i){const n=gt().filter(t=>t.word_name!==i.word_name);n.push(i),localStorage.setItem(wt,JSON.stringify(n))}function le(i){const n=gt().filter(t=>t.word_name!==i);localStorage.setItem(wt,JSON.stringify(n))}function he(i){const n=JSON.stringify(i,null,2),t=new Blob([n],{type:"application/json"}),e=URL.createObjectURL(t),o=Object.assign(document.createElement("a"),{href:e,download:`${i.word_name}_ref.json`});document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(e)}async function de(i){const n=await i.text();let t;try{t=JSON.parse(n)}catch{throw new Error("Invalid JSON")}if(!t.embeddings||!Array.isArray(t.embeddings)||!t.embeddings.length)throw new Error('Missing or empty "embeddings" array');if(!Array.isArray(t.embeddings[0]))throw new Error('"embeddings" must be a 2D array');return t.word_name||(t.word_name=i.name.replace(/_ref\.json$/i,"").replace(/\.json$/i,"")),t}class ue extends EventTarget{constructor(n={}){super(),this._opts={words:n.words??[],refs:n.refs??[],threshold:n.threshold??.65,relaxationMs:n.relaxationMs??2e3,inferenceGapMs:n.inferenceGapMs??300,assetsPath:n.assetsPath},this._refs=new Map,this._detectors=new Map,this._audioCtx=null,this._workletNode=null,this._stream=null,this._initialized=!1,this._running=!1}get isInitialized(){return this._initialized}get isRunning(){return this._running}async init(n){if(this._initialized){n==null||n(1);return}this._opts.assetsPath&&Qt({assetsPath:this._opts.assetsPath});try{await Vt(n)}catch(t){throw this.dispatchEvent(new CustomEvent("error",{detail:{error:t}})),t}for(const t of this._opts.refs)try{let e;if(console.log("fetching ref : ",t),typeof t=="string"){const o=await fetch(t);if(!o.ok)throw new Error(`HTTP ${o.status}`);e=await o.json()}else e=t;this.addCustomWord(e)}catch(e){const o=typeof t=="string"?t:t.word_name;console.warn(`[Mellon] Failed to load ref "${o}": ${e.message}`)}this._initialized=!0,this.dispatchEvent(new CustomEvent("ready"))}async start(n){this._initialized||await this.init();const t=n??this._opts.words;try{this._stream=await navigator.mediaDevices.getUserMedia({audio:!0})}catch(s){const a=new Error(`Microphone access denied: ${s.message}`);throw this.dispatchEvent(new CustomEvent("error",{detail:{error:a}})),a}this._audioCtx=new AudioContext({sampleRate:16e3});const e=ie();await this._audioCtx.audioWorklet.addModule(e);const o=this._audioCtx.createMediaStreamSource(this._stream);this._workletNode=new AudioWorkletNode(this._audioCtx,"audio-processor"),o.connect(this._workletNode),this._workletNode.connect(this._audioCtx.destination);for(const s of t){const a=this._refs.get(s);if(!a){console.warn(`[Mellon] No reference embeddings for "${s}" — skipping. Call addCustomWord() to register custom words before start().`);continue}const r=new xt({name:s,refEmbeddings:a.embeddings,threshold:this._opts.threshold,relaxationMs:this._opts.relaxationMs,inferenceGapMs:this._opts.inferenceGapMs});r.addEventListener("match",c=>{this.dispatchEvent(new CustomEvent("match",{detail:c.detail}))}),this._detectors.set(s,r)}this._workletNode.port.onmessage=async s=>{const a=[];for(const r of this._detectors.values())a.push(r.scoreFrame(s.data));await Promise.allSettled(a)},this._running=!0}stop(){this._workletNode&&(this._workletNode.port.onmessage=null,this._workletNode.disconnect(),this._workletNode=null),this._stream&&(this._stream.getTracks().forEach(n=>n.stop()),this._stream=null),this._audioCtx&&(this._audioCtx.close(),this._audioCtx=null),this._detectors.clear(),this._running=!1}addCustomWord(n){if(this._refs.set(n.word_name,n),this._running&&this._workletNode){const t=new xt({name:n.word_name,refEmbeddings:n.embeddings,threshold:this._opts.threshold,relaxationMs:this._opts.relaxationMs,inferenceGapMs:this._opts.inferenceGapMs});t.addEventListener("match",e=>{this.dispatchEvent(new CustomEvent("match",{detail:e.detail}))}),this._detectors.set(n.word_name,t)}}enrollWord(n){return new kt(n)}static loadWords(){return gt()}static saveWord(n){ce(n)}static deleteWord(n){le(n)}static importWordFile(n){return de(n)}static exportWord(n){he(n)}}exports.EnrollmentSession=kt;exports.Mellon=ue;
|
package/dist/mellon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const Ht = "0.0.
|
|
1
|
+
const Ht = "0.0.6", Jt = [1, 1, 149, 64], Kt = `https://cdn.jsdelivr.net/npm/mellon@${Ht}/dist/assets`, st = {
|
|
2
2
|
assetsPath: `${Kt}`
|
|
3
3
|
};
|
|
4
4
|
let I = null, q = null, tt = null;
|
|
@@ -14,9 +14,9 @@ async function Qt(i) {
|
|
|
14
14
|
const a = parseInt(s.headers.get("content-length") || "0", 10), r = s.body.getReader(), c = [];
|
|
15
15
|
let l = 0;
|
|
16
16
|
for (; ; ) {
|
|
17
|
-
const { done: m, value:
|
|
17
|
+
const { done: m, value: _ } = await r.read();
|
|
18
18
|
if (m) break;
|
|
19
|
-
c.push(
|
|
19
|
+
c.push(_), l += _.byteLength, a > 0 && (i == null || i(l / a));
|
|
20
20
|
}
|
|
21
21
|
const h = new Uint8Array(l);
|
|
22
22
|
let d = 0;
|
|
@@ -109,16 +109,16 @@ function Xt() {
|
|
|
109
109
|
a = e / s << 1;
|
|
110
110
|
var m = a >>> 2;
|
|
111
111
|
for (r = 0; r < e; r += a)
|
|
112
|
-
for (var
|
|
113
|
-
const u = g, p = u + m, v = p + m, w = v + m, b = t[u], A = t[u + 1], E = t[p], y = t[p + 1], F = t[v], C = t[v + 1], M = t[w], T = t[w + 1], x = b, R = A, z = d[
|
|
112
|
+
for (var _ = r + m, g = r, f = 0; g < _; g += 2, f += s) {
|
|
113
|
+
const u = g, p = u + m, v = p + m, w = v + m, b = t[u], A = t[u + 1], E = t[p], y = t[p + 1], F = t[v], C = t[v + 1], M = t[w], T = t[w + 1], x = b, R = A, z = d[f], S = h * d[f + 1], N = E * z - y * S, k = E * S + y * z, L = d[2 * f], P = h * d[2 * f + 1], G = F * L - C * P, H = F * P + C * L, J = d[3 * f], K = h * d[3 * f + 1], Y = M * J - T * K, Q = M * K + T * J, V = x + G, j = R + H, B = x - G, X = R - H, Z = N + Y, U = k + Q, $ = h * (N - Y), O = h * (k - Q), et = V + Z, ot = j + U, at = V - Z, it = j - U, ct = B + O, lt = X - $, ht = B - O, dt = X + $;
|
|
114
114
|
t[u] = et, t[u + 1] = ot, t[p] = ct, t[p + 1] = lt, t[v] = at, t[v + 1] = it, t[w] = ht, t[w + 1] = dt;
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
}, i.prototype._singleTransform2 = function(t, e, o) {
|
|
118
|
-
const s = this._out, a = this._data, r = a[e], c = a[e + 1], l = a[e + o], h = a[e + o + 1], d = r + l, m = c + h,
|
|
119
|
-
s[t] = d, s[t + 1] = m, s[t + 2] =
|
|
118
|
+
const s = this._out, a = this._data, r = a[e], c = a[e + 1], l = a[e + o], h = a[e + o + 1], d = r + l, m = c + h, _ = r - l, g = c - h;
|
|
119
|
+
s[t] = d, s[t + 1] = m, s[t + 2] = _, s[t + 3] = g;
|
|
120
120
|
}, i.prototype._singleTransform4 = function(t, e, o) {
|
|
121
|
-
const s = this._out, a = this._data, r = this._inv ? -1 : 1, c = o * 2, l = o * 3, h = a[e], d = a[e + 1], m = a[e + o],
|
|
121
|
+
const s = this._out, a = this._data, r = this._inv ? -1 : 1, c = o * 2, l = o * 3, h = a[e], d = a[e + 1], m = a[e + o], _ = a[e + o + 1], g = a[e + c], f = a[e + c + 1], u = a[e + l], p = a[e + l + 1], v = h + g, w = d + f, b = h - g, A = d - f, E = m + u, y = _ + p, F = r * (m - u), C = r * (_ - p), M = v + E, T = w + y, x = b + C, R = A - F, z = v - E, S = w - y, N = b - C, k = A + F;
|
|
122
122
|
s[t] = M, s[t + 1] = T, s[t + 2] = x, s[t + 3] = R, s[t + 4] = z, s[t + 5] = S, s[t + 6] = N, s[t + 7] = k;
|
|
123
123
|
}, i.prototype._realTransform4 = function() {
|
|
124
124
|
var t = this._out, e = this._csize, o = this._width, s = 1 << o, a = e / s << 1, r, c, l = this._bitrev;
|
|
@@ -135,17 +135,17 @@ function Xt() {
|
|
|
135
135
|
var h = this._inv ? -1 : 1, d = this.table;
|
|
136
136
|
for (s >>= 2; s >= 2; s >>= 2) {
|
|
137
137
|
a = e / s << 1;
|
|
138
|
-
var m = a >>> 1,
|
|
138
|
+
var m = a >>> 1, _ = m >>> 1, g = _ >>> 1;
|
|
139
139
|
for (r = 0; r < e; r += a)
|
|
140
|
-
for (var
|
|
141
|
-
var p = r +
|
|
142
|
-
if (t[p] = ot, t[p + 1] = at, t[v] = it, t[v + 1] = ct,
|
|
143
|
-
var lt =
|
|
140
|
+
for (var f = 0, u = 0; f <= g; f += 2, u += s) {
|
|
141
|
+
var p = r + f, v = p + _, w = v + _, b = w + _, A = t[p], E = t[p + 1], y = t[v], F = t[v + 1], C = t[w], M = t[w + 1], T = t[b], x = t[b + 1], R = A, z = E, S = d[u], N = h * d[u + 1], k = y * S - F * N, L = y * N + F * S, P = d[2 * u], G = h * d[2 * u + 1], H = C * P - M * G, J = C * G + M * P, K = d[3 * u], Y = h * d[3 * u + 1], Q = T * K - x * Y, V = T * Y + x * K, j = R + H, B = z + J, X = R - H, Z = z - J, U = k + Q, $ = L + V, O = h * (k - Q), et = h * (L - V), ot = j + U, at = B + $, it = X + et, ct = Z - O;
|
|
142
|
+
if (t[p] = ot, t[p + 1] = at, t[v] = it, t[v + 1] = ct, f === 0) {
|
|
143
|
+
var lt = j - U, ht = B - $;
|
|
144
144
|
t[w] = lt, t[w + 1] = ht;
|
|
145
145
|
continue;
|
|
146
146
|
}
|
|
147
|
-
if (
|
|
148
|
-
var dt = X, kt = -Z, It =
|
|
147
|
+
if (f !== g) {
|
|
148
|
+
var dt = X, kt = -Z, It = j, Dt = -B, Wt = -h * et, jt = -h * O, Bt = -h * $, Ut = -h * U, $t = dt + Wt, Lt = kt + jt, Pt = It + Ut, Gt = Dt - Bt, yt = r + _ - f, bt = r + m - f;
|
|
149
149
|
t[yt] = $t, t[yt + 1] = Lt, t[bt] = Pt, t[bt + 1] = Gt;
|
|
150
150
|
}
|
|
151
151
|
}
|
|
@@ -154,12 +154,12 @@ function Xt() {
|
|
|
154
154
|
const s = this._out, a = this._data, r = a[e], c = a[e + o], l = r + c, h = r - c;
|
|
155
155
|
s[t] = l, s[t + 1] = 0, s[t + 2] = h, s[t + 3] = 0;
|
|
156
156
|
}, i.prototype._singleRealTransform4 = function(t, e, o) {
|
|
157
|
-
const s = this._out, a = this._data, r = this._inv ? -1 : 1, c = o * 2, l = o * 3, h = a[e], d = a[e + o], m = a[e + c],
|
|
157
|
+
const s = this._out, a = this._data, r = this._inv ? -1 : 1, c = o * 2, l = o * 3, h = a[e], d = a[e + o], m = a[e + c], _ = a[e + l], g = h + m, f = h - m, u = d + _, p = r * (d - _), v = g + u, w = f, b = -p, A = g - u, E = f, y = p;
|
|
158
158
|
s[t] = v, s[t + 1] = 0, s[t + 2] = w, s[t + 3] = b, s[t + 4] = A, s[t + 5] = 0, s[t + 6] = E, s[t + 7] = y;
|
|
159
159
|
}, mt;
|
|
160
160
|
}
|
|
161
161
|
var Zt = Xt();
|
|
162
|
-
const Ot = /* @__PURE__ */ Vt(Zt), nt = 16e3,
|
|
162
|
+
const Ot = /* @__PURE__ */ Vt(Zt), nt = 16e3, W = 512, D = 64, At = Math.floor(0.025 * nt), Ft = Math.floor(0.01 * nt);
|
|
163
163
|
function Ct(i) {
|
|
164
164
|
return 2595 * Math.log10(1 + i / 700);
|
|
165
165
|
}
|
|
@@ -167,11 +167,11 @@ function qt(i) {
|
|
|
167
167
|
return 700 * (10 ** (i / 2595) - 1);
|
|
168
168
|
}
|
|
169
169
|
function te() {
|
|
170
|
-
const i = Ct(0), n = Ct(nt / 2), t = new Float64Array(
|
|
171
|
-
for (let r = 0; r <
|
|
172
|
-
t[r] = i + r * (n - i) / (
|
|
173
|
-
const o = t.map((r) => qt(r)).map((r) => Math.floor((
|
|
174
|
-
for (let r = 0; r <
|
|
170
|
+
const i = Ct(0), n = Ct(nt / 2), t = new Float64Array(D + 2);
|
|
171
|
+
for (let r = 0; r < D + 2; r++)
|
|
172
|
+
t[r] = i + r * (n - i) / (D + 1);
|
|
173
|
+
const o = t.map((r) => qt(r)).map((r) => Math.floor((W + 1) * r / nt)), s = [], a = Math.floor(W / 2) + 1;
|
|
174
|
+
for (let r = 0; r < D; r++) {
|
|
175
175
|
const c = new Float32Array(a);
|
|
176
176
|
for (let l = o[r]; l < o[r + 1]; l++) c[l] = (l - o[r]) / (o[r + 1] - o[r]);
|
|
177
177
|
for (let l = o[r + 1]; l < o[r + 2]; l++) c[l] = (o[r + 2] - l) / (o[r + 2] - o[r + 1]);
|
|
@@ -179,24 +179,24 @@ function te() {
|
|
|
179
179
|
}
|
|
180
180
|
return s;
|
|
181
181
|
}
|
|
182
|
-
const ee = te(), rt = new Ot(
|
|
182
|
+
const ee = te(), rt = new Ot(W), ft = new Float32Array(W), Mt = rt.createComplexArray(), _t = rt.createComplexArray(), Tt = new Float32Array(Math.floor(W / 2) + 1);
|
|
183
183
|
function Nt(i) {
|
|
184
|
-
const n = 1 + Math.ceil((i.length - At) / Ft), t = new Float32Array(n *
|
|
184
|
+
const n = 1 + Math.ceil((i.length - At) / Ft), t = new Float32Array(n * D), e = Math.floor(W / 2) + 1;
|
|
185
185
|
for (let o = 0; o < n; o++) {
|
|
186
186
|
const s = o * Ft;
|
|
187
|
-
|
|
187
|
+
ft.fill(0);
|
|
188
188
|
for (let a = 0; a < At && s + a < i.length; a++)
|
|
189
|
-
|
|
190
|
-
rt.toComplexArray(
|
|
189
|
+
ft[a] = i[s + a];
|
|
190
|
+
rt.toComplexArray(ft, Mt), rt.transform(_t, Mt);
|
|
191
191
|
for (let a = 0; a < e; a++) {
|
|
192
|
-
const r =
|
|
192
|
+
const r = _t[2 * a], c = _t[2 * a + 1], l = (r * r + c * c) / W;
|
|
193
193
|
Tt[a] = l === 0 ? 1e-30 : l;
|
|
194
194
|
}
|
|
195
|
-
for (let a = 0; a <
|
|
195
|
+
for (let a = 0; a < D; a++) {
|
|
196
196
|
const r = ee[a];
|
|
197
197
|
let c = 0;
|
|
198
198
|
for (let l = 0; l < e; l++) c += Tt[l] * r[l];
|
|
199
|
-
t[o *
|
|
199
|
+
t[o * D + a] = Math.log(c === 0 ? 1e-30 : c);
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
return t;
|
|
@@ -436,8 +436,7 @@ class ue extends EventTarget {
|
|
|
436
436
|
* @param {number} [opts.threshold=0.65] Detection threshold [0, 1]
|
|
437
437
|
* @param {number} [opts.relaxationMs=2000] Min ms between successive match events
|
|
438
438
|
* @param {number} [opts.inferenceGapMs=300] Min ms between inference runs
|
|
439
|
-
* @param {string} [opts.
|
|
440
|
-
* @param {string} [opts.modelUrl] Override model.onnx URL (offline use)
|
|
439
|
+
* @param {string} [opts.assetsPath]
|
|
441
440
|
*/
|
|
442
441
|
constructor(n = {}) {
|
|
443
442
|
super(), this._opts = {
|
|
@@ -446,8 +445,7 @@ class ue extends EventTarget {
|
|
|
446
445
|
threshold: n.threshold ?? 0.65,
|
|
447
446
|
relaxationMs: n.relaxationMs ?? 2e3,
|
|
448
447
|
inferenceGapMs: n.inferenceGapMs ?? 300,
|
|
449
|
-
|
|
450
|
-
modelUrl: n.modelUrl
|
|
448
|
+
assetsPath: n.assetsPath
|
|
451
449
|
}, this._refs = /* @__PURE__ */ new Map(), this._detectors = /* @__PURE__ */ new Map(), this._audioCtx = null, this._workletNode = null, this._stream = null, this._initialized = !1, this._running = !1;
|
|
452
450
|
}
|
|
453
451
|
/** Whether init() has completed successfully. */
|
|
@@ -471,10 +469,7 @@ class ue extends EventTarget {
|
|
|
471
469
|
n == null || n(1);
|
|
472
470
|
return;
|
|
473
471
|
}
|
|
474
|
-
|
|
475
|
-
wasmBasePath: this._opts.wasmBasePath,
|
|
476
|
-
modelUrl: this._opts.modelUrl
|
|
477
|
-
});
|
|
472
|
+
this._opts.assetsPath && Yt({ assetsPath: this._opts.assetsPath });
|
|
478
473
|
try {
|
|
479
474
|
await Qt(n);
|
|
480
475
|
} catch (t) {
|
|
@@ -483,7 +478,7 @@ class ue extends EventTarget {
|
|
|
483
478
|
for (const t of this._opts.refs)
|
|
484
479
|
try {
|
|
485
480
|
let e;
|
|
486
|
-
if (typeof t == "string") {
|
|
481
|
+
if (console.log("fetching ref : ", t), typeof t == "string") {
|
|
487
482
|
const o = await fetch(t);
|
|
488
483
|
if (!o.ok) throw new Error(`HTTP ${o.status}`);
|
|
489
484
|
e = await o.json();
|
package/package.json
CHANGED