@equos/browser 1.0.3 → 1.0.5
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.js +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var r=(s=>(s.USR_AUDIO="usr-audio",s.AGT_AUDIO="agt-audio",s.UTTERANCE="utterance",s.INTERRUPT="interrupt",s.NWK_ERROR="nwk-error",s.SRV_ERROR="srv-error",s.TOKEN_EXP="token-exp",s.VID_FRAME="vid-frame",s.AUD_CHUNK="aud-chunk",s.AUD_FEATS="aud-feats",s.RDR_FRAME="rdr-frame",s))(r||{});const A=16e3;var I=(s=>(s.INTERRUPT="interrupt",s.AGT_AUDIO="agt-audio",s.STOP_WRKL="stop",s.AUD_CHUNK="frame",s.RDR_FRAME="render",s))(I||{});class T{constructor(t){this.t=t,this.i=new AudioContext({latencyHint:"interactive",sampleRate:A}),this.t.addListener(r.AGT_AUDIO,this.o.bind(this)),this.t.addListener(r.INTERRUPT,this.h.bind(this))}i;l=null;async init(){return this.i.audioWorklet.addModule(new URL("data:video/mp2t;base64,aW1wb3J0IHsKICBBVURJT19TQU1QTEVfUkFURSwKICBGUkFNRV9DSFVOS19TSVpFLAogIFJBV19DSFVOS19TSVpFLAp9IGZyb20gJy4uLy4uL2NvbnN0YW50cyc7CmltcG9ydCB7CiAgQWdlbnRBdWRpb0Rpc3BhdGNoZXJJbmJvdW5kTXNnLAogIEFnZW50QXVkaW9EaXNwYXRjaGVyTWVzc2FnZXMsCiAgV09SS0xFVF9OQU1FLAp9IGZyb20gJy4vY29udHJhY3QnOwoKY2xhc3MgQWdlbnRBdWRpb1dvcmtsZXQgZXh0ZW5kcyBBdWRpb1dvcmtsZXRQcm9jZXNzb3IgewogIHByaXZhdGUgX2FjY3VtdWxhdG9yID0gbmV3IEZsb2F0MzJBcnJheSgwKTsKCiAgcHJpdmF0ZSBfc3RvcHBlZDogYm9vbGVhbiA9IGZhbHNlOwoKICAvLyBEZWxheSBiZXR3ZWVuIGVtaXR0aW5nIGNodW5rIGFuZCBwbGF5YmFjay4KICBwcml2YXRlIHJlYWRvbmx5IF9kZWxheUluTXM6IG51bWJlciA9IDQwMDsKICBwcml2YXRlIHJlYWRvbmx5IF9kZWxheUluU2FtcGxlczogbnVtYmVyID0gTWF0aC5yb3VuZCgKICAgIChBVURJT19TQU1QTEVfUkFURSAqIHRoaXMuX2RlbGF5SW5NcykgLyAxMDAwCiAgKTsKCiAgLy8gTG9vayBhaGVhZCBmb3IgcmVuZGVyIGVtaXRzLgogIHByaXZhdGUgcmVhZG9ubHkgX3JlbmRlckxvb2tBaGVhZEluTXM6IG51bWJlciA9IDIyMDsKICBwcml2YXRlIHJlYWRvbmx5IF9yZW5kZXJMb29rQWhlYWRJblNhbXBsZXM6IG51bWJlciA9IE1hdGgucm91bmQoCiAgICAoQVVESU9fU0FNUExFX1JBVEUgKiB0aGlzLl9yZW5kZXJMb29rQWhlYWRJbk1zKSAvIDEwMDAKICApOwoKICAvLyBTYW1wbGVzIHRoYXQgaGF2ZSBiZWVuIGVtaXR0ZWQgYnV0IG5vdCB5ZXQgcGxheWVkLgogIHByaXZhdGUgX3BlbmRpbmdTYW1wbGVzOiBGbG9hdDMyQXJyYXlbXSA9IFsKICAgIG5ldyBGbG9hdDMyQXJyYXkodGhpcy5fZGVsYXlJblNhbXBsZXMpLAogIF07CgogIC8vIFJlYWQgaW5kZXggd2l0aGluIHRoZSBmaXJzdCBwZW5kaW5nIGNodW5rLgogIHByaXZhdGUgX3BlbmRpbmdSZWFkSW5kZXg6IG51bWJlciA9IDA7CgogIC8vIEZhZGUtaW4gbGVuZ3RoIHRvIGF2b2lkIGNsaWNrIGF0IHNpbGVuY2XihpJhdWRpbyB0cmFuc2l0aW9uLgogIHByaXZhdGUgcmVhZG9ubHkgX2ZhZGVJblNhbXBsZXM6IG51bWJlciA9IE1hdGgucm91bmQoCiAgICAoQVVESU9fU0FNUExFX1JBVEUgKiA0MCkgLyAxMDAwCiAgKTsgLy8gNDBtcwoKICAvLyBXaGV0aGVyIHRoZSBmaXJzdCByZWFsIGNodW5rIHN0aWxsIG5lZWRzIGEgZmFkZS1pbiByYW1wLgogIHByaXZhdGUgX25lZWRzRmFkZUluOiBib29sZWFuID0gdHJ1ZTsKCiAgLy8gU2FtcGxlcyBiZWZvcmUgbmV4dCBlbWl0LiBJbml0IHdpdGggMCB0byBlbWl0IGltbWVkaWF0ZWx5LgogIHByaXZhdGUgX3NhbXBsZXNVbnRpbE5leHRFbWl0OiBudW1iZXIgPSAwOwoKICAvLyBTYW1wbGVzIGJlZm9yZSBuZXh0IHJlbmRlciByZXF1ZXN0LgogIHByaXZhdGUgX3NhbXBsZXNVbnRpbE5leHRSZW5kZXI6IG51bWJlciA9CiAgICB0aGlzLl9kZWxheUluU2FtcGxlcyAtIHRoaXMuX3JlbmRlckxvb2tBaGVhZEluU2FtcGxlczsKCiAgLy8gQ291bnQgc2FtcGxlcyBwbGF5ZWQsIGZvciBhY2N1cmF0ZSBQVFMgY2FsY3VsYXRpb24uCiAgcHJpdmF0ZSBfcGxheWVkU2FtcGxlczogbnVtYmVyID0gMDsKCiAgY29uc3RydWN0b3IoKSB7CiAgICBzdXBlcigpOwoKICAgIHRoaXMucG9ydC5vbm1lc3NhZ2UgPSAoZTogTWVzc2FnZUV2ZW50PEFnZW50QXVkaW9EaXNwYXRjaGVySW5ib3VuZE1zZz4pID0+IHsKICAgICAgaWYgKGUuZGF0YS50eXBlID09PSBBZ2VudEF1ZGlvRGlzcGF0Y2hlck1lc3NhZ2VzLkFHVF9BVURJTykgewogICAgICAgIHRoaXMuX29uQXVkaW8oZS5kYXRhLmF1ZGlvKTsKICAgICAgfSBlbHNlIGlmIChlLmRhdGEudHlwZSA9PT0gQWdlbnRBdWRpb0Rpc3BhdGNoZXJNZXNzYWdlcy5JTlRFUlJVUFQpIHsKICAgICAgICB0aGlzLl9vbkludGVycnVwdCgpOwogICAgICB9IGVsc2UgaWYgKGUuZGF0YS50eXBlID09PSBBZ2VudEF1ZGlvRGlzcGF0Y2hlck1lc3NhZ2VzLlNUT1BfV1JLTCkgewogICAgICAgIHRoaXMuX3N0b3BwZWQgPSB0cnVlOwogICAgICB9CiAgICB9OwogIH0KCiAgcHJpdmF0ZSBnZXQgX2N1cnJlbnRQdHMoKTogbnVtYmVyIHsKICAgIC8vIFBUUyBpcyBpbiBtaWNyb2Vjb25kcy4KICAgIHJldHVybiBNYXRoLnJvdW5kKCh0aGlzLl9wbGF5ZWRTYW1wbGVzIC8gQVVESU9fU0FNUExFX1JBVEUpICogMV8wMDBfMDAwKTsKICB9CgogIHByaXZhdGUgX29uQXVkaW8oYXVkaW86IEZsb2F0MzJBcnJheSk6IHZvaWQgewogICAgY29uc3QgbmV3QWNjID0gbmV3IEZsb2F0MzJBcnJheSh0aGlzLl9hY2N1bXVsYXRvci5sZW5ndGggKyBhdWRpby5sZW5ndGgpOwogICAgbmV3QWNjLnNldCh0aGlzLl9hY2N1bXVsYXRvciwgMCk7CiAgICBuZXdBY2Muc2V0KGF1ZGlvLCB0aGlzLl9hY2N1bXVsYXRvci5sZW5ndGgpOwogICAgdGhpcy5fYWNjdW11bGF0b3IgPSBuZXdBY2M7CiAgfQoKICBwcml2YXRlIF9vbkludGVycnVwdCgpOiB2b2lkIHsKICAgIHRoaXMuX2FjY3VtdWxhdG9yID0gbmV3IEZsb2F0MzJBcnJheSgwKTsKICB9CgogIHByb2Nlc3MoX2lucHV0czogRmxvYXQzMkFycmF5W11bXSwgb3V0cHV0czogRmxvYXQzMkFycmF5W11bXSk6IGJvb2xlYW4gewogICAgaWYgKHRoaXMuX3N0b3BwZWQpIHsKICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQoKICAgIGNvbnN0IHNhbXBsZXNUb1dyaXRlID0gb3V0cHV0c1swXVswXS5sZW5ndGg7CgogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzYW1wbGVzVG9Xcml0ZTsgaSsrKSB7CiAgICAgIGlmICh0aGlzLl9zYW1wbGVzVW50aWxOZXh0RW1pdCA9PT0gMCkgewogICAgICAgIC8vIEVtaXQgbmV3IGNodW5rLCBhbmQgYXBwZW5kIHRvIHBlbmRpbmcgc2FtcGxlcy4KICAgICAgICAvLyBQVFMgc2hvdWxkIGJlIGJlZ2lubmluZyBvZiB0aGUgY2h1bmsuCiAgICAgICAgdGhpcy5fZmVlZCgpOwogICAgICAgIHRoaXMuX3NhbXBsZXNVbnRpbE5leHRFbWl0ID0gUkFXX0NIVU5LX1NJWkU7CiAgICAgIH0KCiAgICAgIGlmICh0aGlzLl9zYW1wbGVzVW50aWxOZXh0UmVuZGVyID09PSAwKSB7CiAgICAgICAgLy8gRW1pdCByZW5kZXIgcmVxdWVzdC4KICAgICAgICAvLyBQVFMgc2hvdWxkIGJlIGN1cnJlbnQgdGltZSArIGxvb2sgYWhlYWQuCiAgICAgICAgdGhpcy5fcmVuZGVyKCk7CiAgICAgICAgdGhpcy5fc2FtcGxlc1VudGlsTmV4dFJlbmRlciA9IEZSQU1FX0NIVU5LX1NJWkU7CiAgICAgIH0KCiAgICAgIGlmICh0aGlzLl9wZW5kaW5nU2FtcGxlcy5sZW5ndGggPT09IDApIHsKICAgICAgICBjb25zb2xlLndhcm4oJ0F1ZGlvIHVuZGVyZmxvdzogbm8gcGVuZGluZyBzYW1wbGVzIHRvIHBsYXkuJyk7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KCiAgICAgIGlmICh0aGlzLl9wZW5kaW5nUmVhZEluZGV4ID49IHRoaXMuX3BlbmRpbmdTYW1wbGVzWzBdLmxlbmd0aCkgewogICAgICAgIHRoaXMuX3BlbmRpbmdTYW1wbGVzLnNoaWZ0KCk7CiAgICAgICAgdGhpcy5fcGVuZGluZ1JlYWRJbmRleCA9IDA7CgogICAgICAgIGlmICh0aGlzLl9wZW5kaW5nU2FtcGxlcy5sZW5ndGggPT09IDApIHsKICAgICAgICAgIGNvbnNvbGUud2FybignQXVkaW8gdW5kZXJmbG93OiBubyBwZW5kaW5nIHNhbXBsZXMgdG8gcGxheS4nKTsKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgfQoKICAgICAgY29uc3Qgc2FtcGxlID0gdGhpcy5fcGVuZGluZ1NhbXBsZXNbMF1bdGhpcy5fcGVuZGluZ1JlYWRJbmRleF07CgogICAgICBmb3IgKGxldCBjaGFubmVsID0gMDsgY2hhbm5lbCA8IG91dHB1dHNbMF0ubGVuZ3RoOyBjaGFubmVsKyspIHsKICAgICAgICBvdXRwdXRzWzBdW2NoYW5uZWxdW2ldID0gc2FtcGxlOwogICAgICB9CgogICAgICB0aGlzLl9wZW5kaW5nUmVhZEluZGV4Kys7CgogICAgICB0aGlzLl9wbGF5ZWRTYW1wbGVzKys7CgogICAgICB0aGlzLl9zYW1wbGVzVW50aWxOZXh0RW1pdC0tOwogICAgICB0aGlzLl9zYW1wbGVzVW50aWxOZXh0UmVuZGVyLS07CiAgICB9CgogICAgcmV0dXJuIHRydWU7CiAgfQoKICBwcml2YXRlIF9mZWVkKCk6IHZvaWQgewogICAgY29uc3QgY2h1bmsgPSBuZXcgRmxvYXQzMkFycmF5KFJBV19DSFVOS19TSVpFKTsKCiAgICAvLyBGaWxsIGNodW5rIHdpdGggYnVmZmVyZWQgZGF0YSB1cCB0byBpdHMgY2FwYWNpdHkuCiAgICBjb25zdCBuID0gTWF0aC5taW4oY2h1bmsubGVuZ3RoLCB0aGlzLl9hY2N1bXVsYXRvci5sZW5ndGgpOwogICAgY2h1bmsuc2V0KHRoaXMuX2FjY3VtdWxhdG9yLnN1YmFycmF5KDAsIG4pLCAwKTsKICAgIC8vIFJlbW92ZSBlbWl0dGVkIGRhdGEgZnJvbSBhY2N1bXVsYXRvci4KICAgIHRoaXMuX2FjY3VtdWxhdG9yID0gdGhpcy5fYWNjdW11bGF0b3Iuc3ViYXJyYXkobik7CgogICAgaWYgKHRoaXMuX25lZWRzRmFkZUluKSB7CiAgICAgIGNvbnN0IGxlbiA9IE1hdGgubWluKHRoaXMuX2ZhZGVJblNhbXBsZXMsIGNodW5rLmxlbmd0aCk7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspIHsKICAgICAgICBjaHVua1tpXSAqPSBpIC8gbGVuOwogICAgICB9CiAgICAgIHRoaXMuX25lZWRzRmFkZUluID0gZmFsc2U7CiAgICB9CgogICAgdGhpcy5fcGVuZGluZ1NhbXBsZXMucHVzaChjaHVuayk7CgogICAgLy8gVE9ETzogdmVyaWZ5IGRlbGF5IGlzIHBlcmZlY3RseSBjb25zdGFudCwKICAgIC8vIGFuZCBpZiBub3QgdXNlIG51bWJlciBvZiBwZW5kaW5nIHNhbXBsZXMgdG8gY2FsY3VsYXRlIGV4YWN0IFBUUy4KICAgIGNvbnN0IGNodW5rUHRzID0gdGhpcy5fY3VycmVudFB0cyArIHRoaXMuX2RlbGF5SW5NcyAqIDEwMDA7CgogICAgY29uc3QgZnJhbWUgPSBuZXcgRmxvYXQzMkFycmF5KGNodW5rKTsKICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZSgKICAgICAgewogICAgICAgIHR5cGU6IEFnZW50QXVkaW9EaXNwYXRjaGVyTWVzc2FnZXMuQVVEX0NIVU5LLAogICAgICAgIGNodW5rOiBmcmFtZSwKICAgICAgICBwdHM6IGNodW5rUHRzLAogICAgICB9LAogICAgICBbZnJhbWUuYnVmZmVyXQogICAgKTsKICB9CgogIHByaXZhdGUgX3JlbmRlcigpOiB2b2lkIHsKICAgIGNvbnN0IHJlbmRlclB0cyA9IHRoaXMuX2N1cnJlbnRQdHMgKyB0aGlzLl9yZW5kZXJMb29rQWhlYWRJbk1zICogMTAwMDsKICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZSh7CiAgICAgIHR5cGU6IEFnZW50QXVkaW9EaXNwYXRjaGVyTWVzc2FnZXMuUkRSX0ZSQU1FLAogICAgICBwdHM6IHJlbmRlclB0cywKICAgIH0pOwogIH0KfQoKcmVnaXN0ZXJQcm9jZXNzb3IoV09SS0xFVF9OQU1FLCBBZ2VudEF1ZGlvV29ya2xldCk7Cg==",import.meta.url))}async start(){this.l&&(this.l.disconnect(),this.l=null),this.l=new AudioWorkletNode(this.i,"agt-audio-worklet",{numberOfInputs:0,numberOfOutputs:1,outputChannelCount:[1]}),this.l.connect(this.i.destination),this.l.port.onmessage=async t=>{const e=t.data;e.type===I.AUD_CHUNK?this.t.emit(r.AUD_CHUNK,e.chunk,e.pts):e.type===I.RDR_FRAME&&this.t.emit(r.RDR_FRAME,e.pts)},this.i.state!=="running"&&await this.i.resume()}async stop(){return this.l?.port.postMessage({type:I.STOP_WRKL}),this.l?.disconnect(),this.l=null,this.i.suspend()}async destroy(){return await this.stop(),this.i.close()}async o(t){return this.l?.port.postMessage({type:I.AGT_AUDIO,audio:t},[t.buffer])}async h(){return this.l?.port.postMessage({type:I.INTERRUPT})}}class U{t=new EventTarget;u=new AbortController;p=[];emit(t,...e){return this.t.dispatchEvent(new CustomEvent(t,{detail:e}))}addListener(t,e){const i=new AbortController;this.u.signal.addEventListener("abort",()=>i.abort()),this.t.addEventListener(t,n=>{const c=n.detail;e(...c)},{signal:i.signal}),this.p.push({event:t,handler:e,ctrl:i})}removeListener(t,e){const i=this.p.findIndex(n=>n.event===t&&n.handler===e);i!==-1&&(this.p[i].ctrl.abort(),this.p.splice(i,1))}destroy(){this.u.abort(),this.p.length=0}}class S{constructor(t,e,i){this.I=t,this.m=e,this.t=i,this.t.addListener(r.USR_AUDIO,this._.bind(this))}async destroy(){return this.t.removeListener(r.USR_AUDIO,this._.bind(this)),this.disconnect()}_(t){const e=new ArrayBuffer(t.byteLength);return new Uint8Array(e).set(new Uint8Array(t.buffer,t.byteOffset,t.byteLength)),this.C(e)}}function h(){let s,t;return{promise:new Promise((e,i)=>{s=e,t=i}),resolve:s,reject:t}}var l=(s=>(s.PING="ping",s.USE="use",s.START="start",s.STOP="stop",s.TOKEN_REFRESH="token.refresh",s.PONG="pong",s.USING="using",s.STARTED="started",s.STOPPED="stopped",s.INTERRUPT="interrupt",s.UTTERANCE="utterance",s.TOKEN_EXPIRING="token.expiring",s.ERROR="error",s))(l||{}),a=(s=>(s.TOKEN_MISSING="TOKEN_MISSING",s.TOKEN_EXPIRED="TOKEN_EXPIRED",s.TOKEN_SIGNATURE_INVALID="TOKEN_SIGNATURE_INVALID",s.TOKEN_MALFORMED="TOKEN_MALFORMED",s.TOKEN_MALFORMED_CLAIMS="TOKEN_MALFORMED_CLAIMS",s.CHARACTER_NOT_FOUND="CHARACTER_NOT_FOUND",s.CHARACTER_NOT_FETCHED="CHARACTER_NOT_FETCHED",s.CONVERSATION_TIMEOUT="CONVERSATION_TIMEOUT",s.CONVERSATION_ENDED_PREMATURELY="CONVERSATION_ENDED_PREMATURELY",s.USER_BUSY="USER_BUSY",s))(a||{});class V extends S{constructor(t,e,i){super(t,e,i),this.endpoint=t,this.accessToken=e,this.bus=i}A=null;v=null;G=null;B=null;R=null;V=0;W=null;Z=!1;get resolvedUrl(){return`${this.endpoint}?token=${this.accessToken}`}async connect(){return this.A=new WebSocket(this.resolvedUrl),this.A.binaryType="arraybuffer",this.A.onopen=this.onOpen.bind(this),this.A.onclose=this.onClose.bind(this),this.A.onmessage=this.onMsg.bind(this),this.v=h(),this.v.promise}async disconnect(){this.Z=!0,this.A?.close(),this.A=null,this.v?.reject(new Error("pipeline disconnected")),this.v=null,this.G?.reject(new Error("pipeline disconnected")),this.G=null,this.B?.reject(new Error("pipeline disconnected")),this.B=null,this.R?.reject(new Error("pipeline disconnected")),this.R=null}async use(t){this.R=h();const e={type:l.USE,character:t};return await this.C(e),this.R.promise}async start(t){this.G=h();const e={type:l.START,conversation:t};return await this.C(e),this.G.promise}async stop(){this.B=h();const t={type:l.STOP};return await this.C(t),this.B.promise}async refreshToken(t){this.accessToken=t;const e={type:l.TOKEN_REFRESH,access_token:t};await this.C(e)}async C(t){this.A&&this.A.readyState===WebSocket.OPEN&&(t instanceof ArrayBuffer?this.A.send(t):this.A.send(JSON.stringify(t)))}onOpen(){this.v?.resolve(),this.v=null,this.V=0,this.W&&clearInterval(this.W);const t={type:l.PING};this.W=setInterval(()=>{this.C(t)},1e4)}onClose(t){this.v?.reject(new Error("WebSocket closed before ready")),this.v=null,this.G?.reject(new Error("WebSocket closed before start")),this.G=null,this.B?.reject(new Error("WebSocket closed before stop")),this.B=null,this.R?.reject(new Error("WebSocket closed before use")),this.R=null,this.W&&clearInterval(this.W);const e=t.reason;if(e)this.handleCloseReason(e);else if(!this.Z){if(this.V++,this.V<3){const i=1e3*2**(this.V-1);setTimeout(()=>{this.connect().catch(()=>null)},i)}this.bus.emit(r.NWK_ERROR,this.V>=3)}}handleCloseReason(t){switch(t){case a.TOKEN_MISSING:case a.TOKEN_EXPIRED:case a.TOKEN_SIGNATURE_INVALID:case a.TOKEN_MALFORMED:case a.TOKEN_MALFORMED_CLAIMS:case a.CHARACTER_NOT_FOUND:case a.CHARACTER_NOT_FETCHED:case a.CONVERSATION_TIMEOUT:case a.CONVERSATION_ENDED_PREMATURELY:case a.USER_BUSY:this.bus.emit(r.SRV_ERROR,t);break;default:console.warn(`[Connector] Unknown close reason: ${t}`),this.bus.emit(r.SRV_ERROR,"UNKNOWN_REASON")}}onMsg(t){if(t.data instanceof ArrayBuffer){const e=new Float32Array(t.data);return void this.bus.emit(r.AGT_AUDIO,e)}try{const e=JSON.parse(t.data);switch(e.type){case l.PONG:break;case l.USING:this.X(e.audio_model_url,e.video_model_url,e.video_url);break;case l.STARTED:this.F();break;case l.STOPPED:this.U();break;case l.INTERRUPT:this.h();break;case l.UTTERANCE:this.k(e.utterance);break;case l.TOKEN_EXPIRING:this.S();break;case l.ERROR:this.N(e.code);break;default:console.warn(`[Connector] Unknown message: ${e.type}`)}}catch(e){console.error("[Connector] Failed to parse WS message:",e)}}X(t,e,i){this.R?.resolve({audioModelUrl:t,videoModelUrl:e,videoUrl:i}),this.R=null}F(){this.G?.resolve(),this.G=null}U(){this.B?.resolve(),this.B=null}h(){this.bus.emit(r.INTERRUPT)}k(t){this.bus.emit(r.UTTERANCE,t)}S(){this.bus.emit(r.TOKEN_EXP)}N(t){switch(t){case a.TOKEN_MISSING:case a.TOKEN_EXPIRED:case a.TOKEN_SIGNATURE_INVALID:case a.TOKEN_MALFORMED:case a.TOKEN_MALFORMED_CLAIMS:case a.CHARACTER_NOT_FOUND:case a.CHARACTER_NOT_FETCHED:this.R?.reject(new Error(t)),this.R=null,this.G?.reject(new Error(t)),this.G=null;break;case a.CONVERSATION_TIMEOUT:case a.CONVERSATION_ENDED_PREMATURELY:case a.USER_BUSY:this.G?.reject(new Error(t)),this.G=null;break;default:console.warn(`[Connector] Unknown error code: ${t}`)}this.bus.emit(r.SRV_ERROR,t)}}class B{static new(t,e,i){return new V(t,e,i)}}const C="AES-GCM";class m{constructor(t){this.T=t,this.M=new Map}static SALT_STORAGE_KEY="https://encryption-salt.equos.ai";M;Y=new Map;D=null;O(t){try{const e=new URL(t);return e.search="",e.toString()}catch{return t}}async synchronize(){return await this.H(),this.K()}async fetch(t){const e=this.O(t),i=this.M.get(e);if(i?.objectUrl)return console.log(`Cache hit for ${t}`),i.objectUrl;const n=this.Y.get(e);if(n)return n.promise;const c=h();this.Y.set(e,c);try{let o=null;if(i?.status==="cached"){const b=await this.L(e).catch(()=>null);b&&(o=await this.J(b),this.P(e,o))}if(!o){const b=await this.j(t,e);o=await this.J(b.clone()),this.P(e,o),this.q(b).then(R=>this.$(e,R)).then(()=>this.tt(e,o)).catch(R=>console.warn(`Failed to store asset ${t} in cache:`,R))}c.resolve(o)}catch(o){c.reject(o)}finally{this.Y.delete(e)}return c.promise}async destroy(){this.M.forEach(t=>{t.objectUrl&&URL.revokeObjectURL(t.objectUrl)}),this.Y.forEach(t=>t.reject(new Error("Storage destroyed"))),this.Y.clear(),this.M.clear(),this.D=null}async j(t,e){this.et(e);const i=await fetch(t);if(i.ok)return i;throw this.st(e),new Error(`Failed to fetch ${t}: ${i.statusText}`)}async L(t){const e=await this.it(t);return e?this.nt(e).catch(async i=>(console.log(`Failed to decrypt ${t}, clearing storage`,i),this.D=null,this.M.clear(),await this.rt(),null)):(this.st(t),null)}async J(t){const e=await t.blob();return URL.createObjectURL(e)}st(t){this.M.delete(t)}async ot(){const t=await this.it(m.SALT_STORAGE_KEY);if(t)return new Uint8Array(await t.arrayBuffer());await this.rt();const e=crypto.getRandomValues(new Uint8Array(16));return await this.$(m.SALT_STORAGE_KEY,new Response(e)),e}async H(){if(!this.D){const t=new TextEncoder,e=t.encode(this.T),i=await this.ot(),n=await crypto.subtle.importKey("raw",e,"HKDF",!1,["deriveKey"]);this.D=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:t.encode("equos-storage")},n,{name:C,length:256},!1,["encrypt","decrypt"])}return this.D}async q(t){const e=await this.H(),i=crypto.getRandomValues(new Uint8Array(12)),n=await t.arrayBuffer(),c=await crypto.subtle.encrypt({name:C,iv:i},e,n),o=new Uint8Array(12+c.byteLength);return o.set(i,0),o.set(new Uint8Array(c),12),new Response(o,{headers:t.headers,status:t.status,statusText:t.statusText})}async nt(t){const e=await this.H(),i=new Uint8Array(await t.arrayBuffer()),n=i.slice(0,12),c=i.slice(12),o=await crypto.subtle.decrypt({name:C,iv:n},e,c);return new Response(o,{headers:t.headers,status:t.status,statusText:t.statusText})}et(t){this.M.set(t,{status:"loading",objectUrl:null})}P(t,e){this.M.set(t,{status:"loaded",objectUrl:e})}tt(t,e){this.M.set(t,{status:"cached",objectUrl:e})}}class N extends m{ht;constructor(t){super(t),this.ht="equos-storage-v1"}async K(){(await(await caches.open(this.ht)).keys()).forEach(e=>{const i=this.O(e.url);i!==m.SALT_STORAGE_KEY&&this.tt(i,null)})}async $(t,e){await(await caches.open(this.ht)).put(t,e.clone())}async it(t){return(await caches.open(this.ht)).match(t)}async rt(){const t=await caches.open(this.ht),e=await t.keys();await Promise.all(e.map(i=>t.delete(i)))}}class O{static new(t){return new N(t)}}const E=`import*as t from"onnxruntime-web/webgpu";import{AveProcessor as e}from"@equos/audio-processor";var s=/* @__PURE__ */(t=>(t.INIT="init",t.AUD_CHUNK="audio-chunk",t.RESET="reset",t.DESTROY="destroy",t.LOADED="loaded",t.READY="ready",t.AUD_FEATS="audio-features",t.DESTROYED="destroyed",t.ERROR="error",t))(s||{});const i=8192;t.env.wasm.wasmPaths="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.2/dist/";const n=new class{gpu=null;processor=null;session=null;async init(i){if(this.gpu=await async function(){const t=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(!t)return null;const e=["shader-f16","bgra8unorm-storage","rg11b10ufloat-renderable","float32-filterable"].filter(e=>t.features.has(e)),s=await t.requestDevice({requiredFeatures:e});return GPUAdapter.prototype.requestDevice=async function(){return s},navigator.gpu.requestAdapter=async()=>t,s}(),!this.gpu)return void console.error("Failed to create GPU device.");this.processor=new e,this.session=await t.InferenceSession.create(i,{executionProviders:["webgpu"],preferredOutputLocation:"gpu-buffer",graphOptimizationLevel:"all",logSeverityLevel:3});const n={type:s.READY};self.postMessage(n)}async push(e,n){if(!this.gpu||!this.session||!this.processor)return void console.error("Audio worker not initialized, dropping audio batch...");let r=null;try{const a=this.processor.push(e);if(!a)return;const o=a.length/1280;r=new t.Tensor("float32",a,[o,1,80,16]);const l=await this.session.run({[this.session.inputNames[0]]:r}),c=await l[this.session.outputNames[0]].getData(),u=this.processor.push_features(c);if(u&&u.byteLength>0){const t=u.length/i;for(let e=0;e<t;e++){const t=new Float32Array(u.subarray(e*i,(e+1)*i)),r={type:s.AUD_FEATS,features:t,pts:n+4e4*e};self.postMessage(r,[t.buffer])}}}finally{r?.dispose()}}async reset(){this.processor?.free(),this.processor=new e}async destroy(){await(this.session?.release()),this.session=null,this.processor.free();const t={type:s.DESTROYED};self.postMessage(t)}};self.onmessage=async t=>{const e=t.data;try{e.type===s.INIT?await n.init(e.model):e.type===s.AUD_CHUNK?await n.push(e.chunk,e.pts):e.type===s.RESET?await n.reset():e.type===s.DESTROY&&await n.destroy()}catch(i){const t={type:s.ERROR,data:i};self.postMessage(t)}};const r={type:s.LOADED};self.postMessage(r);
|
|
2
|
-
`,_=typeof self<"u"&&self.Blob&&new Blob(["URL.revokeObjectURL(import.meta.url);",E],{type:"text/javascript;charset=utf-8"});function W(s){let t;try{if(t=_&&(self.URL||self.webkitURL).createObjectURL(_),!t)throw"";const e=new Worker(t,{type:"module",name:s?.name});return e.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),e}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(E),{type:"module",name:s?.name})}}var d=(s=>(s.INIT="init",s.AUD_CHUNK="audio-chunk",s.RESET="reset",s.DESTROY="destroy",s.LOADED="loaded",s.READY="ready",s.AUD_FEATS="audio-features",s.DESTROYED="destroyed",s.ERROR="error",s))(d||{});class Z{constructor(t){this.t=t,this.ct=h(),this.lt=new W,this.lt.onerror=this.ut.bind(this),this.lt.onmessage=this.dt.bind(this),this.t.addListener(r.AUD_CHUNK,this.gt.bind(this))}lt;ct=null;yt=null;bt=null;It=!1;async init(t){this.yt=h(),await this.ct?.promise;const e={type:d.INIT,model:t};return this.lt.postMessage(e),this.yt?.promise}async enable(){this.It=!0}async disable(){this.It=!1}async reset(){const t={type:d.RESET};return this.lt.postMessage(t)}async destroy(){this.bt=h();const t={type:d.DESTROY};return this.lt.postMessage(t)}gt(t,e){if(!this.It)return;const i={type:d.AUD_CHUNK,chunk:t,pts:e};return this.lt.postMessage(i,[t.buffer])}async dt(t){const e=t.data;e.type===d.LOADED?this.ft():e.type===d.READY?this._t():e.type===d.AUD_FEATS?this.Ct(e):e.type===d.ERROR?this.ut(e.data):e.type===d.DESTROYED&&this.wt()}ft(){this.ct?.resolve(),this.ct=null}_t(){this.yt?.resolve(),this.yt=null}Ct(t){this.t.emit(r.AUD_FEATS,t.features,t.pts)}ut(t){console.error(t)}wt(){this.lt.terminate(),this.bt?.resolve(),this.bt=null}}const w='import*as e from"onnxruntime-web/webgpu";var t=/* @__PURE__ */(e=>(e.INIT="init",e.AUD_FEATS="audio-features",e.VID_FRAME="video-frame",e.RDR_FRAME="render",e.DESTROY="destroy",e.RESET="reset",e.LOADED="loaded",e.READY="ready",e.RESETTED="resetted",e.DESTROYED="destroyed",e.ERROR="error",e))(t||{});class n{constructor(e,t,n,i){this.t=e,this.i=t,this.o=n,this.u=i,this.l=this.i.createView();const r=this.t.createShaderModule({label:"BBox Extraction Shader",code:"struct Out {\\n bbox: array<f32, 4>\\n}\\n\\n@group(0) @binding(0) var in_texture: texture_2d<f32>;\\n@group(0) @binding(1) var<storage, read_write> out_bbox: Out;\\n\\nfn read_byte(offset_x: u32, offset_y: u32) -> u32 {\\n // sample 8 center pixels of the 32x32 block\\n let center_pixels = array<vec2<u32>, 8>(\\n vec2<u32>(15u, 14u), vec2<u32>(16u, 14u),\\n vec2<u32>(15u, 15u), vec2<u32>(16u, 15u),\\n vec2<u32>(15u, 16u), vec2<u32>(16u, 16u),\\n vec2<u32>(15u, 17u), vec2<u32>(16u, 17u),\\n );\\n\\n var sum: f32 = 0.0;\\n for (var i: u32 = 0u; i < 8u; i = i + 1u) {\\n let p = textureLoad(in_texture, vec2<u32>(offset_x, offset_y) + center_pixels[i], 0);\\n sum = sum + p.r;\\n }\\n\\n let avg = sum / 8.0;\\n\\n // Convert normalized [0,1] to byte [0,255]\\n let b_f = clamp(round(avg * 255.0), 0.0, 255.0);\\n return u32(b_f);\\n}\\n\\nfn decode_nibble_from_block(offset_x: u32, offset_y: u32) -> u32 {\\n let b = read_byte(offset_x, offset_y); // 0..255\\n\\n // 16 quantized gray levels\\n let levels = array<u32, 16>(\\n 8u, 22u, 36u, 50u,\\n 64u, 78u, 92u, 106u,\\n 120u, 134u, 148u, 162u,\\n 176u, 190u, 204u, 218u\\n );\\n\\n var best_index: u32 = 0u;\\n var best_dist: u32 = 0xffffffffu;\\n\\n for (var i: u32 = 0u; i < 16u; i = i + 1u) {\\n let level: u32 = levels[i];\\n let dist: u32 = select(level - b, b - level, b >= level);\\n\\n if (dist < best_dist) {\\n best_dist = dist;\\n best_index = i;\\n }\\n }\\n\\n return best_index; // 0..15\\n}\\n\\nfn read_value_32bit(x: u32, y: u32, flipped: bool) -> f32 {\\n var n0: u32;\\n var n1: u32;\\n var n2: u32;\\n var n3: u32;\\n var n4: u32;\\n var n5: u32;\\n var n6: u32;\\n var n7: u32;\\n\\n if (!flipped) {\\n n0 = decode_nibble_from_block(x + 0u, y);\\n n1 = decode_nibble_from_block(x + 32u, y);\\n n2 = decode_nibble_from_block(x + 64u, y);\\n n3 = decode_nibble_from_block(x + 96u, y);\\n n4 = decode_nibble_from_block(x + 128u, y);\\n n5 = decode_nibble_from_block(x + 160u, y);\\n n6 = decode_nibble_from_block(x + 192u, y);\\n n7 = decode_nibble_from_block(x + 224u, y);\\n\\n } else {\\n // flipped horizontally: nibble order reversed\\n \\n n0 = decode_nibble_from_block(x + 224u, y);\\n n1 = decode_nibble_from_block(x + 192u, y);\\n n2 = decode_nibble_from_block(x + 160u, y);\\n n3 = decode_nibble_from_block(x + 128u, y);\\n n4 = decode_nibble_from_block(x + 96u, y);\\n n5 = decode_nibble_from_block(x + 64u, y);\\n n6 = decode_nibble_from_block(x + 32u, y);\\n n7 = decode_nibble_from_block(x + 0u, y);\\n }\\n\\n let q: u32 = (n0 << 28u) | (n1 << 24u) | (n2 << 20u) | (n3 << 16u) | (n4 << 12u) | (n5 << 8u) | (n6 << 4u) | n7;\\n\\n let max_u32: f32 = 4294967295.0; // 2^32 - 1\\n return f32(q) / max_u32;\\n}\\n\\n@compute @workgroup_size(1, 1, 1)\\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\\n // where the 2x2 replicated blocks start\\n let x_start = 1280u;\\n let y_start = 352u;\\n\\n // layout: 4 values stacked vertically, each value region is (2*32) tall because of 2x2 replication\\n for (var idx: u32 = 0u; idx < 4u; idx = idx + 1u) {\\n let base_x = x_start;\\n let base_y = y_start + idx * (2u * 32u);\\n\\n var acc: f32 = 0.0;\\n\\n acc = acc + read_value_32bit(base_x, base_y, false);\\n acc = acc + read_value_32bit(base_x, base_y + 32u, true);\\n\\n // Average the two replicated blocks.\\n out_bbox.bbox[idx] = acc * 0.5;\\n }\\n}"});this._=this.t.createComputePipeline({layout:"auto",compute:{module:r,entryPoint:"main"}}),this.h=this.t.createBindGroup({layout:this._.getBindGroupLayout(0),entries:[{binding:0,resource:this.l},{binding:1,resource:this.o}]});const s=this.t.createShaderModule({label:"Extract Shader",code:"@group(0) @binding(0) var in_texture: texture_2d<f32>;\\n@group(0) @binding(1) var<storage, read_write> out_tensor: array<f32>;\\n\\n@compute @workgroup_size(16, 16)\\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let x = gid.x;\\n let y = gid.y;\\n\\n // Only process a 320x320 region.\\n if (x >= 320u || y >= 320u) {\\n return;\\n }\\n\\n // 320x320 crop is located beside the frame on the \\n let offset_x = x + 1280u + 16u; // 1280 frame + 16 pixel padding for color correction region\\n let offset_y = y + 16u; // 16 pixel padding for color correction region\\n\\n let pixel = textureLoad(in_texture, vec2<u32>(offset_x, offset_y), 0);\\n\\n\\n let idx = y * 320u + x;\\n let plane = 320u * 320u;\\n\\n // Channels-first layout, BGR\\n out_tensor[0u * plane + idx] = pixel.b;\\n out_tensor[1u * plane + idx] = pixel.g;\\n out_tensor[2u * plane + idx] = pixel.r;\\n}\\n"});this.m=this.t.createComputePipeline({layout:"auto",compute:{module:s,entryPoint:"main"}}),this.v=this.t.createBindGroup({layout:this.m.getBindGroupLayout(0),entries:[{binding:0,resource:this.l},{binding:1,resource:{buffer:this.u}}]})}l;_;h;m;v;extract(){const e=this.t.createCommandEncoder(),t=e.beginComputePass();t.setPipeline(this._),t.setBindGroup(0,this.h),t.dispatchWorkgroups(1,1,1),t.end();const n=e.beginComputePass();n.setPipeline(this.m),n.setBindGroup(0,this.v),n.dispatchWorkgroups(20,20,1),n.end(),this.t.queue.submit([e.finish()])}destroy(){}}class i{constructor(e,t,n,i,r,s,a){this.p=e,this.t=t,this.U=n,this.P=i,this.B=r,this.k=s,this.G=a,this.O=navigator.gpu.getPreferredCanvasFormat(),this.p.configure({device:this.t,format:this.O,alphaMode:"opaque"}),this.A=this.t.createBuffer({size:24,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});const o=this.F(this.k,this.G);this.t.queue.writeBuffer(this.A,0,o.buffer),this.R=this.U.createView();const u=this.t.createShaderModule({label:"Render Shader",code:"struct BBox { xmin:f32, ymin:f32, xmax:f32, ymax:f32 };\\nstruct ROI { xmin:f32, ymin:f32, xmax:f32, ymax:f32, width:f32, height:f32 };\\n\\n@group(0) @binding(0) var frame_texture : texture_2d<f32>;\\n@group(0) @binding(1) var frame_sampler : sampler;\\n\\n@group(0) @binding(2) var<storage, read_write> out_tensor: array<f32>;\\n\\n@group(0) @binding(3) var<storage, read> mouth_bbox : BBox;\\n@group(0) @binding(4) var<uniform> roi_bbox : ROI;\\n\\nstruct VSOut {\\n @builtin(position) pos : vec4<f32>,\\n};\\n\\n@vertex\\nfn vs_main(@builtin(vertex_index) vid : u32) -> VSOut {\\n var p = array<vec2<f32>, 3>(\\n vec2<f32>(-1.0, -1.0),\\n vec2<f32>( 3.0, -1.0),\\n vec2<f32>(-1.0, 3.0)\\n );\\n var out : VSOut;\\n out.pos = vec4<f32>(p[vid], 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fs_main(@builtin(position) frag_pos : vec4<f32>) -> @location(0) vec4<f32> {\\n let canvas_size = vec2<f32>(roi_bbox.width, roi_bbox.height);\\n let canvas_uv = frag_pos.xy / canvas_size;\\n\\n let atlas_size = vec2<f32>(textureDimensions(frame_texture, 0));\\n\\n // Frame rect inside atlas (in UV)\\n let frame_size = vec2<f32>(1280.0, 720.0);\\n let frame_size_uv = frame_size / atlas_size;\\n\\n // ROI is normalized in the FRAME (0..1)\\n let roi_min_f = vec2<f32>(roi_bbox.xmin, roi_bbox.ymin);\\n let roi_max_f = vec2<f32>(roi_bbox.xmax, roi_bbox.ymax);\\n let roi_size_f = max(roi_max_f - roi_min_f, vec2<f32>(1e-6));\\n\\n // Canvas UV -> ROI UV (still in FRAME-normalized coordinates)\\n var roi_uv_f = roi_min_f + canvas_uv * roi_size_f;\\n\\n // Convert FRAME-normalized UV -> ATLAS UV\\n var atlas_uv = roi_uv_f * frame_size_uv;\\n\\n // Clamp inside ROI, but in ATLAS UV, inset by half a texel to avoid edge repetition\\n let half_texel_uv = 0.5 / atlas_size;\\n\\n let roi_min_atlas_uv = roi_min_f * frame_size_uv + half_texel_uv;\\n let roi_max_atlas_uv = roi_max_f * frame_size_uv - half_texel_uv;\\n\\n atlas_uv = clamp(atlas_uv, roi_min_atlas_uv, roi_max_atlas_uv);\\n\\n let frame_color = textureSample(frame_texture, frame_sampler, atlas_uv);\\n\\n\\n // Convert mouth_bbox from frame-normalized to canvas-normalized coordinates.\\n let mouth_min_canvas = (vec2<f32>(mouth_bbox.xmin, mouth_bbox.ymin) - roi_min_f) / roi_size_f;\\n let mouth_max_canvas = (vec2<f32>(mouth_bbox.xmax, mouth_bbox.ymax) - roi_min_f) / roi_size_f;\\n\\n let inside =\\n canvas_uv.x >= mouth_min_canvas.x && canvas_uv.x <= mouth_max_canvas.x &&\\n canvas_uv.y >= mouth_min_canvas.y && canvas_uv.y <= mouth_max_canvas.y;\\n\\n let rect_size = vec2<f32>(\\n max(mouth_max_canvas.x - mouth_min_canvas.x, 1e-6),\\n max(mouth_max_canvas.y - mouth_min_canvas.y, 1e-6)\\n );\\n\\n let crop_uv = clamp(\\n (canvas_uv - mouth_min_canvas) / rect_size,\\n vec2<f32>(0.0), vec2<f32>(1.0)\\n );\\n\\n let tx = min(u32(crop_uv.x * 320.0), 319u);\\n let ty = min(u32(crop_uv.y * 320.0), 319u);\\n let idx = ty * 320u + tx;\\n let stride = 320u * 320u;\\n\\n let b = out_tensor[0u * stride + idx];\\n let g = out_tensor[1u * stride + idx];\\n let r = out_tensor[2u * stride + idx];\\n let crop_color = vec4<f32>(r, g, b, 1.0);\\n\\n return select(frame_color, crop_color, inside);\\n}"});this.V=this.t.createRenderPipeline({layout:"auto",vertex:{module:u,entryPoint:"vs_main"},fragment:{module:u,entryPoint:"fs_main",targets:[{format:this.O}]},primitive:{topology:"triangle-list"}});const l=this.t.createSampler({magFilter:"linear",minFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge"});this.T=this.t.createBindGroup({layout:this.V.getBindGroupLayout(0),entries:[{binding:0,resource:this.R},{binding:1,resource:l},{binding:2,resource:this.P},{binding:3,resource:{buffer:this.B}},{binding:4,resource:{buffer:this.A}}]})}R;V;T;O;A;render(){const e=this.t.createCommandEncoder(),t=e.beginRenderPass({colorAttachments:[{view:this.p.getCurrentTexture().createView(),clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});t.setPipeline(this.V),t.setBindGroup(0,this.T),t.draw(3),t.end(),this.t.queue.submit([e.finish()])}clear(){const e=this.t.createCommandEncoder();e.beginRenderPass({colorAttachments:[{view:this.p.getCurrentTexture().createView(),clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]}).end(),this.t.queue.submit([e.finish()])}destroy(){}F(e,t){const n=t/e;let i,r;1280/t>720/e?(r=720,i=Math.min(1280,Math.round(r*n))):(i=1280,r=Math.min(720,Math.round(i/n)));const s=Math.round((1280-i)/2)/1280,a=Math.round((720-r)/2)/720;return new Float32Array([s,a,s+i/1280,a+r/720,t,e])}}var r=/* @__PURE__ */(e=>(e.Chromium="chromium",e.Firefox="firefox",e.Safari="safari",e.Opera="opera",e.Unknown="unknown",e))(r||{});e.env.wasm.wasmPaths="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.2/dist/";const s=new class{C=null;p=null;M=null;U;S=[];I=[];L;q;D=[];N;j;B;$;H;J=!1;K;W;X;Y=function(){const e=navigator.userAgent;return e.includes("Firefox")?"firefox":e.includes("OPR")||e.includes("Opera")?"opera":e.includes("Edg")?"chromium":!e.includes("Chrome")||e.includes("Chromium")||e.includes("OPR")||e.includes("Edg")?!e.includes("Safari")||e.includes("Chrome")||e.includes("Chromium")?"unknown":"safari":"chromium"}();async init(r,s){if(this.C=await async function(){const e=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(!e)return null;const t=["shader-f16","bgra8unorm-storage","rg11b10ufloat-renderable","float32-filterable"].filter(t=>e.features.has(t)),n=await e.requestDevice({requiredFeatures:t});return GPUAdapter.prototype.requestDevice=async function(){return n},navigator.gpu.requestAdapter=async()=>e,n}(),!this.C)return void console.error("Failed to create GPU device.");if(this.M=await e.InferenceSession.create(r,{executionProviders:["webgpu"],preferredOutputLocation:"gpu-buffer",graphOptimizationLevel:"all",logSeverityLevel:3}),this.U=this.C.createTexture({size:[1640,720,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.STORAGE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),this.L=this.C.createBuffer({size:32768,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),this.q=e.Tensor.fromGpuBuffer(this.L,{dataType:"float32",dims:[1,32,16,16]}),this.N=this.C.createBuffer({size:1228800,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST}),this.j=e.Tensor.fromGpuBuffer(this.N,{dataType:"float32",dims:[1,3,320,320]}),this.B=this.C.createBuffer({size:16,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST}),this.$=this.C.createBuffer({size:1228800,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST}),this.H=e.Tensor.fromGpuBuffer(this.$,{dataType:"float32",dims:[1,3,320,320]}),this.K=new n(this.C,this.U,this.B,this.N),this.X=s,this.p=this.X.getContext("webgpu"),!this.p)return void console.error("Failed to get canvas context.");this.W=new i(this.p,this.C,this.U,this.$,this.B,this.X.height,this.X.width);const a={type:t.READY};self.postMessage(a)}async onVideoFrame(e){if(this.D.push(e),this.D.length>=3){console.error("Dropping frames to avoid backpressure...",this.D.length);const e=this.D.shift();e?.close()}}async onRender(e){if(this.J)return void console.error("Already rendering.");if(0===this.D.length)return void console.warn("No frame available for rendering...");this.J=!0;const t=performance.now(),n=this.D.shift();try{let t=0;for(;t<this.I.length&&this.I[t]<e;)t++;if(t>=this.I.length)return n.close(),void console.warn("No audio feature for pts",e);const i=this.S[t];this.S=this.S.slice(t+1),this.I=this.I.slice(t+1),this.C.queue.writeBuffer(this.L,0,i);let s=n;this.Y!==r.Safari&&(s=await createImageBitmap(n)),this.C.queue.copyExternalImageToTexture({source:s},{texture:this.U},[n.displayWidth,n.displayHeight]),this.Y!==r.Safari&&s.close(),this.K.extract(),await this.infer(),this.W.render()}finally{this.J=!1,n.close()}const i=performance.now()-t;i>25&&console.warn(`Render time: ${i} ms`)}async onAudioFeature(e,t){this.S.push(e.buffer),this.I.push(t)}async reset(n){this.S=[],this.I=[],this.D.forEach(e=>e.close()),this.D=[],this.W.clear(),n&&(await(this.M?.release()),this.M=null,this.M=await e.InferenceSession.create(n,{executionProviders:["webgpu"],preferredOutputLocation:"gpu-buffer",graphOptimizationLevel:"all",logSeverityLevel:3}));const i={type:t.RESETTED};self.postMessage(i)}async destroy(){this.K.destroy(),this.W.destroy(),await(this.M?.release()),this.M=null,this.U.destroy(),this.q.dispose(),this.j.dispose(),this.N.destroy(),this.B.destroy(),this.H.dispose(),this.$.destroy(),this.C?.destroy(),this.C=null,this.p=null;const e={type:t.DESTROYED};self.postMessage(e)}async infer(){if(!this.M)return null;const e={[this.M.inputNames[0]]:this.j,[this.M.inputNames[1]]:this.q},t={[this.M.outputNames[0]]:this.H};return this.M.run(e,t).catch(e=>(console.error("Inference error:",e),null))}};self.onmessage=async e=>{const n=e.data;try{n.type===t.INIT?await s.init(n.model,n.canvas):n.type===t.AUD_FEATS?await s.onAudioFeature(n.features,n.pts):n.type===t.VID_FRAME?await s.onVideoFrame(n.frame):n.type===t.RDR_FRAME?await s.onRender(n.pts):n.type===t.RESET?await s.reset(n.modelUrl):n.type===t.DESTROY&&await s.destroy()}catch(i){const e={type:t.ERROR,data:i};self.postMessage(e)}};const a={type:t.LOADED};self.postMessage(a);\n',v=typeof self<"u"&&self.Blob&&new Blob(["URL.revokeObjectURL(import.meta.url);",w],{type:"text/javascript;charset=utf-8"});function x(s){let t;try{if(t=v&&(self.URL||self.webkitURL).createObjectURL(v),!t)throw"";const e=new Worker(t,{type:"module",name:s?.name});return e.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),e}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(w),{type:"module",name:s?.name})}}var u=(s=>(s.INIT="init",s.AUD_FEATS="audio-features",s.VID_FRAME="video-frame",s.RDR_FRAME="render",s.DESTROY="destroy",s.RESET="reset",s.LOADED="loaded",s.READY="ready",s.RESETTED="resetted",s.DESTROYED="destroyed",s.ERROR="error",s))(u||{});class D{constructor(t,e){this.t=t,this.At=e,this.ct=h(),this.lt=new x,this.lt.onerror=this.ut.bind(this),this.lt.onmessage=this.dt.bind(this),this.t.addListener(r.AUD_FEATS,this.Ct.bind(this)),this.t.addListener(r.VID_FRAME,this.vt.bind(this)),this.t.addListener(r.RDR_FRAME,this.Gt.bind(this))}lt;ct=null;yt=null;Bt=null;bt=null;It=!1;async init(t){this.yt=h(),await this.ct?.promise;const e={type:u.INIT,model:t,canvas:this.At};return this.lt.postMessage(e,[this.At]),this.yt?.promise}async enable(){this.It=!0}async disable(){this.It=!1}async reset(t){this.Bt=h();const e={type:u.RESET,modelUrl:t};return this.lt.postMessage(e),this.Bt?.promise}async destroy(){this.bt=h();const t={type:u.DESTROY};return this.lt.postMessage(t),this.bt?.promise}Ct(t,e){if(!this.It)return;const i={type:u.AUD_FEATS,features:t,pts:e};return this.lt.postMessage(i,[t.buffer])}vt(t){if(!this.It)return void t.close();const e={type:u.VID_FRAME,frame:t};return this.lt.postMessage(e,[t])}Gt(t){if(!this.It)return;const e={type:u.RDR_FRAME,pts:t};return this.lt.postMessage(e)}async dt(t){const e=t.data;e.type===u.LOADED?this.ft():e.type===u.READY?this._t():e.type===u.RESETTED?this.Rt():e.type===u.ERROR?this.ut(e.data):e.type===u.DESTROYED&&this.wt()}ft(){this.ct?.resolve(),this.ct=null}_t(){this.yt?.resolve(),this.yt=null}Rt(){this.Bt?.resolve(),this.Bt=null}ut(t){console.error(t)}wt(){this.lt.terminate(),this.bt?.resolve(),this.bt=null}}class X{constructor(t){this.t=t,this.Vt=document.createElement("video"),this.Vt.loop=!0,this.Vt.muted=!0,this.Vt.preload="auto",this.Vt.style.display="none",document.body.appendChild(this.Vt)}Vt;xt=!1;async src(t){this.Vt.src=t}async play(){return this.xt||(this.Vt.requestVideoFrameCallback(this.Wt.bind(this)),this.xt=!0),this.Vt.play()}async pause(){return this.Vt.pause()}async destroy(){await this.pause();try{document.body.removeChild(this.Vt)}catch(t){console.warn("Error removing video element:",t)}}async Wt(t,e){this.Vt.requestVideoFrameCallback(this.Wt.bind(this));let i=null;i=new VideoFrame(this.Vt,{timestamp:1e6*e.mediaTime}),this.t.emit(r.VID_FRAME,i)}}var g=(s=>(s.MUST_INIT="must call init()",s.MUST_USE="must call use()",s.NOT_IDLE="cannot call if not initialized or ready",s.STARTED="cannot call while started",s.DESTROYED="cannot call after destroy()",s.INVALID_TOKEN="could not read access token",s.CANNOT_USE_CHARACTER="pipeline is scoped to access token character",s.NO_CONTAINER="container not in DOM",s))(g||{});class f extends Error{constructor(t,e){super(t),this.code=e,this.name="EquosPipelineError"}}var y=(s=>(s.CREATED="created",s.INITIALIZED="initialized",s.READY="ready",s.STARTED="started",s.DESTROYED="destroyed",s))(y||{}),p=(s=>(s.UTTERANCE="utterance",s.INTERRUPT="interrupt",s.ERROR="error",s))(p||{});class G{constructor(t){this.Zt=t,this.I=t.endpoint||"wss://run.equos.ai/run",this.Xt=!!t.audio?.enabled,this.Ft=!!t.video?.enabled;try{this.Ut=this.kt(this.Zt.accessToken)}catch{throw new Error(g.INVALID_TOKEN)}this.St("finished instantiation")}Et="created";Nt=new Map;I;Ut;Tt=null;Xt=!1;Ft=!1;getState(){return this.Et}async init(){this.St("initializing..."),this.Mt(),this.Et==="created"?(await this.Yt(),this.Et="initialized",this.St("successfully initialized"),this.Ut.character&&await this.use(this.Ut.character)):this.zt("skipping init, already initialized")}async use(t){this.St(`using ${t}`),this.Mt(),this.Dt(),this.Ot(t),this.Tt!==t?(await this.Ht(t),this.Tt=t,this.Et="ready",this.St(`successfully using ${t}`)):this.zt(`skipping use, already using ${t}`)}async start(t){this.St("starting..."),this.Mt(),this.Et!=="started"?(this.Kt(),this.Et="started",await this.Lt(t),this.St("successfully started")):this.zt("skipping start, already started")}async stop(){this.St("stopping..."),this.Mt(),this.Et==="started"?(await this.Jt(),this.Et="ready",this.St("successfully stopped")):this.zt("skipping stop, not started")}async destroy(){this.St("destroying"),this.Et!=="destroyed"?(this.Nt.clear(),await this.Pt(),this.Et="destroyed",this.St("successfully destroyed")):this.zt("skipping destroy, already destroyed")}on(t,e){if(this.Et==="destroyed")return;const i=this.Nt.get(t),n=e;i?i.add(n):this.Nt.set(t,new Set([n]))}off(t,e){const i=this.Nt.get(t);i&&i.delete(e)}async Qt(t,...e){if(this.Et==="destroyed")throw new Error(g.DESTROYED);const i=this.Nt.get(t);if(i)for(const n of i)await n(...e)}video(){return{enable:this.jt.bind(this),disable:this.qt.bind(this)}}audio(){return{pushUsrAudio:this.$t.bind(this),enable:this.te.bind(this),disable:this.ee.bind(this)}}St(t){this.Zt.debug&&console.log(`[equos] pipeline (${this.Zt.name||"no name"}): ${t}`)}zt(t){this.Zt.debug&&console.warn(`[equos] pipeline (${this.Zt.name||"no name"}): ${t}`)}kt(t){const e=t.split(".")[1],i=atob(e.replace(/-/g,"+").replace(/_/g,"/")),n=JSON.parse(i);if(!n.org||typeof n.org!="string"||!n.user||typeof n.user!="string"||n.character&&typeof n.character!="string")throw new Error;return{org:n.org,user:n.user,character:n.character||null}}Mt(){if(this.Et==="destroyed")throw new Error(g.DESTROYED)}Kt(){if(this.Et!=="ready")throw new Error(g.MUST_USE)}Dt(){if(!["initialized","ready"].includes(this.Et))throw new Error(g.NOT_IDLE)}Ot(t){if(this.Ut.character&&this.Ut.character!==t)throw new Error(g.CANNOT_USE_CHARACTER)}}class F extends G{constructor(t){if(super(t),this.Zt=t,this.t=new U,this.listenToBus(),this.se=B.new(this.I,this.Zt.accessToken,this.t),this.ie=O.new(this.Ut.org+"_"+this.Ut.user),this.ne=new T(this.t),this.Zt.video){if(this.re=document.querySelector(this.Zt.video.containerSelector),!this.re)throw new Error(g.NO_CONTAINER);this.ae=document.createElement("canvas"),this.ae.width=this.Zt.video.width,this.ae.height=this.Zt.video.height,this.re.appendChild(this.ae),this.ae.style.display="none",this.oe=new X(this.t),this.he=new Z(this.t),this.ce=new D(this.t,this.ae.transferControlToOffscreen())}}t;se;ie;ne;re=null;ae=null;oe=null;he=null;ce=null;le=!1;async Yt(){return Promise.all([this.se.connect(),this.ie.synchronize(),this.ne.init()]).then()}async Ht(t){const e=await this.se.use(t);if(this.he&&this.ce&&this.oe){const[i,n,c]=await Promise.all([this.ie.fetch(e.audioModelUrl),this.ie.fetch(e.videoModelUrl),this.ie.fetch(e.videoUrl)]);await this.oe.src(c),this.le?await this.ce.reset(n):(await Promise.all([this.he.init(i),this.ce.init(n)]),this.le=!0)}}async Lt(t){await this.se.start(t),this.Xt&&await this.te(),this.Ft&&await this.jt()}async Jt(){await Promise.all([this.se.stop().then(()=>console.log("Connector stopped")),this.ee(!1).then(()=>console.log("Audio stopped")),this.qt(!1).then(()=>console.log("Video stopped"))])}async Pt(){return this.t.destroy(),this.re&&this.ae&&this.re.removeChild(this.ae),Promise.all([this.se.destroy(),this.ie.destroy(),this.ne.destroy(),this.oe?.destroy(),this.he?.destroy()]).then()}async jt(){this.Zt.video?(this.Ft=!0,this.Xt||await this.te(),this.getState()===y.STARTED&&(await this.oe?.play(),await this.he?.enable(),await this.ce?.enable(),this.ae&&(this.ae.style.display=""))):this.zt("video is not enabled in the pipeline config")}async qt(t=!0){t&&(this.Ft=!1),await this.oe?.pause(),await this.he?.disable(),await this.ce?.disable(),await this.he?.reset(),await this.ce?.reset(),this.ae&&(this.ae.style.display="none")}async $t(t){this.t.emit(r.USR_AUDIO,t)}async te(){this.Xt=!0,this.getState()===y.STARTED&&await this.ne.start()}async ee(t=!0){t&&(this.Xt=!1),await this.ne.stop()}listenToBus(){this.t.addListener(r.INTERRUPT,()=>{this.Qt(p.INTERRUPT)}),this.t.addListener(r.UTTERANCE,t=>{this.Qt(p.UTTERANCE,t)}),this.t.addListener(r.NWK_ERROR,async t=>{const e=t?new f("Network failed","NETWORK_FAILED"):new f("Network disconnected, attempting to reconnect...","NETWORK_DISCONNECTED");this.Qt(p.ERROR,e),this.getState()===y.STARTED&&await this.stop()}),this.t.addListener(r.SRV_ERROR,t=>{this.Qt(p.ERROR,new f(`Remote error: ${t}`,t))})}}class M{static new(t){return new F(t)}}class k{constructor(t){this.onAudio=t,this.i=new AudioContext({latencyHint:"interactive",sampleRate:A})}i;ue=null;de=null;l=null;async init(){return this.i.audioWorklet.addModule(new URL("data:video/mp2t;base64,aW1wb3J0IHsgV09SS0xFVF9OQU1FIH0gZnJvbSAnLi9jb250cmFjdCc7Cgpjb25zdCBTQU1QTEVfUkFURSA9IDE2MDAwOwpjb25zdCBDSFVOS19NUyA9IDQwOwpjb25zdCBDSFVOS19TSVpFID0gKFNBTVBMRV9SQVRFICogQ0hVTktfTVMpIC8gMTAwMDsgLy8gNjQwIHNhbXBsZXMKCmNsYXNzIFVzZXJBdWRpb1dvcmtsZXQgZXh0ZW5kcyBBdWRpb1dvcmtsZXRQcm9jZXNzb3IgewogIHByaXZhdGUgX2NodW5rID0gbmV3IEZsb2F0MzJBcnJheShDSFVOS19TSVpFKTsKICBwcml2YXRlIF93cml0ZUluZGV4ID0gMDsKCiAgcHJvY2VzcyhpbnB1dHM6IEZsb2F0MzJBcnJheVtdW10pOiBib29sZWFuIHsKICAgIGNvbnN0IGlucHV0ID0gaW5wdXRzWzBdPy5bMF07CiAgICBpZiAoIWlucHV0IHx8IGlucHV0Lmxlbmd0aCA9PT0gMCkgcmV0dXJuIHRydWU7CgogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbnB1dC5sZW5ndGg7IGkrKykgewogICAgICB0aGlzLl9jaHVua1t0aGlzLl93cml0ZUluZGV4KytdID0gaW5wdXRbaV07CgogICAgICBpZiAodGhpcy5fd3JpdGVJbmRleCA+PSBDSFVOS19TSVpFKSB7CiAgICAgICAgY29uc3QgY29weSA9IG5ldyBGbG9hdDMyQXJyYXkodGhpcy5fY2h1bmspOwogICAgICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZShjb3B5LCBbY29weS5idWZmZXJdKTsKCiAgICAgICAgdGhpcy5fY2h1bmsgPSBuZXcgRmxvYXQzMkFycmF5KENIVU5LX1NJWkUpOwogICAgICAgIHRoaXMuX3dyaXRlSW5kZXggPSAwOwogICAgICB9CiAgICB9CgogICAgcmV0dXJuIHRydWU7CiAgfQp9CgpyZWdpc3RlclByb2Nlc3NvcihXT1JLTEVUX05BTUUsIFVzZXJBdWRpb1dvcmtsZXQpOwo=",import.meta.url))}async start(){this.l&&(this.l.disconnect(),this.l=null),this.ue=await navigator.mediaDevices.getUserMedia({audio:{channelCount:1,sampleRate:A,echoCancellation:!0,noiseSuppression:!0}}),this.de=this.i.createMediaStreamSource(this.ue),this.l=new AudioWorkletNode(this.i,"usr-audio-worklet",{numberOfInputs:1,numberOfOutputs:0,channelCount:1}),this.l.port.onmessage=t=>{this.onAudio(t.data)},this.de.connect(this.l),this.i.state!=="running"&&await this.i.resume()}async stop(){this.l?.disconnect(),this.l=null,this.de?.disconnect(),this.de=null,this.ue?.getTracks().forEach(t=>t.stop()),this.ue=null,this.i.state==="running"&&await this.i.suspend()}async destroy(){return await this.stop(),this.i.close()}}export{G as EquosPipeline,f as EquosPipelineError,g as EquosPipelineErrors,p as EquosPipelineEvents,M as EquosPipelineFactory,y as EquosPipelineState,k as EquosUserAudioRecorder};
|
|
1
|
+
var r=(s=>(s.USR_AUDIO="usr-audio",s.AGT_AUDIO="agt-audio",s.UTTERANCE="utterance",s.INTERRUPT="interrupt",s.NWK_ERROR="nwk-error",s.SRV_ERROR="srv-error",s.TOKEN_EXP="token-exp",s.VID_FRAME="vid-frame",s.AUD_CHUNK="aud-chunk",s.AUD_FEATS="aud-feats",s.RDR_FRAME="rdr-frame",s))(r||{});const A=16e3;var p=(s=>(s.INTERRUPT="interrupt",s.AGT_AUDIO="agt-audio",s.STOP_WRKL="stop",s.AUD_CHUNK="frame",s.RDR_FRAME="render",s))(p||{});class U{constructor(t){this.t=t,this.i=new AudioContext({latencyHint:"interactive",sampleRate:A}),this.t.addListener(r.AGT_AUDIO,this.o.bind(this)),this.t.addListener(r.INTERRUPT,this.h.bind(this))}i;l=null;async init(){return this.i.audioWorklet.addModule(URL.createObjectURL(new Blob([atob("Ly8gc3JjL2NvbnN0YW50cy50cwp2YXIgVklERU9fRlBTID0gMjU7CnZhciBBVURJT19TQU1QTEVfUkFURSA9IDE2ZTM7CnZhciBGUkFNRV9EVVJBVElPTl9NUyA9IDFlMyAvIFZJREVPX0ZQUzsKdmFyIEZSQU1FX0NIVU5LX1NJWkUgPSBGUkFNRV9EVVJBVElPTl9NUyAqIEFVRElPX1NBTVBMRV9SQVRFIC8gMWUzOwp2YXIgUkFXX0NIVU5LX0RVUkFUSU9OX01TID0gMjAwOwp2YXIgUkFXX0NIVU5LX1NJWkUgPSBNYXRoLmZsb29yKAogIEFVRElPX1NBTVBMRV9SQVRFICogKFJBV19DSFVOS19EVVJBVElPTl9NUyAvIDFlMykKKTsKdmFyIEFVRElPX0ZFQVRVUkVfV0lORE9XID0gMTY7CnZhciBBVURJT19GRUFUVVJFX1NJWkUgPSA1MTI7CnZhciBBVURJT19GRUFUVVJFU19MRU5fUEVSX0ZSQU1FID0gQVVESU9fRkVBVFVSRV9TSVpFICogQVVESU9fRkVBVFVSRV9XSU5ET1c7CgovLyBzcmMvYXVkaW8vYWdlbnQvY29udHJhY3QudHMKdmFyIFdPUktMRVRfTkFNRSA9ICJhZ3QtYXVkaW8td29ya2xldCI7CgovLyBzcmMvYXVkaW8vYWdlbnQvd29ya2xldC50cwp2YXIgQWdlbnRBdWRpb1dvcmtsZXQgPSBjbGFzcyBleHRlbmRzIEF1ZGlvV29ya2xldFByb2Nlc3NvciB7CiAgX2FjY3VtdWxhdG9yID0gbmV3IEZsb2F0MzJBcnJheSgwKTsKICBfc3RvcHBlZCA9IGZhbHNlOwogIC8vIERlbGF5IGJldHdlZW4gZW1pdHRpbmcgY2h1bmsgYW5kIHBsYXliYWNrLgogIF9kZWxheUluTXMgPSA0MDA7CiAgX2RlbGF5SW5TYW1wbGVzID0gTWF0aC5yb3VuZCgKICAgIEFVRElPX1NBTVBMRV9SQVRFICogdGhpcy5fZGVsYXlJbk1zIC8gMWUzCiAgKTsKICAvLyBMb29rIGFoZWFkIGZvciByZW5kZXIgZW1pdHMuCiAgX3JlbmRlckxvb2tBaGVhZEluTXMgPSAyMjA7CiAgX3JlbmRlckxvb2tBaGVhZEluU2FtcGxlcyA9IE1hdGgucm91bmQoCiAgICBBVURJT19TQU1QTEVfUkFURSAqIHRoaXMuX3JlbmRlckxvb2tBaGVhZEluTXMgLyAxZTMKICApOwogIC8vIFNhbXBsZXMgdGhhdCBoYXZlIGJlZW4gZW1pdHRlZCBidXQgbm90IHlldCBwbGF5ZWQuCiAgX3BlbmRpbmdTYW1wbGVzID0gWwogICAgbmV3IEZsb2F0MzJBcnJheSh0aGlzLl9kZWxheUluU2FtcGxlcykKICBdOwogIC8vIFJlYWQgaW5kZXggd2l0aGluIHRoZSBmaXJzdCBwZW5kaW5nIGNodW5rLgogIF9wZW5kaW5nUmVhZEluZGV4ID0gMDsKICAvLyBGYWRlLWluIGxlbmd0aCB0byBhdm9pZCBjbGljayBhdCBzaWxlbmNl4oaSYXVkaW8gdHJhbnNpdGlvbi4KICBfZmFkZUluU2FtcGxlcyA9IE1hdGgucm91bmQoCiAgICBBVURJT19TQU1QTEVfUkFURSAqIDQwIC8gMWUzCiAgKTsKICAvLyA0MG1zCiAgLy8gV2hldGhlciB0aGUgZmlyc3QgcmVhbCBjaHVuayBzdGlsbCBuZWVkcyBhIGZhZGUtaW4gcmFtcC4KICBfbmVlZHNGYWRlSW4gPSB0cnVlOwogIC8vIFNhbXBsZXMgYmVmb3JlIG5leHQgZW1pdC4gSW5pdCB3aXRoIDAgdG8gZW1pdCBpbW1lZGlhdGVseS4KICBfc2FtcGxlc1VudGlsTmV4dEVtaXQgPSAwOwogIC8vIFNhbXBsZXMgYmVmb3JlIG5leHQgcmVuZGVyIHJlcXVlc3QuCiAgX3NhbXBsZXNVbnRpbE5leHRSZW5kZXIgPSB0aGlzLl9kZWxheUluU2FtcGxlcyAtIHRoaXMuX3JlbmRlckxvb2tBaGVhZEluU2FtcGxlczsKICAvLyBDb3VudCBzYW1wbGVzIHBsYXllZCwgZm9yIGFjY3VyYXRlIFBUUyBjYWxjdWxhdGlvbi4KICBfcGxheWVkU2FtcGxlcyA9IDA7CiAgY29uc3RydWN0b3IoKSB7CiAgICBzdXBlcigpOwogICAgdGhpcy5wb3J0Lm9ubWVzc2FnZSA9IChlKSA9PiB7CiAgICAgIGlmIChlLmRhdGEudHlwZSA9PT0gImFndC1hdWRpbyIgLyogQUdUX0FVRElPICovKSB7CiAgICAgICAgdGhpcy5fb25BdWRpbyhlLmRhdGEuYXVkaW8pOwogICAgICB9IGVsc2UgaWYgKGUuZGF0YS50eXBlID09PSAiaW50ZXJydXB0IiAvKiBJTlRFUlJVUFQgKi8pIHsKICAgICAgICB0aGlzLl9vbkludGVycnVwdCgpOwogICAgICB9IGVsc2UgaWYgKGUuZGF0YS50eXBlID09PSAic3RvcCIgLyogU1RPUF9XUktMICovKSB7CiAgICAgICAgdGhpcy5fc3RvcHBlZCA9IHRydWU7CiAgICAgIH0KICAgIH07CiAgfQogIGdldCBfY3VycmVudFB0cygpIHsKICAgIHJldHVybiBNYXRoLnJvdW5kKHRoaXMuX3BsYXllZFNhbXBsZXMgLyBBVURJT19TQU1QTEVfUkFURSAqIDFlNik7CiAgfQogIF9vbkF1ZGlvKGF1ZGlvKSB7CiAgICBjb25zdCBuZXdBY2MgPSBuZXcgRmxvYXQzMkFycmF5KHRoaXMuX2FjY3VtdWxhdG9yLmxlbmd0aCArIGF1ZGlvLmxlbmd0aCk7CiAgICBuZXdBY2Muc2V0KHRoaXMuX2FjY3VtdWxhdG9yLCAwKTsKICAgIG5ld0FjYy5zZXQoYXVkaW8sIHRoaXMuX2FjY3VtdWxhdG9yLmxlbmd0aCk7CiAgICB0aGlzLl9hY2N1bXVsYXRvciA9IG5ld0FjYzsKICB9CiAgX29uSW50ZXJydXB0KCkgewogICAgdGhpcy5fYWNjdW11bGF0b3IgPSBuZXcgRmxvYXQzMkFycmF5KDApOwogIH0KICBwcm9jZXNzKF9pbnB1dHMsIG91dHB1dHMpIHsKICAgIGlmICh0aGlzLl9zdG9wcGVkKSB7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICAgIGNvbnN0IHNhbXBsZXNUb1dyaXRlID0gb3V0cHV0c1swXVswXS5sZW5ndGg7CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNhbXBsZXNUb1dyaXRlOyBpKyspIHsKICAgICAgaWYgKHRoaXMuX3NhbXBsZXNVbnRpbE5leHRFbWl0ID09PSAwKSB7CiAgICAgICAgdGhpcy5fZmVlZCgpOwogICAgICAgIHRoaXMuX3NhbXBsZXNVbnRpbE5leHRFbWl0ID0gUkFXX0NIVU5LX1NJWkU7CiAgICAgIH0KICAgICAgaWYgKHRoaXMuX3NhbXBsZXNVbnRpbE5leHRSZW5kZXIgPT09IDApIHsKICAgICAgICB0aGlzLl9yZW5kZXIoKTsKICAgICAgICB0aGlzLl9zYW1wbGVzVW50aWxOZXh0UmVuZGVyID0gRlJBTUVfQ0hVTktfU0laRTsKICAgICAgfQogICAgICBpZiAodGhpcy5fcGVuZGluZ1NhbXBsZXMubGVuZ3RoID09PSAwKSB7CiAgICAgICAgY29uc29sZS53YXJuKCJBdWRpbyB1bmRlcmZsb3c6IG5vIHBlbmRpbmcgc2FtcGxlcyB0byBwbGF5LiIpOwogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGlmICh0aGlzLl9wZW5kaW5nUmVhZEluZGV4ID49IHRoaXMuX3BlbmRpbmdTYW1wbGVzWzBdLmxlbmd0aCkgewogICAgICAgIHRoaXMuX3BlbmRpbmdTYW1wbGVzLnNoaWZ0KCk7CiAgICAgICAgdGhpcy5fcGVuZGluZ1JlYWRJbmRleCA9IDA7CiAgICAgICAgaWYgKHRoaXMuX3BlbmRpbmdTYW1wbGVzLmxlbmd0aCA9PT0gMCkgewogICAgICAgICAgY29uc29sZS53YXJuKCJBdWRpbyB1bmRlcmZsb3c6IG5vIHBlbmRpbmcgc2FtcGxlcyB0byBwbGF5LiIpOwogICAgICAgICAgY29udGludWU7CiAgICAgICAgfQogICAgICB9CiAgICAgIGNvbnN0IHNhbXBsZSA9IHRoaXMuX3BlbmRpbmdTYW1wbGVzWzBdW3RoaXMuX3BlbmRpbmdSZWFkSW5kZXhdOwogICAgICBmb3IgKGxldCBjaGFubmVsID0gMDsgY2hhbm5lbCA8IG91dHB1dHNbMF0ubGVuZ3RoOyBjaGFubmVsKyspIHsKICAgICAgICBvdXRwdXRzWzBdW2NoYW5uZWxdW2ldID0gc2FtcGxlOwogICAgICB9CiAgICAgIHRoaXMuX3BlbmRpbmdSZWFkSW5kZXgrKzsKICAgICAgdGhpcy5fcGxheWVkU2FtcGxlcysrOwogICAgICB0aGlzLl9zYW1wbGVzVW50aWxOZXh0RW1pdC0tOwogICAgICB0aGlzLl9zYW1wbGVzVW50aWxOZXh0UmVuZGVyLS07CiAgICB9CiAgICByZXR1cm4gdHJ1ZTsKICB9CiAgX2ZlZWQoKSB7CiAgICBjb25zdCBjaHVuayA9IG5ldyBGbG9hdDMyQXJyYXkoUkFXX0NIVU5LX1NJWkUpOwogICAgY29uc3QgbiA9IE1hdGgubWluKGNodW5rLmxlbmd0aCwgdGhpcy5fYWNjdW11bGF0b3IubGVuZ3RoKTsKICAgIGNodW5rLnNldCh0aGlzLl9hY2N1bXVsYXRvci5zdWJhcnJheSgwLCBuKSwgMCk7CiAgICB0aGlzLl9hY2N1bXVsYXRvciA9IHRoaXMuX2FjY3VtdWxhdG9yLnN1YmFycmF5KG4pOwogICAgaWYgKHRoaXMuX25lZWRzRmFkZUluKSB7CiAgICAgIGNvbnN0IGxlbiA9IE1hdGgubWluKHRoaXMuX2ZhZGVJblNhbXBsZXMsIGNodW5rLmxlbmd0aCk7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspIHsKICAgICAgICBjaHVua1tpXSAqPSBpIC8gbGVuOwogICAgICB9CiAgICAgIHRoaXMuX25lZWRzRmFkZUluID0gZmFsc2U7CiAgICB9CiAgICB0aGlzLl9wZW5kaW5nU2FtcGxlcy5wdXNoKGNodW5rKTsKICAgIGNvbnN0IGNodW5rUHRzID0gdGhpcy5fY3VycmVudFB0cyArIHRoaXMuX2RlbGF5SW5NcyAqIDFlMzsKICAgIGNvbnN0IGZyYW1lID0gbmV3IEZsb2F0MzJBcnJheShjaHVuayk7CiAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2UoCiAgICAgIHsKICAgICAgICB0eXBlOiAiZnJhbWUiIC8qIEFVRF9DSFVOSyAqLywKICAgICAgICBjaHVuazogZnJhbWUsCiAgICAgICAgcHRzOiBjaHVua1B0cwogICAgICB9LAogICAgICBbZnJhbWUuYnVmZmVyXQogICAgKTsKICB9CiAgX3JlbmRlcigpIHsKICAgIGNvbnN0IHJlbmRlclB0cyA9IHRoaXMuX2N1cnJlbnRQdHMgKyB0aGlzLl9yZW5kZXJMb29rQWhlYWRJbk1zICogMWUzOwogICAgdGhpcy5wb3J0LnBvc3RNZXNzYWdlKHsKICAgICAgdHlwZTogInJlbmRlciIgLyogUkRSX0ZSQU1FICovLAogICAgICBwdHM6IHJlbmRlclB0cwogICAgfSk7CiAgfQp9OwpyZWdpc3RlclByb2Nlc3NvcihXT1JLTEVUX05BTUUsIEFnZW50QXVkaW9Xb3JrbGV0KTsK")],{type:"text/javascript"})))}async start(){this.l&&(this.l.disconnect(),this.l=null),this.l=new AudioWorkletNode(this.i,"agt-audio-worklet",{numberOfInputs:0,numberOfOutputs:1,outputChannelCount:[1]}),this.l.connect(this.i.destination),this.l.port.onmessage=async t=>{const e=t.data;e.type===p.AUD_CHUNK?this.t.emit(r.AUD_CHUNK,e.chunk,e.pts):e.type===p.RDR_FRAME&&this.t.emit(r.RDR_FRAME,e.pts)},this.i.state!=="running"&&await this.i.resume()}async stop(){return this.l?.port.postMessage({type:p.STOP_WRKL}),this.l?.disconnect(),this.l=null,this.i.suspend()}async destroy(){return await this.stop(),this.i.close()}async o(t){return this.l?.port.postMessage({type:p.AGT_AUDIO,audio:t},[t.buffer])}async h(){return this.l?.port.postMessage({type:p.INTERRUPT})}}class B{t=new EventTarget;u=new AbortController;p=[];emit(t,...e){return this.t.dispatchEvent(new CustomEvent(t,{detail:e}))}addListener(t,e){const i=new AbortController;this.u.signal.addEventListener("abort",()=>i.abort()),this.t.addEventListener(t,n=>{const c=n.detail;e(...c)},{signal:i.signal}),this.p.push({event:t,handler:e,ctrl:i})}removeListener(t,e){const i=this.p.findIndex(n=>n.event===t&&n.handler===e);i!==-1&&(this.p[i].ctrl.abort(),this.p.splice(i,1))}destroy(){this.u.abort(),this.p.length=0}}class V{constructor(t,e,i){this.I=t,this.m=e,this.t=i,this.t.addListener(r.USR_AUDIO,this._.bind(this))}async destroy(){return this.t.removeListener(r.USR_AUDIO,this._.bind(this)),this.disconnect()}_(t){const e=new ArrayBuffer(t.byteLength);return new Uint8Array(e).set(new Uint8Array(t.buffer,t.byteOffset,t.byteLength)),this.C(e)}}function h(){let s,t;return{promise:new Promise((e,i)=>{s=e,t=i}),resolve:s,reject:t}}var l=(s=>(s.PING="ping",s.USE="use",s.START="start",s.STOP="stop",s.TOKEN_REFRESH="token.refresh",s.PONG="pong",s.USING="using",s.STARTED="started",s.STOPPED="stopped",s.INTERRUPT="interrupt",s.UTTERANCE="utterance",s.TOKEN_EXPIRING="token.expiring",s.ERROR="error",s))(l||{}),a=(s=>(s.TOKEN_MISSING="TOKEN_MISSING",s.TOKEN_EXPIRED="TOKEN_EXPIRED",s.TOKEN_SIGNATURE_INVALID="TOKEN_SIGNATURE_INVALID",s.TOKEN_MALFORMED="TOKEN_MALFORMED",s.TOKEN_MALFORMED_CLAIMS="TOKEN_MALFORMED_CLAIMS",s.CHARACTER_NOT_FOUND="CHARACTER_NOT_FOUND",s.CHARACTER_NOT_FETCHED="CHARACTER_NOT_FETCHED",s.CONVERSATION_TIMEOUT="CONVERSATION_TIMEOUT",s.CONVERSATION_ENDED_PREMATURELY="CONVERSATION_ENDED_PREMATURELY",s.USER_BUSY="USER_BUSY",s))(a||{});class S extends V{constructor(t,e,i){super(t,e,i),this.endpoint=t,this.accessToken=e,this.bus=i}A=null;v=null;B=null;R=null;V=null;G=0;U=null;X=!1;get resolvedUrl(){return`${this.endpoint}?token=${this.accessToken}`}async connect(){return this.A=new WebSocket(this.resolvedUrl),this.A.binaryType="arraybuffer",this.A.onopen=this.onOpen.bind(this),this.A.onclose=this.onClose.bind(this),this.A.onmessage=this.onMsg.bind(this),this.v=h(),this.v.promise}async disconnect(){this.X=!0,this.A?.close(),this.A=null,this.v?.reject(new Error("pipeline disconnected")),this.v=null,this.B?.reject(new Error("pipeline disconnected")),this.B=null,this.R?.reject(new Error("pipeline disconnected")),this.R=null,this.V?.reject(new Error("pipeline disconnected")),this.V=null}async use(t){this.V=h();const e={type:l.USE,character:t};return await this.C(e),this.V.promise}async start(t){this.B=h();const e={type:l.START,conversation:t};return await this.C(e),this.B.promise}async stop(){this.R=h();const t={type:l.STOP};return await this.C(t),this.R.promise}async refreshToken(t){this.accessToken=t;const e={type:l.TOKEN_REFRESH,access_token:t};await this.C(e)}async C(t){this.A&&this.A.readyState===WebSocket.OPEN&&(t instanceof ArrayBuffer?this.A.send(t):this.A.send(JSON.stringify(t)))}onOpen(){this.v?.resolve(),this.v=null,this.G=0,this.U&&clearInterval(this.U);const t={type:l.PING};this.U=setInterval(()=>{this.C(t)},1e4)}onClose(t){this.v?.reject(new Error("WebSocket closed before ready")),this.v=null,this.B?.reject(new Error("WebSocket closed before start")),this.B=null,this.R?.reject(new Error("WebSocket closed before stop")),this.R=null,this.V?.reject(new Error("WebSocket closed before use")),this.V=null,this.U&&clearInterval(this.U);const e=t.reason;if(e)this.handleCloseReason(e);else if(!this.X){if(this.G++,this.G<3){const i=1e3*2**(this.G-1);setTimeout(()=>{this.connect().catch(()=>null)},i)}this.bus.emit(r.NWK_ERROR,this.G>=3)}}handleCloseReason(t){switch(t){case a.TOKEN_MISSING:case a.TOKEN_EXPIRED:case a.TOKEN_SIGNATURE_INVALID:case a.TOKEN_MALFORMED:case a.TOKEN_MALFORMED_CLAIMS:case a.CHARACTER_NOT_FOUND:case a.CHARACTER_NOT_FETCHED:case a.CONVERSATION_TIMEOUT:case a.CONVERSATION_ENDED_PREMATURELY:case a.USER_BUSY:this.bus.emit(r.SRV_ERROR,t);break;default:console.warn(`[Connector] Unknown close reason: ${t}`),this.bus.emit(r.SRV_ERROR,"UNKNOWN_REASON")}}onMsg(t){if(t.data instanceof ArrayBuffer){const e=new Float32Array(t.data);return void this.bus.emit(r.AGT_AUDIO,e)}try{const e=JSON.parse(t.data);switch(e.type){case l.PONG:break;case l.USING:this.k(e.audio_model_url,e.video_model_url,e.video_url);break;case l.STARTED:this.W();break;case l.STOPPED:this.S();break;case l.INTERRUPT:this.h();break;case l.UTTERANCE:this.F(e.utterance);break;case l.TOKEN_EXPIRING:this.Z();break;case l.ERROR:this.T(e.code);break;default:console.warn(`[Connector] Unknown message: ${e.type}`)}}catch(e){console.error("[Connector] Failed to parse WS message:",e)}}k(t,e,i){this.V?.resolve({audioModelUrl:t,videoModelUrl:e,videoUrl:i}),this.V=null}W(){this.B?.resolve(),this.B=null}S(){this.R?.resolve(),this.R=null}h(){this.bus.emit(r.INTERRUPT)}F(t){this.bus.emit(r.UTTERANCE,t)}Z(){this.bus.emit(r.TOKEN_EXP)}T(t){switch(t){case a.TOKEN_MISSING:case a.TOKEN_EXPIRED:case a.TOKEN_SIGNATURE_INVALID:case a.TOKEN_MALFORMED:case a.TOKEN_MALFORMED_CLAIMS:case a.CHARACTER_NOT_FOUND:case a.CHARACTER_NOT_FETCHED:this.V?.reject(new Error(t)),this.V=null,this.B?.reject(new Error(t)),this.B=null;break;case a.CONVERSATION_TIMEOUT:case a.CONVERSATION_ENDED_PREMATURELY:case a.USER_BUSY:this.B?.reject(new Error(t)),this.B=null;break;default:console.warn(`[Connector] Unknown error code: ${t}`)}this.bus.emit(r.SRV_ERROR,t)}}class G{static new(t,e,i){return new S(t,e,i)}}const C="AES-GCM";class f{constructor(t){this.N=t,this.M=new Map}static SALT_STORAGE_KEY="https://encryption-salt.equos.ai";M;O=new Map;D=null;K(t){try{const e=new URL(t);return e.search="",e.toString()}catch{return t}}async synchronize(){return await this.L(),this.Y()}async fetch(t){const e=this.K(t),i=this.M.get(e);if(i?.objectUrl)return console.log(`Cache hit for ${t}`),i.objectUrl;const n=this.O.get(e);if(n)return n.promise;const c=h();this.O.set(e,c);try{let o=null;if(i?.status==="cached"){const y=await this.H(e).catch(()=>null);y&&(o=await this.P(y),this.J(e,o))}if(!o){const y=await this.j(t,e);o=await this.P(y.clone()),this.J(e,o),this.q(y).then(m=>this.$(e,m)).then(()=>this.tt(e,o)).catch(m=>console.warn(`Failed to store asset ${t} in cache:`,m))}c.resolve(o)}catch(o){c.reject(o)}finally{this.O.delete(e)}return c.promise}async destroy(){this.M.forEach(t=>{t.objectUrl&&URL.revokeObjectURL(t.objectUrl)}),this.O.forEach(t=>t.reject(new Error("Storage destroyed"))),this.O.clear(),this.M.clear(),this.D=null}async j(t,e){this.et(e);const i=await fetch(t);if(i.ok)return i;throw this.st(e),new Error(`Failed to fetch ${t}: ${i.statusText}`)}async H(t){const e=await this.it(t);return e?this.nt(e).catch(async i=>(console.log(`Failed to decrypt ${t}, clearing storage`,i),this.D=null,this.M.clear(),await this.rt(),null)):(this.st(t),null)}async P(t){const e=await t.blob();return URL.createObjectURL(e)}st(t){this.M.delete(t)}async ot(){const t=await this.it(f.SALT_STORAGE_KEY);if(t)return new Uint8Array(await t.arrayBuffer());await this.rt();const e=crypto.getRandomValues(new Uint8Array(16));return await this.$(f.SALT_STORAGE_KEY,new Response(e)),e}async L(){if(!this.D){const t=new TextEncoder,e=t.encode(this.N),i=await this.ot(),n=await crypto.subtle.importKey("raw",e,"HKDF",!1,["deriveKey"]);this.D=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:t.encode("equos-storage")},n,{name:C,length:256},!1,["encrypt","decrypt"])}return this.D}async q(t){const e=await this.L(),i=crypto.getRandomValues(new Uint8Array(12)),n=await t.arrayBuffer(),c=await crypto.subtle.encrypt({name:C,iv:i},e,n),o=new Uint8Array(12+c.byteLength);return o.set(i,0),o.set(new Uint8Array(c),12),new Response(o,{headers:t.headers,status:t.status,statusText:t.statusText})}async nt(t){const e=await this.L(),i=new Uint8Array(await t.arrayBuffer()),n=i.slice(0,12),c=i.slice(12),o=await crypto.subtle.decrypt({name:C,iv:n},e,c);return new Response(o,{headers:t.headers,status:t.status,statusText:t.statusText})}et(t){this.M.set(t,{status:"loading",objectUrl:null})}J(t,e){this.M.set(t,{status:"loaded",objectUrl:e})}tt(t,e){this.M.set(t,{status:"cached",objectUrl:e})}}class N extends f{ht;constructor(t){super(t),this.ht="equos-storage-v1"}async Y(){(await(await caches.open(this.ht)).keys()).forEach(e=>{const i=this.K(e.url);i!==f.SALT_STORAGE_KEY&&this.tt(i,null)})}async $(t,e){await(await caches.open(this.ht)).put(t,e.clone())}async it(t){return(await caches.open(this.ht)).match(t)}async rt(){const t=await caches.open(this.ht),e=await t.keys();await Promise.all(e.map(i=>t.delete(i)))}}class O{static new(t){return new N(t)}}const _=`import*as t from"onnxruntime-web/webgpu";import{AveProcessor as e}from"@equos/audio-processor";var s=/* @__PURE__ */(t=>(t.INIT="init",t.AUD_CHUNK="audio-chunk",t.RESET="reset",t.DESTROY="destroy",t.LOADED="loaded",t.READY="ready",t.AUD_FEATS="audio-features",t.DESTROYED="destroyed",t.ERROR="error",t))(s||{});const i=8192;t.env.wasm.wasmPaths="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/";const n=new class{t=null;i=null;o=null;async init(i){if(this.t=await async function(){const t=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(!t)return null;const e=["shader-f16","bgra8unorm-storage","rg11b10ufloat-renderable","float32-filterable"].filter(e=>t.features.has(e)),s=await t.requestDevice({requiredFeatures:e});return GPUAdapter.prototype.requestDevice=async function(){return s},navigator.gpu.requestAdapter=async()=>t,s}(),!this.t)return void console.error("Failed to create GPU device.");this.i=new e,this.o=await t.InferenceSession.create(i,{executionProviders:["webgpu"],preferredOutputLocation:"gpu-buffer",graphOptimizationLevel:"all",logSeverityLevel:3});const n={type:s.READY};self.postMessage(n)}async push(e,n){if(!this.t||!this.o||!this.i)return void console.error("Audio worker not initialized, dropping audio batch...");let r=null;try{const a=this.i.push(e);if(!a)return;const o=a.length/1280;r=new t.Tensor("float32",a,[o,1,80,16]);const l=await this.o.run({[this.o.inputNames[0]]:r}),c=await l[this.o.outputNames[0]].getData(),u=this.i.push_features(c);if(u&&u.byteLength>0){const t=u.length/i;for(let e=0;e<t;e++){const t=new Float32Array(u.subarray(e*i,(e+1)*i)),r={type:s.AUD_FEATS,features:t,pts:n+4e4*e};self.postMessage(r,[t.buffer])}}}finally{r?.dispose()}}async reset(){this.i?.free(),this.i=new e}async destroy(){await(this.o?.release()),this.o=null,this.i.free();const t={type:s.DESTROYED};self.postMessage(t)}};self.onmessage=async t=>{const e=t.data;try{e.type===s.INIT?await n.init(e.model):e.type===s.AUD_CHUNK?await n.push(e.chunk,e.pts):e.type===s.RESET?await n.reset():e.type===s.DESTROY&&await n.destroy()}catch(i){const t={type:s.ERROR,data:i};self.postMessage(t)}};const r={type:s.LOADED};self.postMessage(r);
|
|
2
|
+
`,E=typeof self<"u"&&self.Blob&&new Blob(["URL.revokeObjectURL(import.meta.url);",_],{type:"text/javascript;charset=utf-8"});function x(s){let t;try{if(t=E&&(self.URL||self.webkitURL).createObjectURL(E),!t)throw"";const e=new Worker(t,{type:"module",name:s?.name});return e.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),e}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(_),{type:"module",name:s?.name})}}var d=(s=>(s.INIT="init",s.AUD_CHUNK="audio-chunk",s.RESET="reset",s.DESTROY="destroy",s.LOADED="loaded",s.READY="ready",s.AUD_FEATS="audio-features",s.DESTROYED="destroyed",s.ERROR="error",s))(d||{});class D{constructor(t){this.t=t,this.lt=h(),this.ct=new x,this.ct.onerror=this.ut.bind(this),this.ct.onmessage=this.dt.bind(this),this.t.addListener(r.AUD_CHUNK,this.gt.bind(this))}ct;lt=null;yt=null;ft=null;bt=!1;async init(t){this.yt=h(),await this.lt?.promise;const e={type:d.INIT,model:t};return this.ct.postMessage(e),this.yt?.promise}async enable(){this.bt=!0}async disable(){this.bt=!1}async reset(){const t={type:d.RESET};return this.ct.postMessage(t)}async destroy(){this.ft=h();const t={type:d.DESTROY};return this.ct.postMessage(t)}gt(t,e){if(!this.bt)return;const i={type:d.AUD_CHUNK,chunk:t,pts:e};return this.ct.postMessage(i,[t.buffer])}async dt(t){const e=t.data;e.type===d.LOADED?this.It():e.type===d.READY?this._t():e.type===d.AUD_FEATS?this.Ct(e):e.type===d.ERROR?this.ut(e.data):e.type===d.DESTROYED&&this.wt()}It(){this.lt?.resolve(),this.lt=null}_t(){this.yt?.resolve(),this.yt=null}Ct(t){this.t.emit(r.AUD_FEATS,t.features,t.pts)}ut(t){console.error(t)}wt(){this.ct.terminate(),this.ft?.resolve(),this.ft=null}}const v='import*as e from"onnxruntime-web/webgpu";var t=/* @__PURE__ */(e=>(e.INIT="init",e.AUD_FEATS="audio-features",e.VID_FRAME="video-frame",e.RDR_FRAME="render",e.DESTROY="destroy",e.RESET="reset",e.LOADED="loaded",e.READY="ready",e.RESETTED="resetted",e.DESTROYED="destroyed",e.ERROR="error",e))(t||{});class n{constructor(e,t,n,i){this.t=e,this.i=t,this.o=n,this.u=i,this.l=this.i.createView();const r=this.t.createShaderModule({label:"BBox Extraction Shader",code:"struct Out {\\n bbox: array<f32, 4>\\n}\\n\\n@group(0) @binding(0) var in_texture: texture_2d<f32>;\\n@group(0) @binding(1) var<storage, read_write> out_bbox: Out;\\n\\nfn read_byte(offset_x: u32, offset_y: u32) -> u32 {\\n // sample 8 center pixels of the 32x32 block\\n let center_pixels = array<vec2<u32>, 8>(\\n vec2<u32>(15u, 14u), vec2<u32>(16u, 14u),\\n vec2<u32>(15u, 15u), vec2<u32>(16u, 15u),\\n vec2<u32>(15u, 16u), vec2<u32>(16u, 16u),\\n vec2<u32>(15u, 17u), vec2<u32>(16u, 17u),\\n );\\n\\n var sum: f32 = 0.0;\\n for (var i: u32 = 0u; i < 8u; i = i + 1u) {\\n let p = textureLoad(in_texture, vec2<u32>(offset_x, offset_y) + center_pixels[i], 0);\\n sum = sum + p.r;\\n }\\n\\n let avg = sum / 8.0;\\n\\n // Convert normalized [0,1] to byte [0,255]\\n let b_f = clamp(round(avg * 255.0), 0.0, 255.0);\\n return u32(b_f);\\n}\\n\\nfn decode_nibble_from_block(offset_x: u32, offset_y: u32) -> u32 {\\n let b = read_byte(offset_x, offset_y); // 0..255\\n\\n // 16 quantized gray levels\\n let levels = array<u32, 16>(\\n 8u, 22u, 36u, 50u,\\n 64u, 78u, 92u, 106u,\\n 120u, 134u, 148u, 162u,\\n 176u, 190u, 204u, 218u\\n );\\n\\n var best_index: u32 = 0u;\\n var best_dist: u32 = 0xffffffffu;\\n\\n for (var i: u32 = 0u; i < 16u; i = i + 1u) {\\n let level: u32 = levels[i];\\n let dist: u32 = select(level - b, b - level, b >= level);\\n\\n if (dist < best_dist) {\\n best_dist = dist;\\n best_index = i;\\n }\\n }\\n\\n return best_index; // 0..15\\n}\\n\\nfn read_value_32bit(x: u32, y: u32, flipped: bool) -> f32 {\\n var n0: u32;\\n var n1: u32;\\n var n2: u32;\\n var n3: u32;\\n var n4: u32;\\n var n5: u32;\\n var n6: u32;\\n var n7: u32;\\n\\n if (!flipped) {\\n n0 = decode_nibble_from_block(x + 0u, y);\\n n1 = decode_nibble_from_block(x + 32u, y);\\n n2 = decode_nibble_from_block(x + 64u, y);\\n n3 = decode_nibble_from_block(x + 96u, y);\\n n4 = decode_nibble_from_block(x + 128u, y);\\n n5 = decode_nibble_from_block(x + 160u, y);\\n n6 = decode_nibble_from_block(x + 192u, y);\\n n7 = decode_nibble_from_block(x + 224u, y);\\n\\n } else {\\n // flipped horizontally: nibble order reversed\\n \\n n0 = decode_nibble_from_block(x + 224u, y);\\n n1 = decode_nibble_from_block(x + 192u, y);\\n n2 = decode_nibble_from_block(x + 160u, y);\\n n3 = decode_nibble_from_block(x + 128u, y);\\n n4 = decode_nibble_from_block(x + 96u, y);\\n n5 = decode_nibble_from_block(x + 64u, y);\\n n6 = decode_nibble_from_block(x + 32u, y);\\n n7 = decode_nibble_from_block(x + 0u, y);\\n }\\n\\n let q: u32 = (n0 << 28u) | (n1 << 24u) | (n2 << 20u) | (n3 << 16u) | (n4 << 12u) | (n5 << 8u) | (n6 << 4u) | n7;\\n\\n let max_u32: f32 = 4294967295.0; // 2^32 - 1\\n return f32(q) / max_u32;\\n}\\n\\n@compute @workgroup_size(1, 1, 1)\\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\\n // where the 2x2 replicated blocks start\\n let x_start = 1280u;\\n let y_start = 352u;\\n\\n // layout: 4 values stacked vertically, each value region is (2*32) tall because of 2x2 replication\\n for (var idx: u32 = 0u; idx < 4u; idx = idx + 1u) {\\n let base_x = x_start;\\n let base_y = y_start + idx * (2u * 32u);\\n\\n var acc: f32 = 0.0;\\n\\n acc = acc + read_value_32bit(base_x, base_y, false);\\n acc = acc + read_value_32bit(base_x, base_y + 32u, true);\\n\\n // Average the two replicated blocks.\\n out_bbox.bbox[idx] = acc * 0.5;\\n }\\n}"});this._=this.t.createComputePipeline({layout:"auto",compute:{module:r,entryPoint:"main"}}),this.h=this.t.createBindGroup({layout:this._.getBindGroupLayout(0),entries:[{binding:0,resource:this.l},{binding:1,resource:this.o}]});const s=this.t.createShaderModule({label:"Extract Shader",code:"@group(0) @binding(0) var in_texture: texture_2d<f32>;\\n@group(0) @binding(1) var<storage, read_write> out_tensor: array<f32>;\\n\\n@compute @workgroup_size(16, 16)\\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let x = gid.x;\\n let y = gid.y;\\n\\n // Only process a 320x320 region.\\n if (x >= 320u || y >= 320u) {\\n return;\\n }\\n\\n // 320x320 crop is located beside the frame on the \\n let offset_x = x + 1280u + 16u; // 1280 frame + 16 pixel padding for color correction region\\n let offset_y = y + 16u; // 16 pixel padding for color correction region\\n\\n let pixel = textureLoad(in_texture, vec2<u32>(offset_x, offset_y), 0);\\n\\n\\n let idx = y * 320u + x;\\n let plane = 320u * 320u;\\n\\n // Channels-first layout, BGR\\n out_tensor[0u * plane + idx] = pixel.b;\\n out_tensor[1u * plane + idx] = pixel.g;\\n out_tensor[2u * plane + idx] = pixel.r;\\n}\\n"});this.m=this.t.createComputePipeline({layout:"auto",compute:{module:s,entryPoint:"main"}}),this.v=this.t.createBindGroup({layout:this.m.getBindGroupLayout(0),entries:[{binding:0,resource:this.l},{binding:1,resource:{buffer:this.u}}]})}l;_;h;m;v;extract(){const e=this.t.createCommandEncoder(),t=e.beginComputePass();t.setPipeline(this._),t.setBindGroup(0,this.h),t.dispatchWorkgroups(1,1,1),t.end();const n=e.beginComputePass();n.setPipeline(this.m),n.setBindGroup(0,this.v),n.dispatchWorkgroups(20,20,1),n.end(),this.t.queue.submit([e.finish()])}destroy(){}}class i{constructor(e,t,n,i,r,s,a){this.p=e,this.t=t,this.U=n,this.P=i,this.B=r,this.k=s,this.G=a,this.O=navigator.gpu.getPreferredCanvasFormat(),this.p.configure({device:this.t,format:this.O,alphaMode:"opaque"}),this.A=this.t.createBuffer({size:24,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});const o=this.F(this.k,this.G);this.t.queue.writeBuffer(this.A,0,o.buffer),this.R=this.U.createView();const u=this.t.createShaderModule({label:"Render Shader",code:"struct BBox { xmin:f32, ymin:f32, xmax:f32, ymax:f32 };\\nstruct ROI { xmin:f32, ymin:f32, xmax:f32, ymax:f32, width:f32, height:f32 };\\n\\n@group(0) @binding(0) var frame_texture : texture_2d<f32>;\\n@group(0) @binding(1) var frame_sampler : sampler;\\n\\n@group(0) @binding(2) var<storage, read_write> out_tensor: array<f32>;\\n\\n@group(0) @binding(3) var<storage, read> mouth_bbox : BBox;\\n@group(0) @binding(4) var<uniform> roi_bbox : ROI;\\n\\nstruct VSOut {\\n @builtin(position) pos : vec4<f32>,\\n};\\n\\n@vertex\\nfn vs_main(@builtin(vertex_index) vid : u32) -> VSOut {\\n var p = array<vec2<f32>, 3>(\\n vec2<f32>(-1.0, -1.0),\\n vec2<f32>( 3.0, -1.0),\\n vec2<f32>(-1.0, 3.0)\\n );\\n var out : VSOut;\\n out.pos = vec4<f32>(p[vid], 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fs_main(@builtin(position) frag_pos : vec4<f32>) -> @location(0) vec4<f32> {\\n let canvas_size = vec2<f32>(roi_bbox.width, roi_bbox.height);\\n let canvas_uv = frag_pos.xy / canvas_size;\\n\\n let atlas_size = vec2<f32>(textureDimensions(frame_texture, 0));\\n\\n // Frame rect inside atlas (in UV)\\n let frame_size = vec2<f32>(1280.0, 720.0);\\n let frame_size_uv = frame_size / atlas_size;\\n\\n // ROI is normalized in the FRAME (0..1)\\n let roi_min_f = vec2<f32>(roi_bbox.xmin, roi_bbox.ymin);\\n let roi_max_f = vec2<f32>(roi_bbox.xmax, roi_bbox.ymax);\\n let roi_size_f = max(roi_max_f - roi_min_f, vec2<f32>(1e-6));\\n\\n // Canvas UV -> ROI UV (still in FRAME-normalized coordinates)\\n var roi_uv_f = roi_min_f + canvas_uv * roi_size_f;\\n\\n // Convert FRAME-normalized UV -> ATLAS UV\\n var atlas_uv = roi_uv_f * frame_size_uv;\\n\\n // Clamp inside ROI, but in ATLAS UV, inset by half a texel to avoid edge repetition\\n let half_texel_uv = 0.5 / atlas_size;\\n\\n let roi_min_atlas_uv = roi_min_f * frame_size_uv + half_texel_uv;\\n let roi_max_atlas_uv = roi_max_f * frame_size_uv - half_texel_uv;\\n\\n atlas_uv = clamp(atlas_uv, roi_min_atlas_uv, roi_max_atlas_uv);\\n\\n let frame_color = textureSample(frame_texture, frame_sampler, atlas_uv);\\n\\n\\n // Convert mouth_bbox from frame-normalized to canvas-normalized coordinates.\\n let mouth_min_canvas = (vec2<f32>(mouth_bbox.xmin, mouth_bbox.ymin) - roi_min_f) / roi_size_f;\\n let mouth_max_canvas = (vec2<f32>(mouth_bbox.xmax, mouth_bbox.ymax) - roi_min_f) / roi_size_f;\\n\\n let inside =\\n canvas_uv.x >= mouth_min_canvas.x && canvas_uv.x <= mouth_max_canvas.x &&\\n canvas_uv.y >= mouth_min_canvas.y && canvas_uv.y <= mouth_max_canvas.y;\\n\\n let rect_size = vec2<f32>(\\n max(mouth_max_canvas.x - mouth_min_canvas.x, 1e-6),\\n max(mouth_max_canvas.y - mouth_min_canvas.y, 1e-6)\\n );\\n\\n let crop_uv = clamp(\\n (canvas_uv - mouth_min_canvas) / rect_size,\\n vec2<f32>(0.0), vec2<f32>(1.0)\\n );\\n\\n let tx = min(u32(crop_uv.x * 320.0), 319u);\\n let ty = min(u32(crop_uv.y * 320.0), 319u);\\n let idx = ty * 320u + tx;\\n let stride = 320u * 320u;\\n\\n let b = out_tensor[0u * stride + idx];\\n let g = out_tensor[1u * stride + idx];\\n let r = out_tensor[2u * stride + idx];\\n let crop_color = vec4<f32>(r, g, b, 1.0);\\n\\n return select(frame_color, crop_color, inside);\\n}"});this.V=this.t.createRenderPipeline({layout:"auto",vertex:{module:u,entryPoint:"vs_main"},fragment:{module:u,entryPoint:"fs_main",targets:[{format:this.O}]},primitive:{topology:"triangle-list"}});const l=this.t.createSampler({magFilter:"linear",minFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge"});this.T=this.t.createBindGroup({layout:this.V.getBindGroupLayout(0),entries:[{binding:0,resource:this.R},{binding:1,resource:l},{binding:2,resource:this.P},{binding:3,resource:{buffer:this.B}},{binding:4,resource:{buffer:this.A}}]})}R;V;T;O;A;render(){const e=this.t.createCommandEncoder(),t=e.beginRenderPass({colorAttachments:[{view:this.p.getCurrentTexture().createView(),clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});t.setPipeline(this.V),t.setBindGroup(0,this.T),t.draw(3),t.end(),this.t.queue.submit([e.finish()])}clear(){const e=this.t.createCommandEncoder();e.beginRenderPass({colorAttachments:[{view:this.p.getCurrentTexture().createView(),clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]}).end(),this.t.queue.submit([e.finish()])}destroy(){}F(e,t){const n=t/e;let i,r;1280/t>720/e?(r=720,i=Math.min(1280,Math.round(r*n))):(i=1280,r=Math.min(720,Math.round(i/n)));const s=Math.round((1280-i)/2)/1280,a=Math.round((720-r)/2)/720;return new Float32Array([s,a,s+i/1280,a+r/720,t,e])}}var r=/* @__PURE__ */(e=>(e.Chromium="chromium",e.Firefox="firefox",e.Safari="safari",e.Opera="opera",e.Unknown="unknown",e))(r||{});e.env.wasm.wasmPaths="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/";const s=new class{C=null;p=null;M=null;U;S=[];I=[];L;q;D=[];N;j;B;$;H;J=!1;K;W;X;Y=function(){const e=navigator.userAgent;return e.includes("Firefox")?"firefox":e.includes("OPR")||e.includes("Opera")?"opera":e.includes("Edg")?"chromium":!e.includes("Chrome")||e.includes("Chromium")||e.includes("OPR")||e.includes("Edg")?!e.includes("Safari")||e.includes("Chrome")||e.includes("Chromium")?"unknown":"safari":"chromium"}();async init(r,s){if(this.C=await async function(){const e=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(!e)return null;const t=["shader-f16","bgra8unorm-storage","rg11b10ufloat-renderable","float32-filterable"].filter(t=>e.features.has(t)),n=await e.requestDevice({requiredFeatures:t});return GPUAdapter.prototype.requestDevice=async function(){return n},navigator.gpu.requestAdapter=async()=>e,n}(),!this.C)return void console.error("Failed to create GPU device.");if(this.M=await e.InferenceSession.create(r,{executionProviders:["webgpu"],preferredOutputLocation:"gpu-buffer",graphOptimizationLevel:"all",logSeverityLevel:3}),this.U=this.C.createTexture({size:[1640,720,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.STORAGE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),this.L=this.C.createBuffer({size:32768,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),this.q=e.Tensor.fromGpuBuffer(this.L,{dataType:"float32",dims:[1,32,16,16]}),this.N=this.C.createBuffer({size:1228800,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST}),this.j=e.Tensor.fromGpuBuffer(this.N,{dataType:"float32",dims:[1,3,320,320]}),this.B=this.C.createBuffer({size:16,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST}),this.$=this.C.createBuffer({size:1228800,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST}),this.H=e.Tensor.fromGpuBuffer(this.$,{dataType:"float32",dims:[1,3,320,320]}),this.K=new n(this.C,this.U,this.B,this.N),this.X=s,this.p=this.X.getContext("webgpu"),!this.p)return void console.error("Failed to get canvas context.");this.W=new i(this.p,this.C,this.U,this.$,this.B,this.X.height,this.X.width);const a={type:t.READY};self.postMessage(a)}async onVideoFrame(e){if(this.D.push(e),this.D.length>=3){console.error("Dropping frames to avoid backpressure...",this.D.length);const e=this.D.shift();e?.close()}}async onRender(e){if(this.J)return void console.error("Already rendering.");if(0===this.D.length)return void console.warn("No frame available for rendering...");this.J=!0;const t=performance.now(),n=this.D.shift();try{let t=0;for(;t<this.I.length&&this.I[t]<e;)t++;if(t>=this.I.length)return n.close(),void console.warn("No audio feature for pts",e);const i=this.S[t];this.S=this.S.slice(t+1),this.I=this.I.slice(t+1),this.C.queue.writeBuffer(this.L,0,i);let s=n;this.Y!==r.Safari&&(s=await createImageBitmap(n)),this.C.queue.copyExternalImageToTexture({source:s},{texture:this.U},[n.displayWidth,n.displayHeight]),this.Y!==r.Safari&&s.close(),this.K.extract(),await this.infer(),this.W.render()}finally{this.J=!1,n.close()}const i=performance.now()-t;i>25&&console.warn(`Render time: ${i} ms`)}async onAudioFeature(e,t){this.S.push(e.buffer),this.I.push(t)}async reset(n){this.S=[],this.I=[],this.D.forEach(e=>e.close()),this.D=[],this.W.clear(),n&&(await(this.M?.release()),this.M=null,this.M=await e.InferenceSession.create(n,{executionProviders:["webgpu"],preferredOutputLocation:"gpu-buffer",graphOptimizationLevel:"all",logSeverityLevel:3}));const i={type:t.RESETTED};self.postMessage(i)}async destroy(){this.K.destroy(),this.W.destroy(),await(this.M?.release()),this.M=null,this.U.destroy(),this.q.dispose(),this.j.dispose(),this.N.destroy(),this.B.destroy(),this.H.dispose(),this.$.destroy(),this.C?.destroy(),this.C=null,this.p=null;const e={type:t.DESTROYED};self.postMessage(e)}async infer(){if(!this.M)return null;const e={[this.M.inputNames[0]]:this.j,[this.M.inputNames[1]]:this.q},t={[this.M.outputNames[0]]:this.H};return this.M.run(e,t).catch(e=>(console.error("Inference error:",e),null))}};self.onmessage=async e=>{const n=e.data;try{n.type===t.INIT?await s.init(n.model,n.canvas):n.type===t.AUD_FEATS?await s.onAudioFeature(n.features,n.pts):n.type===t.VID_FRAME?await s.onVideoFrame(n.frame):n.type===t.RDR_FRAME?await s.onRender(n.pts):n.type===t.RESET?await s.reset(n.modelUrl):n.type===t.DESTROY&&await s.destroy()}catch(i){const e={type:t.ERROR,data:i};self.postMessage(e)}};const a={type:t.LOADED};self.postMessage(a);\n',T=typeof self<"u"&&self.Blob&&new Blob(["URL.revokeObjectURL(import.meta.url);",v],{type:"text/javascript;charset=utf-8"});function X(s){let t;try{if(t=T&&(self.URL||self.webkitURL).createObjectURL(T),!t)throw"";const e=new Worker(t,{type:"module",name:s?.name});return e.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),e}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(v),{type:"module",name:s?.name})}}var u=(s=>(s.INIT="init",s.AUD_FEATS="audio-features",s.VID_FRAME="video-frame",s.RDR_FRAME="render",s.DESTROY="destroy",s.RESET="reset",s.LOADED="loaded",s.READY="ready",s.RESETTED="resetted",s.DESTROYED="destroyed",s.ERROR="error",s))(u||{});class F{constructor(t,e){this.t=t,this.At=e,this.lt=h(),this.ct=new X,this.ct.onerror=this.ut.bind(this),this.ct.onmessage=this.dt.bind(this),this.t.addListener(r.AUD_FEATS,this.Ct.bind(this)),this.t.addListener(r.VID_FRAME,this.vt.bind(this)),this.t.addListener(r.RDR_FRAME,this.Bt.bind(this))}ct;lt=null;yt=null;Rt=null;ft=null;bt=!1;async init(t){this.yt=h(),await this.lt?.promise;const e={type:u.INIT,model:t,canvas:this.At};return this.ct.postMessage(e,[this.At]),this.yt?.promise}async enable(){this.bt=!0}async disable(){this.bt=!1}async reset(t){this.Rt=h();const e={type:u.RESET,modelUrl:t};return this.ct.postMessage(e),this.Rt?.promise}async destroy(){this.ft=h();const t={type:u.DESTROY};return this.ct.postMessage(t),this.ft?.promise}Ct(t,e){if(!this.bt)return;const i={type:u.AUD_FEATS,features:t,pts:e};return this.ct.postMessage(i,[t.buffer])}vt(t){if(!this.bt)return void t.close();const e={type:u.VID_FRAME,frame:t};return this.ct.postMessage(e,[t])}Bt(t){if(!this.bt)return;const e={type:u.RDR_FRAME,pts:t};return this.ct.postMessage(e)}async dt(t){const e=t.data;e.type===u.LOADED?this.It():e.type===u.READY?this._t():e.type===u.RESETTED?this.xt():e.type===u.ERROR?this.ut(e.data):e.type===u.DESTROYED&&this.wt()}It(){this.lt?.resolve(),this.lt=null}_t(){this.yt?.resolve(),this.yt=null}xt(){this.Rt?.resolve(),this.Rt=null}ut(t){console.error(t)}wt(){this.ct.terminate(),this.ft?.resolve(),this.ft=null}}class M{constructor(t){this.t=t,this.Vt=document.createElement("video"),this.Vt.loop=!0,this.Vt.muted=!0,this.Vt.preload="auto",this.Vt.style.display="none",document.body.appendChild(this.Vt)}Vt;Gt=!1;async src(t){this.Vt.src=t}async play(){return this.Gt||(this.Vt.requestVideoFrameCallback(this.Ut.bind(this)),this.Gt=!0),this.Vt.play()}async pause(){return this.Vt.pause()}async destroy(){await this.pause();try{document.body.removeChild(this.Vt)}catch(t){console.warn("Error removing video element:",t)}}async Ut(t,e){this.Vt.requestVideoFrameCallback(this.Ut.bind(this));let i=null;i=new VideoFrame(this.Vt,{timestamp:1e6*e.mediaTime}),this.t.emit(r.VID_FRAME,i)}}var g=(s=>(s.MUST_INIT="must call init()",s.MUST_USE="must call use()",s.NOT_IDLE="cannot call if not initialized or ready",s.STARTED="cannot call while started",s.DESTROYED="cannot call after destroy()",s.INVALID_TOKEN="could not read access token",s.CANNOT_USE_CHARACTER="pipeline is scoped to access token character",s.NO_CONTAINER="container not in DOM",s))(g||{});class R extends Error{constructor(t,e){super(t),this.code=e,this.name="EquosPipelineError"}}var I=(s=>(s.CREATED="created",s.INITIALIZED="initialized",s.READY="ready",s.STARTED="started",s.DESTROYED="destroyed",s))(I||{}),b=(s=>(s.UTTERANCE="utterance",s.INTERRUPT="interrupt",s.ERROR="error",s))(b||{});class w{constructor(t){this.Xt=t,this.I=t.endpoint||"wss://run.equos.ai/run",this.kt=!!t.audio?.enabled,this.Et=!!t.video?.enabled;try{this.Wt=this.St(this.Xt.accessToken)}catch{throw new Error(g.INVALID_TOKEN)}this.Ft("finished instantiation")}Zt="created";Tt=new Map;I;Wt;Nt=null;kt=!1;Et=!1;getState(){return this.Zt}async init(){this.Ft("initializing..."),this.Mt(),this.Zt==="created"?(await this.Ot(),this.Zt="initialized",this.Ft("successfully initialized"),this.Wt.character&&await this.use(this.Wt.character)):this.zt("skipping init, already initialized")}async use(t){this.Ft(`using ${t}`),this.Mt(),this.Dt(),this.Kt(t),this.Nt!==t?(await this.Lt(t),this.Nt=t,this.Zt="ready",this.Ft(`successfully using ${t}`)):this.zt(`skipping use, already using ${t}`)}async start(t){this.Ft("starting..."),this.Mt(),this.Zt!=="started"?(this.Yt(),this.Zt="started",await this.Ht(t),this.Ft("successfully started")):this.zt("skipping start, already started")}async stop(){this.Ft("stopping..."),this.Mt(),this.Zt==="started"?(await this.Pt(),this.Zt="ready",this.Ft("successfully stopped")):this.zt("skipping stop, not started")}async destroy(){this.Ft("destroying"),this.Zt!=="destroyed"?(this.Tt.clear(),await this.Jt(),this.Zt="destroyed",this.Ft("successfully destroyed")):this.zt("skipping destroy, already destroyed")}on(t,e){if(this.Zt==="destroyed")return;const i=this.Tt.get(t),n=e;i?i.add(n):this.Tt.set(t,new Set([n]))}off(t,e){const i=this.Tt.get(t);i&&i.delete(e)}async Qt(t,...e){if(this.Zt==="destroyed")throw new Error(g.DESTROYED);const i=this.Tt.get(t);if(i)for(const n of i)await n(...e)}video(){return{enable:this.jt.bind(this),disable:this.qt.bind(this)}}audio(){return{pushUsrAudio:this.$t.bind(this),enable:this.te.bind(this),disable:this.ee.bind(this)}}Ft(t){this.Xt.debug&&console.log(`[equos] pipeline (${this.Xt.name||"no name"}): ${t}`)}zt(t){this.Xt.debug&&console.warn(`[equos] pipeline (${this.Xt.name||"no name"}): ${t}`)}St(t){const e=t.split(".")[1],i=atob(e.replace(/-/g,"+").replace(/_/g,"/")),n=JSON.parse(i);if(!n.org||typeof n.org!="string"||!n.user||typeof n.user!="string"||n.character&&typeof n.character!="string")throw new Error;return{org:n.org,user:n.user,character:n.character||null}}Mt(){if(this.Zt==="destroyed")throw new Error(g.DESTROYED)}Yt(){if(this.Zt!=="ready")throw new Error(g.MUST_USE)}Dt(){if(!["initialized","ready"].includes(this.Zt))throw new Error(g.NOT_IDLE)}Kt(t){if(this.Wt.character&&this.Wt.character!==t)throw new Error(g.CANNOT_USE_CHARACTER)}}class k extends w{constructor(t){if(super(t),this.Xt=t,this.t=new B,this.listenToBus(),this.se=G.new(this.I,this.Xt.accessToken,this.t),this.ie=O.new(this.Wt.org+"_"+this.Wt.user),this.ne=new U(this.t),this.Xt.video){if(this.re=document.querySelector(this.Xt.video.containerSelector),!this.re)throw new Error(g.NO_CONTAINER);this.ae=document.createElement("canvas"),this.ae.width=this.Xt.video.width,this.ae.height=this.Xt.video.height,this.re.appendChild(this.ae),this.ae.style.display="none",this.oe=new M(this.t),this.he=new D(this.t),this.le=new F(this.t,this.ae.transferControlToOffscreen())}}t;se;ie;ne;re=null;ae=null;oe=null;he=null;le=null;ce=!1;async Ot(){return Promise.all([this.se.connect(),this.ie.synchronize(),this.ne.init()]).then()}async Lt(t){const e=await this.se.use(t);if(this.he&&this.le&&this.oe){const[i,n,c]=await Promise.all([this.ie.fetch(e.audioModelUrl),this.ie.fetch(e.videoModelUrl),this.ie.fetch(e.videoUrl)]);await this.oe.src(c),this.ce?await this.le.reset(n):(await Promise.all([this.he.init(i),this.le.init(n)]),this.ce=!0)}}async Ht(t){await this.se.start(t),this.kt&&await this.te(),this.Et&&await this.jt()}async Pt(){await Promise.all([this.se.stop().then(()=>console.log("Connector stopped")),this.ee(!1).then(()=>console.log("Audio stopped")),this.qt(!1).then(()=>console.log("Video stopped"))])}async Jt(){return this.t.destroy(),this.re&&this.ae&&this.re.removeChild(this.ae),Promise.all([this.se.destroy(),this.ie.destroy(),this.ne.destroy(),this.oe?.destroy(),this.he?.destroy()]).then()}async jt(){this.Xt.video?(this.Et=!0,this.kt||await this.te(),this.getState()===I.STARTED&&(await this.oe?.play(),await this.he?.enable(),await this.le?.enable(),this.ae&&(this.ae.style.display=""))):this.zt("video is not enabled in the pipeline config")}async qt(t=!0){t&&(this.Et=!1),await this.oe?.pause(),await this.he?.disable(),await this.le?.disable(),await this.he?.reset(),await this.le?.reset(),this.ae&&(this.ae.style.display="none")}async $t(t){this.t.emit(r.USR_AUDIO,t)}async te(){this.kt=!0,this.getState()===I.STARTED&&await this.ne.start()}async ee(t=!0){t&&(this.kt=!1),await this.ne.stop()}listenToBus(){this.t.addListener(r.INTERRUPT,()=>{this.Qt(b.INTERRUPT)}),this.t.addListener(r.UTTERANCE,t=>{this.Qt(b.UTTERANCE,t)}),this.t.addListener(r.NWK_ERROR,async t=>{const e=t?new R("Network failed","NETWORK_FAILED"):new R("Network disconnected, attempting to reconnect...","NETWORK_DISCONNECTED");this.Qt(b.ERROR,e),this.getState()===I.STARTED&&await this.stop()}),this.t.addListener(r.SRV_ERROR,t=>{this.Qt(b.ERROR,new R(`Remote error: ${t}`,t))})}}class W{static new(t){return new k(t)}}class Z{constructor(t){this.onAudio=t,this.i=new AudioContext({latencyHint:"interactive",sampleRate:A})}i;ue=null;de=null;l=null;async init(){return this.i.audioWorklet.addModule(URL.createObjectURL(new Blob([atob("Ly8gc3JjL2F1ZGlvL3VzZXIvY29udHJhY3QudHMKdmFyIFdPUktMRVRfTkFNRSA9ICJ1c3ItYXVkaW8td29ya2xldCI7CgovLyBzcmMvYXVkaW8vdXNlci93b3JrbGV0LnRzCnZhciBTQU1QTEVfUkFURSA9IDE2ZTM7CnZhciBDSFVOS19NUyA9IDQwOwp2YXIgQ0hVTktfU0laRSA9IFNBTVBMRV9SQVRFICogQ0hVTktfTVMgLyAxZTM7CnZhciBVc2VyQXVkaW9Xb3JrbGV0ID0gY2xhc3MgZXh0ZW5kcyBBdWRpb1dvcmtsZXRQcm9jZXNzb3IgewogIF9jaHVuayA9IG5ldyBGbG9hdDMyQXJyYXkoQ0hVTktfU0laRSk7CiAgX3dyaXRlSW5kZXggPSAwOwogIHByb2Nlc3MoaW5wdXRzKSB7CiAgICBjb25zdCBpbnB1dCA9IGlucHV0c1swXT8uWzBdOwogICAgaWYgKCFpbnB1dCB8fCBpbnB1dC5sZW5ndGggPT09IDApIHJldHVybiB0cnVlOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbnB1dC5sZW5ndGg7IGkrKykgewogICAgICB0aGlzLl9jaHVua1t0aGlzLl93cml0ZUluZGV4KytdID0gaW5wdXRbaV07CiAgICAgIGlmICh0aGlzLl93cml0ZUluZGV4ID49IENIVU5LX1NJWkUpIHsKICAgICAgICBjb25zdCBjb3B5ID0gbmV3IEZsb2F0MzJBcnJheSh0aGlzLl9jaHVuayk7CiAgICAgICAgdGhpcy5wb3J0LnBvc3RNZXNzYWdlKGNvcHksIFtjb3B5LmJ1ZmZlcl0pOwogICAgICAgIHRoaXMuX2NodW5rID0gbmV3IEZsb2F0MzJBcnJheShDSFVOS19TSVpFKTsKICAgICAgICB0aGlzLl93cml0ZUluZGV4ID0gMDsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQp9OwpyZWdpc3RlclByb2Nlc3NvcihXT1JLTEVUX05BTUUsIFVzZXJBdWRpb1dvcmtsZXQpOwo=")],{type:"text/javascript"})))}async start(){this.l&&(this.l.disconnect(),this.l=null),this.ue=await navigator.mediaDevices.getUserMedia({audio:{channelCount:1,sampleRate:A,echoCancellation:!0,noiseSuppression:!0}}),this.de=this.i.createMediaStreamSource(this.ue),this.l=new AudioWorkletNode(this.i,"usr-audio-worklet",{numberOfInputs:1,numberOfOutputs:0,channelCount:1}),this.l.port.onmessage=t=>{this.onAudio(t.data)},this.de.connect(this.l),this.i.state!=="running"&&await this.i.resume()}async stop(){this.l?.disconnect(),this.l=null,this.de?.disconnect(),this.de=null,this.ue?.getTracks().forEach(t=>t.stop()),this.ue=null,this.i.state==="running"&&await this.i.suspend()}async destroy(){return await this.stop(),this.i.close()}}export{w as EquosPipeline,R as EquosPipelineError,g as EquosPipelineErrors,b as EquosPipelineEvents,W as EquosPipelineFactory,I as EquosPipelineState,Z as EquosUserAudioRecorder};
|