diff --git a/public/maia-worker.js b/public/maia-worker.js new file mode 100644 index 00000000..6a908068 --- /dev/null +++ b/public/maia-worker.js @@ -0,0 +1,201 @@ +/** + * Maia3 Web Worker — runs ONNX inference off the main thread. + * + * Messages FROM main thread: + * { type: 'init', modelUrl, modelVersion } + * { type: 'download' } + * { type: 'inference', id, tokens, eloSelfs, eloOppos, batchSize } + * + * Messages TO main thread: + * { type: 'status', status } + * { type: 'progress', progress } + * { type: 'error', message, id? } + * { type: 'inference-result', id, logitsMove, logitsValue } + */ + +importScripts('/ort/ort.wasm.min.js') + +const ORT = ort +ORT.env.wasm.wasmPaths = '/ort/' + +// ── IndexedDB storage (mirrors MaiaModelStorage) ───────────────────────────── + +const DB_NAME = 'MaiaModels' +const STORE_NAME = 'models' +const MODEL_KEY = 'maia-rapid-model' + +function openDB() { + return new Promise((resolve, reject) => { + const request = indexedDB.open(DB_NAME, 1) + request.onerror = () => reject(request.error) + request.onsuccess = () => resolve(request.result) + request.onupgradeneeded = (event) => { + const db = event.target.result + if (!db.objectStoreNames.contains(STORE_NAME)) { + db.createObjectStore(STORE_NAME, { keyPath: 'id' }) + } + } + }) +} + +async function getCachedModel(modelUrl, modelVersion) { + const db = await openDB() + const tx = db.transaction([STORE_NAME], 'readonly') + const store = tx.objectStore(STORE_NAME) + + const data = await new Promise((resolve, reject) => { + const req = store.get(MODEL_KEY) + req.onsuccess = () => resolve(req.result || null) + req.onerror = () => reject(req.error) + }) + + if (!data) return null + + if (data.version && data.version !== modelVersion) { + const rwTx = db.transaction([STORE_NAME], 'readwrite') + rwTx.objectStore(STORE_NAME).delete(MODEL_KEY) + return null + } + + return await data.data.arrayBuffer() +} + +async function storeModel(modelUrl, modelVersion, buffer) { + const db = await openDB() + const tx = db.transaction([STORE_NAME], 'readwrite') + const store = tx.objectStore(STORE_NAME) + + await new Promise((resolve, reject) => { + const req = store.put({ + id: MODEL_KEY, + url: modelUrl, + version: modelVersion, + data: new Blob([buffer]), + timestamp: Date.now(), + size: buffer.byteLength, + }) + req.onsuccess = () => resolve() + req.onerror = () => reject(req.error) + }) +} + +// ── Worker state ───────────────────────────────────────────────────────────── + +let session = null +let modelUrl = null +let modelVersion = null + +async function initSession(buffer) { + session = await ORT.InferenceSession.create(buffer) +} + +// ── Message handler ────────────────────────────────────────────────────────── + +self.onmessage = async (e) => { + const msg = e.data + + try { + switch (msg.type) { + case 'init': { + modelUrl = msg.modelUrl + modelVersion = msg.modelVersion + postMessage({ type: 'status', status: 'loading' }) + + const buffer = await getCachedModel(modelUrl, modelVersion) + if (buffer) { + await initSession(buffer) + postMessage({ type: 'status', status: 'ready' }) + } else { + postMessage({ type: 'status', status: 'no-cache' }) + } + break + } + + case 'download': { + const response = await fetch(modelUrl) + if (!response.ok) throw new Error('Failed to fetch model') + + const reader = response.body.getReader() + const contentLength = +(response.headers.get('Content-Length') || 0) + const chunks = [] + let receivedLength = 0 + let lastReportedProgress = 0 + + while (true) { + const { done, value } = await reader.read() + if (done) break + chunks.push(value) + receivedLength += value.length + const currentProgress = Math.floor( + (receivedLength / contentLength) * 100, + ) + if (currentProgress >= lastReportedProgress + 10) { + postMessage({ type: 'progress', progress: currentProgress }) + lastReportedProgress = currentProgress + } + } + + const buffer = new Uint8Array(receivedLength) + let position = 0 + for (const chunk of chunks) { + buffer.set(chunk, position) + position += chunk.length + } + + await storeModel(modelUrl, modelVersion, buffer.buffer) + await initSession(buffer.buffer) + postMessage({ type: 'status', status: 'ready' }) + break + } + + case 'inference': { + if (!session) { + postMessage({ + type: 'error', + message: 'Model not initialized', + id: msg.id, + }) + return + } + + const { id, tokens, eloSelfs, eloOppos, batchSize } = msg + + const feeds = { + tokens: new ORT.Tensor('float32', new Float32Array(tokens), [ + batchSize, + 64, + 12, + ]), + elo_self: new ORT.Tensor('float32', new Float32Array(eloSelfs), [ + batchSize, + ]), + elo_oppo: new ORT.Tensor('float32', new Float32Array(eloOppos), [ + batchSize, + ]), + } + + const result = await session.run(feeds) + + const logitsMove = new Float32Array(result.logits_move.data) + const logitsValue = new Float32Array(result.logits_value.data) + + postMessage( + { + type: 'inference-result', + id, + logitsMove: logitsMove.buffer, + logitsValue: logitsValue.buffer, + }, + [logitsMove.buffer, logitsValue.buffer], + ) + break + } + } + } catch (err) { + postMessage({ + type: 'error', + message: err.message || 'Unknown worker error', + id: msg.id, + }) + } +} diff --git a/public/ort/ort-wasm-simd-threaded.mjs b/public/ort/ort-wasm-simd-threaded.mjs new file mode 100644 index 00000000..9e3bfd47 --- /dev/null +++ b/public/ort/ort-wasm-simd-threaded.mjs @@ -0,0 +1,68 @@ +var ortWasmThreaded = (() => { + + return ( +async function(moduleArg = {}) { + var moduleRtn; + +var f=moduleArg,k,aa,ba=new Promise((a,b)=>{k=a;aa=b}),ca="object"==typeof window,l="undefined"!=typeof WorkerGlobalScope,m="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node&&"renderer"!=process.type,n=l&&self.name?.startsWith("em-pthread");if(m){const {createRequire:a}=await import("module");var require=a(import.meta.url),q=require("worker_threads");global.Worker=q.Worker;n=(l=!q.ib)&&"em-pthread"==q.workerData} +f.mountExternalData=(a,b)=>{a.startsWith("./")&&(a=a.substring(2));(f.Sa||(f.Sa=new Map)).set(a,b)};f.unmountExternalData=()=>{delete f.Sa};var SharedArrayBuffer=globalThis.SharedArrayBuffer??(new WebAssembly.Memory({initial:0,maximum:0,kb:!0})).buffer.constructor,da="./this.program",r=(a,b)=>{throw b;},ea=import.meta.url,t="",fa,v; +if(m){var fs=require("fs"),ha=require("path");ea.startsWith("file:")&&(t=ha.dirname(require("url").fileURLToPath(ea))+"/");v=a=>{a=w(a)?new URL(a):a;return fs.readFileSync(a)};fa=async a=>{a=w(a)?new URL(a):a;return fs.readFileSync(a,void 0)};1{process.exitCode=a;throw b;}}else if(ca||l){try{t=(new URL(".",ea)).href}catch{}m||(l&&(v=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer"; +b.send(null);return new Uint8Array(b.response)}),fa=async a=>{if(w(a))return new Promise((c,d)=>{var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=()=>{200==e.status||0==e.status&&e.response?c(e.response):d(e.status)};e.onerror=d;e.send(null)});var b=await fetch(a,{credentials:"same-origin"});if(b.ok)return b.arrayBuffer();throw Error(b.status+" : "+b.url);})}var ia=console.log.bind(console),ja=console.error.bind(console); +if(m){var ka=require("util"),la=a=>"object"==typeof a?ka.inspect(a):a;ia=(...a)=>fs.writeSync(1,a.map(la).join(" ")+"\n");ja=(...a)=>fs.writeSync(2,a.map(la).join(" ")+"\n")}var ma=ia,x=ja,y,z,na,A=!1,B,C,oa,pa,qa,ra,sa,D,ta,w=a=>a.startsWith("file://");function E(){z.buffer!=C.buffer&&F();return C}function G(){z.buffer!=C.buffer&&F();return oa}function wa(){z.buffer!=C.buffer&&F();return pa}function H(){z.buffer!=C.buffer&&F();return qa}function I(){z.buffer!=C.buffer&&F();return ra} +function xa(){z.buffer!=C.buffer&&F();return sa}function J(){z.buffer!=C.buffer&&F();return ta}var ya;if(m&&n){var za=q.parentPort;za.on("message",a=>global.onmessage?.({data:a}));Object.assign(globalThis,{self:global,postMessage:a=>za.postMessage(a)})} +if(n){var Aa=!1;self.onunhandledrejection=b=>{throw b.reason||b;};function a(b){try{var c=b.data,d=c.Ra;if("load"===d){let e=[];self.onmessage=g=>e.push(g);self.startWorker=()=>{postMessage({Ra:"loaded"});for(let g of e)a(g);self.onmessage=a};for(const g of c.Za)if(!f[g]||f[g].proxy)f[g]=(...h)=>{postMessage({Ra:"callHandler",Ya:g,args:h})},"print"==g&&(ma=f[g]),"printErr"==g&&(x=f[g]);z=c.fb;F();ya(c.gb)}else if("run"===d){Ba(c.Qa);Ca(c.Qa,0,0,1,0,0);Da();Ea(c.Qa);Aa||=!0;try{Fa(c.bb,c.Va)}catch(e){if("unwind"!= +e)throw e;}}else"setimmediate"!==c.target&&("checkMailbox"===d?Aa&&K():d&&(x(`worker: received unknown command ${d}`),x(c)))}catch(e){throw Ga(),e;}}self.onmessage=a}function F(){var a=z.buffer;f.HEAP8=C=new Int8Array(a);pa=new Int16Array(a);f.HEAPU8=oa=new Uint8Array(a);new Uint16Array(a);f.HEAP32=qa=new Int32Array(a);f.HEAPU32=ra=new Uint32Array(a);sa=new Float32Array(a);ta=new Float64Array(a);D=new BigInt64Array(a);new BigUint64Array(a)}function Ha(){n?startWorker(f):L.$()}var M=0,N=null; +function Ia(){M--;if(0==M&&N){var a=N;N=null;a()}}function O(a){a="Aborted("+a+")";x(a);A=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");aa(a);throw a;}var Ja;async function Ka(a){if(!y)try{var b=await fa(a);return new Uint8Array(b)}catch{}if(a==Ja&&y)a=new Uint8Array(y);else if(v)a=v(a);else throw"both async and sync fetching of the wasm failed";return a} +async function La(a,b){try{var c=await Ka(a);return await WebAssembly.instantiate(c,b)}catch(d){x(`failed to asynchronously prepare wasm: ${d}`),O(d)}}async function Ma(a){var b=Ja;if(!y&&"function"==typeof WebAssembly.instantiateStreaming&&!w(b)&&!m)try{var c=fetch(b,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(c,a)}catch(d){x(`wasm streaming compile failed: ${d}`),x("falling back to ArrayBuffer instantiation")}return La(b,a)} +function Na(){Oa={j:Pa,b:Qa,E:Ra,f:Sa,U:Ta,A:Ua,C:Va,V:Wa,S:Xa,L:Ya,R:Za,n:$a,B:ab,y:bb,T:cb,z:db,_:eb,O:fb,w:gb,F:hb,t:ib,i:jb,N:Ea,X:kb,I:lb,J:mb,K:nb,G:ob,H:pb,u:qb,q:rb,Z:sb,o:tb,k:ub,Y:vb,d:wb,W:xb,x:yb,c:zb,e:Ab,h:Bb,v:Cb,s:Db,r:Eb,P:Fb,Q:Gb,D:Hb,g:Ib,m:Jb,M:Kb,l:Lb,a:z,p:Mb};return{a:Oa}}class Nb{name="ExitStatus";constructor(a){this.message=`Program terminated with exit(${a})`;this.status=a}} +var Ob=a=>{a.terminate();a.onmessage=()=>{}},Pb=[],Sb=a=>{0==P.length&&(Qb(),Rb(P[0]));var b=P.pop();if(!b)return 6;Q.push(b);R[a.Qa]=b;b.Qa=a.Qa;var c={Ra:"run",bb:a.ab,Va:a.Va,Qa:a.Qa};m&&b.unref();b.postMessage(c,a.Xa);return 0},S=0,U=(a,b,...c)=>{for(var d=2*c.length,e=Tb(),g=Ub(8*d),h=g>>>3,p=0;p>>0]=u)}a=Vb(a,0,d,g,b);T(e);return a}; +function Mb(a){if(n)return U(0,1,a);B=a;if(!(0{B=a;if(n)throw Wb(a),"unwind";Mb(a)},P=[],Q=[],Xb=[],R={};function Yb(){for(var a=f.numThreads-1;a--;)Qb();Pb.push(()=>{M++;Zb(()=>Ia())})}var ac=a=>{var b=a.Qa;delete R[b];P.push(a);Q.splice(Q.indexOf(a),1);a.Qa=0;$b(b)};function Da(){Xb.forEach(a=>a())} +var Rb=a=>new Promise(b=>{a.onmessage=g=>{g=g.data;var h=g.Ra;if(g.Ta&&g.Ta!=bc()){var p=R[g.Ta];p?p.postMessage(g,g.Xa):x(`Internal error! Worker sent a message "${h}" to target pthread ${g.Ta}, but that thread no longer exists!`)}else if("checkMailbox"===h)K();else if("spawnThread"===h)Sb(g);else if("cleanupThread"===h)ac(R[g.cb]);else if("loaded"===h)a.loaded=!0,m&&!a.Qa&&a.unref(),b(a);else if("setimmediate"===g.target)a.postMessage(g);else if("callHandler"===h)f[g.Ya](...g.args);else h&&x(`worker sent an unknown command ${h}`)}; +a.onerror=g=>{x(`${"worker sent an error!"} ${g.filename}:${g.lineno}: ${g.message}`);throw g;};m&&(a.on("message",g=>a.onmessage({data:g})),a.on("error",g=>a.onerror(g)));var c=[],d=[],e;for(e of d)f.propertyIsEnumerable(e)&&c.push(e);a.postMessage({Ra:"load",Za:c,fb:z,gb:na})});function Zb(a){n?a():Promise.all(P.map(Rb)).then(a)}function Qb(){var a=new Worker(new URL(import.meta.url),{type:"module",workerData:"em-pthread",name:"em-pthread"});P.push(a)} +var Ba=a=>{F();var b=I()[a+52>>>2>>>0];a=I()[a+56>>>2>>>0];cc(b,b-a);T(b)},dc=[],ec,Fa=(a,b)=>{S=0;var c=dc[a];c||(dc[a]=c=ec.get(a));a=c(b);0>>=0;var d=new gc(a);b>>>=0;c>>>=0;I()[d.Ua+16>>>2>>>0]=0;I()[d.Ua+4>>>2>>>0]=b;I()[d.Ua+8>>>2>>>0]=c;hc=a;ic++;throw hc;}function jc(a,b,c,d){return n?U(2,1,a,b,c,d):Ra(a,b,c,d)} +function Ra(a,b,c,d){a>>>=0;b>>>=0;c>>>=0;d>>>=0;if("undefined"==typeof SharedArrayBuffer)return 6;var e=[];if(n&&0===e.length)return jc(a,b,c,d);a={ab:c,Qa:a,Va:d,Xa:e};return n?(a.Ra="spawnThread",postMessage(a,e),0):Sb(a)} +var kc="undefined"!=typeof TextDecoder?new TextDecoder:void 0,lc=(a,b=0,c=NaN)=>{b>>>=0;var d=b+c;for(c=b;a[c]&&!(c>=d);)++c;if(16e?d+=String.fromCharCode(e):(e-=65536,d+=String.fromCharCode(55296|e>>10,56320| +e&1023))}}else d+=String.fromCharCode(e)}return d},mc=(a,b)=>(a>>>=0)?lc(G(),a,b):"";function Sa(a,b,c){return n?U(3,1,a,b,c):0}function Ta(a,b){if(n)return U(4,1,a,b)}function Ua(a,b){if(n)return U(5,1,a,b)}function Va(a,b,c){if(n)return U(6,1,a,b,c)}function Wa(a,b,c){return n?U(7,1,a,b,c):0}function Xa(a,b){if(n)return U(8,1,a,b)}function Ya(a,b,c){if(n)return U(9,1,a,b,c)}function Za(a,b,c,d){if(n)return U(10,1,a,b,c,d)}function $a(a,b,c,d){if(n)return U(11,1,a,b,c,d)} +function ab(a,b,c,d){if(n)return U(12,1,a,b,c,d)}function bb(a){if(n)return U(13,1,a)}function cb(a,b){if(n)return U(14,1,a,b)}function db(a,b,c){if(n)return U(15,1,a,b,c)}var eb=()=>O("");function fb(a){Ca(a>>>0,!l,1,!ca,131072,!1);Da()}var nc=a=>{if(!A)try{if(a(),!(0>>=0;"function"===typeof Atomics.eb&&(Atomics.eb(H(),a>>>2,a).value.then(K),a+=128,Atomics.store(H(),a>>>2,1))}var K=()=>{var a=bc();a&&(Ea(a),nc(oc))};function gb(a,b){a>>>=0;a==b>>>0?setTimeout(K):n?postMessage({Ta:a,Ra:"checkMailbox"}):(a=R[a])&&a.postMessage({Ra:"checkMailbox"})}var pc=[];function hb(a,b,c,d,e){b>>>=0;d/=2;pc.length=d;c=e>>>0>>>3;for(e=0;e>>0];return(b?qc[b]:rc[a])(...pc)}var ib=()=>{S=0}; +function jb(a){a>>>=0;n?postMessage({Ra:"cleanupThread",cb:a}):ac(R[a])}function kb(a){m&&R[a>>>0].ref()} +function lb(a,b){a=-9007199254740992>a||9007199254740992>>=0;a=new Date(1E3*a);H()[b>>>2>>>0]=a.getUTCSeconds();H()[b+4>>>2>>>0]=a.getUTCMinutes();H()[b+8>>>2>>>0]=a.getUTCHours();H()[b+12>>>2>>>0]=a.getUTCDate();H()[b+16>>>2>>>0]=a.getUTCMonth();H()[b+20>>>2>>>0]=a.getUTCFullYear()-1900;H()[b+24>>>2>>>0]=a.getUTCDay();a=(a.getTime()-Date.UTC(a.getUTCFullYear(),0,1,0,0,0,0))/864E5|0;H()[b+28>>>2>>>0]=a} +var sc=a=>0===a%4&&(0!==a%100||0===a%400),tc=[0,31,60,91,121,152,182,213,244,274,305,335],uc=[0,31,59,90,120,151,181,212,243,273,304,334]; +function mb(a,b){a=-9007199254740992>a||9007199254740992>>=0;a=new Date(1E3*a);H()[b>>>2>>>0]=a.getSeconds();H()[b+4>>>2>>>0]=a.getMinutes();H()[b+8>>>2>>>0]=a.getHours();H()[b+12>>>2>>>0]=a.getDate();H()[b+16>>>2>>>0]=a.getMonth();H()[b+20>>>2>>>0]=a.getFullYear()-1900;H()[b+24>>>2>>>0]=a.getDay();var c=(sc(a.getFullYear())?tc:uc)[a.getMonth()]+a.getDate()-1|0;H()[b+28>>>2>>>0]=c;H()[b+36>>>2>>>0]=-(60*a.getTimezoneOffset());c=(new Date(a.getFullYear(),6,1)).getTimezoneOffset(); +var d=(new Date(a.getFullYear(),0,1)).getTimezoneOffset();a=(c!=d&&a.getTimezoneOffset()==Math.min(d,c))|0;H()[b+32>>>2>>>0]=a} +function nb(a){a>>>=0;var b=new Date(H()[a+20>>>2>>>0]+1900,H()[a+16>>>2>>>0],H()[a+12>>>2>>>0],H()[a+8>>>2>>>0],H()[a+4>>>2>>>0],H()[a>>>2>>>0],0),c=H()[a+32>>>2>>>0],d=b.getTimezoneOffset(),e=(new Date(b.getFullYear(),6,1)).getTimezoneOffset(),g=(new Date(b.getFullYear(),0,1)).getTimezoneOffset(),h=Math.min(g,e);0>c?H()[a+32>>>2>>>0]=Number(e!=g&&h==d):0>>2>>>0]=b.getDay();c=(sc(b.getFullYear())?tc:uc)[b.getMonth()]+ +b.getDate()-1|0;H()[a+28>>>2>>>0]=c;H()[a>>>2>>>0]=b.getSeconds();H()[a+4>>>2>>>0]=b.getMinutes();H()[a+8>>>2>>>0]=b.getHours();H()[a+12>>>2>>>0]=b.getDate();H()[a+16>>>2>>>0]=b.getMonth();H()[a+20>>>2>>>0]=b.getYear();a=b.getTime();return BigInt(isNaN(a)?-1:a/1E3)}function ob(a,b,c,d,e,g,h){return n?U(16,1,a,b,c,d,e,g,h):-52}function pb(a,b,c,d,e,g){if(n)return U(17,1,a,b,c,d,e,g)}var V={},zb=()=>performance.timeOrigin+performance.now(); +function qb(a,b){if(n)return U(18,1,a,b);V[a]&&(clearTimeout(V[a].id),delete V[a]);if(!b)return 0;var c=setTimeout(()=>{delete V[a];nc(()=>vc(a,performance.timeOrigin+performance.now()))},b);V[a]={id:c,lb:b};return 0} +var W=(a,b,c)=>{var d=G();b>>>=0;if(0=h){var p=a.charCodeAt(++g);h=65536+((h&1023)<<10)|p&1023}if(127>=h){if(b>=c)break;d[b++>>>0]=h}else{if(2047>=h){if(b+1>=c)break;d[b++>>>0]=192|h>>6}else{if(65535>=h){if(b+2>=c)break;d[b++>>>0]=224|h>>12}else{if(b+3>=c)break;d[b++>>>0]=240|h>>18;d[b++>>>0]=128|h>>12&63}d[b++>>>0]=128|h>>6&63}d[b++>>>0]=128|h&63}}d[b>>>0]=0;a=b-e}else a=0;return a}; +function rb(a,b,c,d){a>>>=0;b>>>=0;c>>>=0;d>>>=0;var e=(new Date).getFullYear(),g=(new Date(e,0,1)).getTimezoneOffset();e=(new Date(e,6,1)).getTimezoneOffset();var h=Math.max(g,e);I()[a>>>2>>>0]=60*h;H()[b>>>2>>>0]=Number(g!=e);b=p=>{var u=Math.abs(p);return`UTC${0<=p?"-":"+"}${String(Math.floor(u/60)).padStart(2,"0")}${String(u%60).padStart(2,"0")}`};a=b(g);b=b(e);eDate.now(),wc=1; +function sb(a,b,c){if(!(0<=a&&3>=a))return 28;if(0===a)a=Date.now();else if(wc)a=performance.timeOrigin+performance.now();else return 52;D[c>>>0>>>3]=BigInt(Math.round(1E6*a));return 0}var xc=[];function tb(a,b,c){a>>>=0;b>>>=0;c>>>=0;xc.length=0;for(var d;d=G()[b++>>>0];){var e=105!=d;e&=112!=d;c+=e&&c%8?4:0;xc.push(112==d?I()[c>>>2>>>0]:106==d?D[c>>>3]:105==d?H()[c>>>2>>>0]:J()[c>>>3>>>0]);c+=e?8:4}return qc[a](...xc)}var ub=()=>{};function wb(a,b){return x(mc(a>>>0,b>>>0))} +var xb=()=>{S+=1;throw"unwind";};function yb(){return 4294901760}var Ab=()=>m?require("os").cpus().length:navigator.hardwareConcurrency;function Bb(){O("Cannot use emscripten_pc_get_function without -sUSE_OFFSET_CONVERTER");return 0} +function Cb(a){a>>>=0;var b=G().length;if(a<=b||4294901760=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);a:{d=(Math.min(4294901760,65536*Math.ceil(Math.max(a,d)/65536))-z.buffer.byteLength+65535)/65536|0;try{z.grow(d);F();var e=1;break a}catch(g){}e=void 0}if(e)return!0}return!1}var X=()=>{O("Cannot use convertFrameToPC (needed by __builtin_return_address) without -sUSE_OFFSET_CONVERTER");return 0},Z={},yc=a=>{a.forEach(b=>{var c=X();c&&(Z[c]=b)})}; +function Db(){var a=Error().stack.toString().split("\n");"Error"==a[0]&&a.shift();yc(a);Z.Wa=X();Z.$a=a;return Z.Wa}function Eb(a,b,c){a>>>=0;b>>>=0;if(Z.Wa==a)var d=Z.$a;else d=Error().stack.toString().split("\n"),"Error"==d[0]&&d.shift(),yc(d);for(var e=3;d[e]&&X()!=a;)++e;for(a=0;a>>2>>>0]=X();return a} +var zc={},Bc=()=>{if(!Ac){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:da||"./this.program"},b;for(b in zc)void 0===zc[b]?delete a[b]:a[b]=zc[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);Ac=c}return Ac},Ac; +function Fb(a,b){if(n)return U(19,1,a,b);a>>>=0;b>>>=0;var c=0,d=0,e;for(e of Bc()){var g=b+c;I()[a+d>>>2>>>0]=g;c+=W(e,g,Infinity)+1;d+=4}return 0}var Cc=a=>{for(var b=0,c=0;c=d?b++:2047>=d?b+=2:55296<=d&&57343>=d?(b+=4,++c):b+=3}return b};function Gb(a,b){if(n)return U(20,1,a,b);a>>>=0;b>>>=0;var c=Bc();I()[a>>>2>>>0]=c.length;a=0;for(var d of c)a+=Cc(d)+1;I()[b>>>2>>>0]=a;return 0}function Ib(a){return n?U(21,1,a):52} +function Jb(a,b,c,d){return n?U(22,1,a,b,c,d):52}function Kb(a,b,c,d){return n?U(23,1,a,b,c,d):70}var Dc=[null,[],[]];function Lb(a,b,c,d){if(n)return U(24,1,a,b,c,d);b>>>=0;c>>>=0;d>>>=0;for(var e=0,g=0;g>>2>>>0],p=I()[b+4>>>2>>>0];b+=8;for(var u=0;u>>0],va=Dc[Y];0===ua||10===ua?((1===Y?ma:x)(lc(va)),va.length=0):va.push(ua)}e+=p}I()[d>>>2>>>0]=e;return 0}n||Yb();n||(z=new WebAssembly.Memory({initial:256,maximum:65536,shared:!0}),F()); +f.wasmBinary&&(y=f.wasmBinary);f.stackSave=()=>Tb();f.stackRestore=a=>T(a);f.stackAlloc=a=>Ub(a);f.setValue=function(a,b,c="i8"){c.endsWith("*")&&(c="*");switch(c){case "i1":E()[a>>>0]=b;break;case "i8":E()[a>>>0]=b;break;case "i16":wa()[a>>>1>>>0]=b;break;case "i32":H()[a>>>2>>>0]=b;break;case "i64":D[a>>>3]=BigInt(b);break;case "float":xa()[a>>>2>>>0]=b;break;case "double":J()[a>>>3>>>0]=b;break;case "*":I()[a>>>2>>>0]=b;break;default:O(`invalid type for setValue: ${c}`)}}; +f.getValue=function(a,b="i8"){b.endsWith("*")&&(b="*");switch(b){case "i1":return E()[a>>>0];case "i8":return E()[a>>>0];case "i16":return wa()[a>>>1>>>0];case "i32":return H()[a>>>2>>>0];case "i64":return D[a>>>3];case "float":return xa()[a>>>2>>>0];case "double":return J()[a>>>3>>>0];case "*":return I()[a>>>2>>>0];default:O(`invalid type for getValue: ${b}`)}};f.UTF8ToString=mc;f.stringToUTF8=W;f.lengthBytesUTF8=Cc; +var rc=[Mb,Wb,jc,Sa,Ta,Ua,Va,Wa,Xa,Ya,Za,$a,ab,bb,cb,db,ob,pb,qb,Fb,Gb,Ib,Jb,Kb,Lb],qc={851916:(a,b,c,d,e)=>{if("undefined"==typeof f||!f.Sa)return 1;a=mc(Number(a>>>0));a.startsWith("./")&&(a=a.substring(2));a=f.Sa.get(a);if(!a)return 2;b=Number(b>>>0);c=Number(c>>>0);d=Number(d>>>0);if(b+c>a.byteLength)return 3;try{const g=a.subarray(b,b+c);switch(e){case 0:G().set(g,d>>>0);break;case 1:f.hb?f.hb(d,g):f.jb(d,g);break;default:return 4}return 0}catch{return 4}},852740:()=>"undefined"!==typeof wasmOffsetConverter}; +function Pa(){return"undefined"!==typeof wasmOffsetConverter} +var Oa,L=await (async function(){function a(d,e){L=d.exports;L=Ec();Xb.push(L.Da);ec=L.Ea;na=e;Ia();return L}M++;var b=Na();if(f.instantiateWasm)return new Promise(d=>{f.instantiateWasm(b,(e,g)=>{d(a(e,g))})});if(n)return new Promise(d=>{ya=e=>{var g=new WebAssembly.Instance(e,Na());d(a(g,e))}});Ja??=f.locateFile?f.locateFile?f.locateFile("ort-wasm-simd-threaded.wasm",t):t+"ort-wasm-simd-threaded.wasm":(new URL("ort-wasm-simd-threaded.wasm",import.meta.url)).href;try{var c=await Ma(b); +return a(c.instance,c.module)}catch(d){return aa(d),Promise.reject(d)}}());f._OrtInit=(a,b)=>(f._OrtInit=L.aa)(a,b);f._OrtGetLastError=(a,b)=>(f._OrtGetLastError=L.ba)(a,b);f._OrtCreateSessionOptions=(a,b,c,d,e,g,h,p,u,Y)=>(f._OrtCreateSessionOptions=L.ca)(a,b,c,d,e,g,h,p,u,Y);f._OrtAppendExecutionProvider=(a,b,c,d,e)=>(f._OrtAppendExecutionProvider=L.da)(a,b,c,d,e);f._OrtAddFreeDimensionOverride=(a,b,c)=>(f._OrtAddFreeDimensionOverride=L.ea)(a,b,c); +f._OrtAddSessionConfigEntry=(a,b,c)=>(f._OrtAddSessionConfigEntry=L.fa)(a,b,c);f._OrtReleaseSessionOptions=a=>(f._OrtReleaseSessionOptions=L.ga)(a);f._OrtCreateSession=(a,b,c)=>(f._OrtCreateSession=L.ha)(a,b,c);f._OrtReleaseSession=a=>(f._OrtReleaseSession=L.ia)(a);f._OrtGetInputOutputCount=(a,b,c)=>(f._OrtGetInputOutputCount=L.ja)(a,b,c);f._OrtGetInputOutputMetadata=(a,b,c,d)=>(f._OrtGetInputOutputMetadata=L.ka)(a,b,c,d);f._OrtFree=a=>(f._OrtFree=L.la)(a); +f._OrtCreateTensor=(a,b,c,d,e,g)=>(f._OrtCreateTensor=L.ma)(a,b,c,d,e,g);f._OrtGetTensorData=(a,b,c,d,e)=>(f._OrtGetTensorData=L.na)(a,b,c,d,e);f._OrtReleaseTensor=a=>(f._OrtReleaseTensor=L.oa)(a);f._OrtCreateRunOptions=(a,b,c,d)=>(f._OrtCreateRunOptions=L.pa)(a,b,c,d);f._OrtAddRunConfigEntry=(a,b,c)=>(f._OrtAddRunConfigEntry=L.qa)(a,b,c);f._OrtReleaseRunOptions=a=>(f._OrtReleaseRunOptions=L.ra)(a);f._OrtCreateBinding=a=>(f._OrtCreateBinding=L.sa)(a); +f._OrtBindInput=(a,b,c)=>(f._OrtBindInput=L.ta)(a,b,c);f._OrtBindOutput=(a,b,c,d)=>(f._OrtBindOutput=L.ua)(a,b,c,d);f._OrtClearBoundOutputs=a=>(f._OrtClearBoundOutputs=L.va)(a);f._OrtReleaseBinding=a=>(f._OrtReleaseBinding=L.wa)(a);f._OrtRunWithBinding=(a,b,c,d,e)=>(f._OrtRunWithBinding=L.xa)(a,b,c,d,e);f._OrtRun=(a,b,c,d,e,g,h,p)=>(f._OrtRun=L.ya)(a,b,c,d,e,g,h,p);f._OrtEndProfiling=a=>(f._OrtEndProfiling=L.za)(a);var bc=()=>(bc=L.Aa)();f._free=a=>(f._free=L.Ba)(a);f._malloc=a=>(f._malloc=L.Ca)(a); +var Ca=(a,b,c,d,e,g)=>(Ca=L.Fa)(a,b,c,d,e,g),Ga=()=>(Ga=L.Ga)(),Vb=(a,b,c,d,e)=>(Vb=L.Ha)(a,b,c,d,e),$b=a=>($b=L.Ia)(a),fc=a=>(fc=L.Ja)(a),vc=(a,b)=>(vc=L.Ka)(a,b),oc=()=>(oc=L.La)(),cc=(a,b)=>(cc=L.Ma)(a,b),T=a=>(T=L.Na)(a),Ub=a=>(Ub=L.Oa)(a),Tb=()=>(Tb=L.Pa)();function Ec(){var a=L;a=Object.assign({},a);var b=d=>()=>d()>>>0,c=d=>e=>d(e)>>>0;a.Aa=b(a.Aa);a.Ca=c(a.Ca);a.Oa=c(a.Oa);a.Pa=b(a.Pa);a.__cxa_get_exception_ptr=c(a.__cxa_get_exception_ptr);return a} +function Fc(){if(0{var Je=Object.defineProperty;var Bn=Object.getOwnPropertyDescriptor;var On=Object.getOwnPropertyNames;var Ln=Object.prototype.hasOwnProperty;var Ye=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var E=(e,t)=>()=>(e&&(t=e(e=0)),t);var Ee=(e,t)=>{for(var n in t)Je(e,n,{get:t[n],enumerable:!0})},Pn=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of On(t))!Ln.call(e,r)&&r!==n&&Je(e,r,{get:()=>t[r],enumerable:!(o=Bn(t,r))||o.enumerable});return e};var qe=e=>Pn(Je({},"__esModule",{value:!0}),e);var Te,K,se,Dn,ht,Ze=E(()=>{"use strict";Te=new Map,K=[],se=(e,t,n)=>{if(t&&typeof t.init=="function"&&typeof t.createInferenceSessionHandler=="function"){let o=Te.get(e);if(o===void 0)Te.set(e,{backend:t,priority:n});else{if(o.priority>n)return;if(o.priority===n&&o.backend!==t)throw new Error(`cannot register backend "${e}" using priority ${n}`)}if(n>=0){let r=K.indexOf(e);r!==-1&&K.splice(r,1);for(let a=0;a{let t=Te.get(e);if(!t)return"backend not found.";if(t.initialized)return t.backend;if(t.aborted)return t.error;{let n=!!t.initPromise;try{return n||(t.initPromise=t.backend.init(e)),await t.initPromise,t.initialized=!0,t.backend}catch(o){return n||(t.error=`${o}`,t.aborted=!0),t.error}finally{delete t.initPromise}}},ht=async e=>{let t=e.executionProviders||[],n=t.map(u=>typeof u=="string"?u:u.name),o=n.length===0?K:n,r,a=[],i=new Set;for(let u of o){let f=await Dn(u);typeof f=="string"?a.push({name:u,err:f}):(r||(r=f),r===f&&i.add(u))}if(!r)throw new Error(`no available backend found. ERR: ${a.map(u=>`[${u.name}] ${u.err}`).join(", ")}`);for(let{name:u,err:f}of a)n.includes(u)&&console.warn(`removing requested execution provider "${u}" from session options because it is not available: ${f}`);let s=t.filter(u=>i.has(typeof u=="string"?u:u.name));return[r,new Proxy(e,{get:(u,f)=>f==="executionProviders"?s:Reflect.get(u,f)})]}});var yt=E(()=>{"use strict";Ze()});var bt,gt=E(()=>{"use strict";bt="1.23.0"});var Et,D,Xe=E(()=>{"use strict";gt();Et="warning",D={wasm:{},webgl:{},webgpu:{},versions:{common:bt},set logLevel(e){if(e!==void 0){if(typeof e!="string"||["verbose","info","warning","error","fatal"].indexOf(e)===-1)throw new Error(`Unsupported logging level: ${e}`);Et=e}},get logLevel(){return Et}};Object.defineProperty(D,"logLevel",{enumerable:!0})});var A,Tt=E(()=>{"use strict";Xe();A=D});var St,It,At=E(()=>{"use strict";St=(e,t)=>{let n=typeof document<"u"?document.createElement("canvas"):new OffscreenCanvas(1,1);n.width=e.dims[3],n.height=e.dims[2];let o=n.getContext("2d");if(o!=null){let r,a;t?.tensorLayout!==void 0&&t.tensorLayout==="NHWC"?(r=e.dims[2],a=e.dims[3]):(r=e.dims[3],a=e.dims[2]);let i=t?.format!==void 0?t.format:"RGB",s=t?.norm,u,f;s===void 0||s.mean===void 0?u=[255,255,255,255]:typeof s.mean=="number"?u=[s.mean,s.mean,s.mean,s.mean]:(u=[s.mean[0],s.mean[1],s.mean[2],0],s.mean[3]!==void 0&&(u[3]=s.mean[3])),s===void 0||s.bias===void 0?f=[0,0,0,0]:typeof s.bias=="number"?f=[s.bias,s.bias,s.bias,s.bias]:(f=[s.bias[0],s.bias[1],s.bias[2],0],s.bias[3]!==void 0&&(f[3]=s.bias[3]));let c=a*r,l=0,d=c,p=c*2,w=-1;i==="RGBA"?(l=0,d=c,p=c*2,w=c*3):i==="RGB"?(l=0,d=c,p=c*2):i==="RBG"&&(l=0,p=c,d=c*2);for(let b=0;b{let n=typeof document<"u"?document.createElement("canvas").getContext("2d"):new OffscreenCanvas(1,1).getContext("2d"),o;if(n!=null){let r,a,i;t?.tensorLayout!==void 0&&t.tensorLayout==="NHWC"?(r=e.dims[2],a=e.dims[1],i=e.dims[3]):(r=e.dims[3],a=e.dims[2],i=e.dims[1]);let s=t!==void 0&&t.format!==void 0?t.format:"RGB",u=t?.norm,f,c;u===void 0||u.mean===void 0?f=[255,255,255,255]:typeof u.mean=="number"?f=[u.mean,u.mean,u.mean,u.mean]:(f=[u.mean[0],u.mean[1],u.mean[2],255],u.mean[3]!==void 0&&(f[3]=u.mean[3])),u===void 0||u.bias===void 0?c=[0,0,0,0]:typeof u.bias=="number"?c=[u.bias,u.bias,u.bias,u.bias]:(c=[u.bias[0],u.bias[1],u.bias[2],0],u.bias[3]!==void 0&&(c[3]=u.bias[3]));let l=a*r;if(t!==void 0&&(t.format!==void 0&&i===4&&t.format!=="RGBA"||i===3&&t.format!=="RGB"&&t.format!=="BGR"))throw new Error("Tensor format doesn't match input tensor dims");let d=4,p=0,w=1,b=2,B=3,m=0,h=l,O=l*2,g=-1;s==="RGBA"?(m=0,h=l,O=l*2,g=l*3):s==="RGB"?(m=0,h=l,O=l*2):s==="RBG"&&(m=0,O=l,h=l*2),o=n.createImageData(r,a);for(let S=0;S{"use strict";Se();Ke=(e,t)=>{if(e===void 0)throw new Error("Image buffer must be defined");if(t.height===void 0||t.width===void 0)throw new Error("Image height and width must be defined");if(t.tensorLayout==="NHWC")throw new Error("NHWC Tensor layout is not supported yet");let{height:n,width:o}=t,r=t.norm??{mean:255,bias:0},a,i;typeof r.mean=="number"?a=[r.mean,r.mean,r.mean,r.mean]:a=[r.mean[0],r.mean[1],r.mean[2],r.mean[3]??255],typeof r.bias=="number"?i=[r.bias,r.bias,r.bias,r.bias]:i=[r.bias[0],r.bias[1],r.bias[2],r.bias[3]??0];let s=t.format!==void 0?t.format:"RGBA",u=t.tensorFormat!==void 0&&t.tensorFormat!==void 0?t.tensorFormat:"RGB",f=n*o,c=u==="RGBA"?new Float32Array(f*4):new Float32Array(f*3),l=4,d=0,p=1,w=2,b=3,B=0,m=f,h=f*2,O=-1;s==="RGB"&&(l=3,d=0,p=1,w=2,b=-1),u==="RGBA"?O=f*3:u==="RBG"?(B=0,h=f,m=f*2):u==="BGR"&&(h=0,m=f,B=f*2);for(let S=0;S{let n=typeof HTMLImageElement<"u"&&e instanceof HTMLImageElement,o=typeof ImageData<"u"&&e instanceof ImageData,r=typeof ImageBitmap<"u"&&e instanceof ImageBitmap,a=typeof e=="string",i,s=t??{},u=()=>{if(typeof document<"u")return document.createElement("canvas");if(typeof OffscreenCanvas<"u")return new OffscreenCanvas(1,1);throw new Error("Canvas is not supported")},f=c=>typeof HTMLCanvasElement<"u"&&c instanceof HTMLCanvasElement||c instanceof OffscreenCanvas?c.getContext("2d"):null;if(n){let c=u();c.width=e.width,c.height=e.height;let l=f(c);if(l!=null){let d=e.height,p=e.width;if(t!==void 0&&t.resizedHeight!==void 0&&t.resizedWidth!==void 0&&(d=t.resizedHeight,p=t.resizedWidth),t!==void 0){if(s=t,t.tensorFormat!==void 0)throw new Error("Image input config format must be RGBA for HTMLImageElement");s.tensorFormat="RGBA",s.height=d,s.width=p}else s.tensorFormat="RGBA",s.height=d,s.width=p;l.drawImage(e,0,0),i=l.getImageData(0,0,p,d).data}else throw new Error("Can not access image data")}else if(o){let c,l;if(t!==void 0&&t.resizedWidth!==void 0&&t.resizedHeight!==void 0?(c=t.resizedHeight,l=t.resizedWidth):(c=e.height,l=e.width),t!==void 0&&(s=t),s.format="RGBA",s.height=c,s.width=l,t!==void 0){let d=u();d.width=l,d.height=c;let p=f(d);if(p!=null)p.putImageData(e,0,0),i=p.getImageData(0,0,l,c).data;else throw new Error("Can not access image data")}else i=e.data}else if(r){if(t===void 0)throw new Error("Please provide image config with format for Imagebitmap");let c=u();c.width=e.width,c.height=e.height;let l=f(c);if(l!=null){let d=e.height,p=e.width;return l.drawImage(e,0,0,p,d),i=l.getImageData(0,0,p,d).data,s.height=d,s.width=p,Ke(i,s)}else throw new Error("Can not access image data")}else{if(a)return new Promise((c,l)=>{let d=u(),p=f(d);if(!e||!p)return l();let w=new Image;w.crossOrigin="Anonymous",w.src=e,w.onload=()=>{d.width=w.width,d.height=w.height,p.drawImage(w,0,0,d.width,d.height);let b=p.getImageData(0,0,d.width,d.height);s.height=d.height,s.width=d.width,c(Ke(b.data,s))}});throw new Error("Input data provided is not supported - aborted tensor creation")}if(i!==void 0)return Ke(i,s);throw new Error("Input data provided is not supported - aborted tensor creation")},Ot=(e,t)=>{let{width:n,height:o,download:r,dispose:a}=t,i=[1,o,n,4];return new x({location:"texture",type:"float32",texture:e,dims:i,download:r,dispose:a})},Lt=(e,t)=>{let{dataType:n,dims:o,download:r,dispose:a}=t;return new x({location:"gpu-buffer",type:n??"float32",gpuBuffer:e,dims:o,download:r,dispose:a})},Pt=(e,t)=>{let{dataType:n,dims:o,download:r,dispose:a}=t;return new x({location:"ml-tensor",type:n??"float32",mlTensor:e,dims:o,download:r,dispose:a})},Dt=(e,t,n)=>new x({location:"cpu-pinned",type:e,data:t,dims:n??[t.length]})});var Q,pe,_t,xt,vt=E(()=>{"use strict";Q=new Map([["float32",Float32Array],["uint8",Uint8Array],["int8",Int8Array],["uint16",Uint16Array],["int16",Int16Array],["int32",Int32Array],["bool",Uint8Array],["float64",Float64Array],["uint32",Uint32Array],["int4",Uint8Array],["uint4",Uint8Array]]),pe=new Map([[Float32Array,"float32"],[Uint8Array,"uint8"],[Int8Array,"int8"],[Uint16Array,"uint16"],[Int16Array,"int16"],[Int32Array,"int32"],[Float64Array,"float64"],[Uint32Array,"uint32"]]),_t=!1,xt=()=>{if(!_t){_t=!0;let e=typeof BigInt64Array<"u"&&BigInt64Array.from,t=typeof BigUint64Array<"u"&&BigUint64Array.from,n=globalThis.Float16Array,o=typeof n<"u"&&n.from;e&&(Q.set("int64",BigInt64Array),pe.set(BigInt64Array,"int64")),t&&(Q.set("uint64",BigUint64Array),pe.set(BigUint64Array,"uint64")),o?(Q.set("float16",n),pe.set(n,"float16")):Q.set("float16",Uint16Array)}}});var Ct,Mt,Rt=E(()=>{"use strict";Se();Ct=e=>{let t=1;for(let n=0;n{switch(e.location){case"cpu":return new x(e.type,e.data,t);case"cpu-pinned":return new x({location:"cpu-pinned",data:e.data,type:e.type,dims:t});case"texture":return new x({location:"texture",texture:e.texture,type:e.type,dims:t});case"gpu-buffer":return new x({location:"gpu-buffer",gpuBuffer:e.gpuBuffer,type:e.type,dims:t});case"ml-tensor":return new x({location:"ml-tensor",mlTensor:e.mlTensor,type:e.type,dims:t});default:throw new Error(`tensorReshape: tensor location ${e.location} is not supported`)}}});var x,Se=E(()=>{"use strict";At();Ut();vt();Rt();x=class{constructor(t,n,o){xt();let r,a;if(typeof t=="object"&&"location"in t)switch(this.dataLocation=t.location,r=t.type,a=t.dims,t.location){case"cpu-pinned":{let s=Q.get(r);if(!s)throw new TypeError(`unsupported type "${r}" to create tensor from pinned buffer`);if(!(t.data instanceof s))throw new TypeError(`buffer should be of type ${s.name}`);this.cpuData=t.data;break}case"texture":{if(r!=="float32")throw new TypeError(`unsupported type "${r}" to create tensor from texture`);this.gpuTextureData=t.texture,this.downloader=t.download,this.disposer=t.dispose;break}case"gpu-buffer":{if(r!=="float32"&&r!=="float16"&&r!=="int32"&&r!=="int64"&&r!=="uint32"&&r!=="uint8"&&r!=="bool"&&r!=="uint4"&&r!=="int4")throw new TypeError(`unsupported type "${r}" to create tensor from gpu buffer`);this.gpuBufferData=t.gpuBuffer,this.downloader=t.download,this.disposer=t.dispose;break}case"ml-tensor":{if(r!=="float32"&&r!=="float16"&&r!=="int32"&&r!=="int64"&&r!=="uint32"&&r!=="uint64"&&r!=="int8"&&r!=="uint8"&&r!=="bool"&&r!=="uint4"&&r!=="int4")throw new TypeError(`unsupported type "${r}" to create tensor from MLTensor`);this.mlTensorData=t.mlTensor,this.downloader=t.download,this.disposer=t.dispose;break}default:throw new Error(`Tensor constructor: unsupported location '${this.dataLocation}'`)}else{let s,u;if(typeof t=="string")if(r=t,u=o,t==="string"){if(!Array.isArray(n))throw new TypeError("A string tensor's data must be a string array.");s=n}else{let f=Q.get(t);if(f===void 0)throw new TypeError(`Unsupported tensor type: ${t}.`);if(Array.isArray(n)){if(t==="float16"&&f===Uint16Array||t==="uint4"||t==="int4")throw new TypeError(`Creating a ${t} tensor from number array is not supported. Please use ${f.name} as data.`);t==="uint64"||t==="int64"?s=f.from(n,BigInt):s=f.from(n)}else if(n instanceof f)s=n;else if(n instanceof Uint8ClampedArray)if(t==="uint8")s=Uint8Array.from(n);else throw new TypeError("A Uint8ClampedArray tensor's data must be type of uint8");else if(t==="float16"&&n instanceof Uint16Array&&f!==Uint16Array)s=new globalThis.Float16Array(n.buffer,n.byteOffset,n.length);else throw new TypeError(`A ${r} tensor's data must be type of ${f}`)}else if(u=n,Array.isArray(t)){if(t.length===0)throw new TypeError("Tensor type cannot be inferred from an empty array.");let f=typeof t[0];if(f==="string")r="string",s=t;else if(f==="boolean")r="bool",s=Uint8Array.from(t);else throw new TypeError(`Invalid element type of data array: ${f}.`)}else if(t instanceof Uint8ClampedArray)r="uint8",s=Uint8Array.from(t);else{let f=pe.get(t.constructor);if(f===void 0)throw new TypeError(`Unsupported type for tensor data: ${t.constructor}.`);r=f,s=t}if(u===void 0)u=[s.length];else if(!Array.isArray(u))throw new TypeError("A tensor's dims must be a number array");a=u,this.cpuData=s,this.dataLocation="cpu"}let i=Ct(a);if(this.cpuData&&i!==this.cpuData.length&&!((r==="uint4"||r==="int4")&&Math.ceil(i/2)===this.cpuData.length))throw new Error(`Tensor's size(${i}) does not match data length(${this.cpuData.length}).`);this.type=r,this.dims=a,this.size=i}static async fromImage(t,n){return Bt(t,n)}static fromTexture(t,n){return Ot(t,n)}static fromGpuBuffer(t,n){return Lt(t,n)}static fromMLTensor(t,n){return Pt(t,n)}static fromPinnedBuffer(t,n,o){return Dt(t,n,o)}toDataURL(t){return St(this,t)}toImageData(t){return It(this,t)}get data(){if(this.ensureValid(),!this.cpuData)throw new Error("The data is not on CPU. Use `getData()` to download GPU data to CPU, or use `texture` or `gpuBuffer` property to access the GPU data directly.");return this.cpuData}get location(){return this.dataLocation}get texture(){if(this.ensureValid(),!this.gpuTextureData)throw new Error("The data is not stored as a WebGL texture.");return this.gpuTextureData}get gpuBuffer(){if(this.ensureValid(),!this.gpuBufferData)throw new Error("The data is not stored as a WebGPU buffer.");return this.gpuBufferData}get mlTensor(){if(this.ensureValid(),!this.mlTensorData)throw new Error("The data is not stored as a WebNN MLTensor.");return this.mlTensorData}async getData(t){switch(this.ensureValid(),this.dataLocation){case"cpu":case"cpu-pinned":return this.data;case"texture":case"gpu-buffer":case"ml-tensor":{if(!this.downloader)throw new Error("The current tensor is not created with a specified data downloader.");if(this.isDownloading)throw new Error("The current tensor is being downloaded.");try{this.isDownloading=!0;let n=await this.downloader();return this.downloader=void 0,this.dataLocation="cpu",this.cpuData=n,t&&this.disposer&&(this.disposer(),this.disposer=void 0),n}finally{this.isDownloading=!1}}default:throw new Error(`cannot get data from location: ${this.dataLocation}`)}}dispose(){if(this.isDownloading)throw new Error("The current tensor is being downloaded.");this.disposer&&(this.disposer(),this.disposer=void 0),this.cpuData=void 0,this.gpuTextureData=void 0,this.gpuBufferData=void 0,this.mlTensorData=void 0,this.downloader=void 0,this.isDownloading=void 0,this.dataLocation="none"}ensureValid(){if(this.dataLocation==="none")throw new Error("The tensor is disposed.")}reshape(t){if(this.ensureValid(),this.downloader||this.disposer)throw new Error("Cannot reshape a tensor that owns GPU resource.");return Mt(this,t)}}});var k,Qe=E(()=>{"use strict";Se();k=x});var et,Ft,J,Y,q,Z,tt=E(()=>{"use strict";Xe();et=(e,t)=>{(typeof D.trace>"u"?!D.wasm.trace:!D.trace)||console.timeStamp(`${e}::ORT::${t}`)},Ft=(e,t)=>{let n=new Error().stack?.split(/\r\n|\r|\n/g)||[],o=!1;for(let r=0;r{(typeof D.trace>"u"?!D.wasm.trace:!D.trace)||Ft("BEGIN",e)},Y=e=>{(typeof D.trace>"u"?!D.wasm.trace:!D.trace)||Ft("END",e)},q=e=>{(typeof D.trace>"u"?!D.wasm.trace:!D.trace)||console.time(`ORT::${e}`)},Z=e=>{(typeof D.trace>"u"?!D.wasm.trace:!D.trace)||console.timeEnd(`ORT::${e}`)}});var Ie,Nt=E(()=>{"use strict";Ze();Qe();tt();Ie=class e{constructor(t){this.handler=t}async run(t,n,o){J(),q("InferenceSession.run");let r={},a={};if(typeof t!="object"||t===null||t instanceof k||Array.isArray(t))throw new TypeError("'feeds' must be an object that use input names as keys and OnnxValue as corresponding values.");let i=!0;if(typeof n=="object"){if(n===null)throw new TypeError("Unexpected argument[1]: cannot be null.");if(n instanceof k)throw new TypeError("'fetches' cannot be a Tensor");if(Array.isArray(n)){if(n.length===0)throw new TypeError("'fetches' cannot be an empty array.");i=!1;for(let f of n){if(typeof f!="string")throw new TypeError("'fetches' must be a string array or an object.");if(this.outputNames.indexOf(f)===-1)throw new RangeError(`'fetches' contains invalid output name: ${f}.`);r[f]=null}if(typeof o=="object"&&o!==null)a=o;else if(typeof o<"u")throw new TypeError("'options' must be an object.")}else{let f=!1,c=Object.getOwnPropertyNames(n);for(let l of this.outputNames)if(c.indexOf(l)!==-1){let d=n[l];(d===null||d instanceof k)&&(f=!0,i=!1,r[l]=d)}if(f){if(typeof o=="object"&&o!==null)a=o;else if(typeof o<"u")throw new TypeError("'options' must be an object.")}else a=n}}else if(typeof n<"u")throw new TypeError("Unexpected argument[1]: must be 'fetches' or 'options'.");for(let f of this.inputNames)if(typeof t[f]>"u")throw new Error(`input '${f}' is missing in 'feeds'.`);if(i)for(let f of this.outputNames)r[f]=null;let s=await this.handler.run(t,r,a),u={};for(let f in s)if(Object.hasOwnProperty.call(s,f)){let c=s[f];c instanceof k?u[f]=c:u[f]=new k(c.type,c.data,c.dims)}return Z("InferenceSession.run"),Y(),u}async release(){return this.handler.dispose()}static async create(t,n,o,r){J(),q("InferenceSession.create");let a,i={};if(typeof t=="string"){if(a=t,typeof n=="object"&&n!==null)i=n;else if(typeof n<"u")throw new TypeError("'options' must be an object.")}else if(t instanceof Uint8Array){if(a=t,typeof n=="object"&&n!==null)i=n;else if(typeof n<"u")throw new TypeError("'options' must be an object.")}else if(t instanceof ArrayBuffer||typeof SharedArrayBuffer<"u"&&t instanceof SharedArrayBuffer){let c=t,l=0,d=t.byteLength;if(typeof n=="object"&&n!==null)i=n;else if(typeof n=="number"){if(l=n,!Number.isSafeInteger(l))throw new RangeError("'byteOffset' must be an integer.");if(l<0||l>=c.byteLength)throw new RangeError(`'byteOffset' is out of range [0, ${c.byteLength}).`);if(d=t.byteLength-l,typeof o=="number"){if(d=o,!Number.isSafeInteger(d))throw new RangeError("'byteLength' must be an integer.");if(d<=0||l+d>c.byteLength)throw new RangeError(`'byteLength' is out of range (0, ${c.byteLength-l}].`);if(typeof r=="object"&&r!==null)i=r;else if(typeof r<"u")throw new TypeError("'options' must be an object.")}else if(typeof o<"u")throw new TypeError("'byteLength' must be a number.")}else if(typeof n<"u")throw new TypeError("'options' must be an object.");a=new Uint8Array(c,l,d)}else throw new TypeError("Unexpected argument[0]: must be 'path' or 'buffer'.");let[s,u]=await ht(i),f=await s.createInferenceSessionHandler(a,u);return Z("InferenceSession.create"),Y(),new e(f)}startProfiling(){this.handler.startProfiling()}endProfiling(){this.handler.endProfiling()}get inputNames(){return this.handler.inputNames}get outputNames(){return this.handler.outputNames}get inputMetadata(){return this.handler.inputMetadata}get outputMetadata(){return this.handler.outputMetadata}}});var kt,Wt=E(()=>{"use strict";Nt();kt=Ie});var Gt=E(()=>{"use strict"});var $t=E(()=>{"use strict"});var zt=E(()=>{"use strict"});var Ht=E(()=>{"use strict"});var nt={};Ee(nt,{InferenceSession:()=>kt,TRACE:()=>et,TRACE_EVENT_BEGIN:()=>q,TRACE_EVENT_END:()=>Z,TRACE_FUNC_BEGIN:()=>J,TRACE_FUNC_END:()=>Y,Tensor:()=>k,env:()=>A,registerBackend:()=>se});var X=E(()=>{"use strict";yt();Tt();Wt();Qe();Gt();$t();tt();zt();Ht()});var Ae=E(()=>{"use strict"});var Yt={};Ee(Yt,{default:()=>Un});var Vt,Jt,Un,qt=E(()=>{"use strict";rt();ee();Be();Vt="ort-wasm-proxy-worker",Jt=globalThis.self?.name===Vt;Jt&&(self.onmessage=e=>{let{type:t,in:n}=e.data;try{switch(t){case"init-wasm":Oe(n.wasm).then(()=>{Le(n).then(()=>{postMessage({type:t})},o=>{postMessage({type:t,err:o})})},o=>{postMessage({type:t,err:o})});break;case"init-ep":{let{epName:o,env:r}=n;Pe(r,o).then(()=>{postMessage({type:t})},a=>{postMessage({type:t,err:a})});break}case"copy-from":{let{buffer:o}=n,r=me(o);postMessage({type:t,out:r});break}case"create":{let{model:o,options:r}=n;De(o,r).then(a=>{postMessage({type:t,out:a})},a=>{postMessage({type:t,err:a})});break}case"release":Ue(n),postMessage({type:t});break;case"run":{let{sessionId:o,inputIndices:r,inputs:a,outputIndices:i,options:s}=n;_e(o,r,a,i,new Array(i.length).fill(null),s).then(u=>{u.some(f=>f[3]!=="cpu")?postMessage({type:t,err:"Proxy does not support non-cpu tensor location."}):postMessage({type:t,out:u},ve([...a,...u]))},u=>{postMessage({type:t,err:u})});break}case"end-profiling":xe(n),postMessage({type:t});break;default:}}catch(o){postMessage({type:t,err:o})}});Un=Jt?null:e=>new Worker(e??R,{type:"classic",name:Vt})});var _n,xn,R,Ce,ot,vn,Cn,Kt,Mn,Zt,Qt,Xt,en,Be=E(()=>{"use strict";Ae();_n=typeof location>"u"?void 0:location.origin,xn=()=>{if(!!1)return typeof document<"u"?document.currentScript?.src:typeof self<"u"?self.location?.href:void 0},R=xn(),Ce=()=>{if(R&&!R.startsWith("blob:"))return R.substring(0,R.lastIndexOf("/")+1)},ot=(e,t)=>{try{let n=t??R;return(n?new URL(e,n):new URL(e)).origin===_n}catch{return!1}},vn=(e,t)=>{let n=t??R;try{return(n?new URL(e,n):new URL(e)).href}catch{return}},Cn=(e,t)=>`${t??"./"}${e}`,Kt=async e=>{let n=await(await fetch(e,{credentials:"same-origin"})).blob();return URL.createObjectURL(n)},Mn=async e=>(await import(/*webpackIgnore:true*/e)).default,Zt=(qt(),qe(Yt)).default,Qt=async()=>{if(!R)throw new Error("Failed to load proxy worker: cannot determine the script source URL.");if(ot(R))return[void 0,Zt()];let e=await Kt(R);return[e,Zt(e)]},Xt=void 0,en=async(e,t,n,o)=>{let r=Xt&&!(e||t);if(r)if(R)r=ot(R);else if(o&&!n)r=!0;else throw new Error("cannot determine the script source URL.");if(r)return[void 0,Xt];{let a="ort-wasm-simd-threaded.mjs",i=e??vn(a,t),s=!!1&&n&&i&&!ot(i,t),u=s?await Kt(i):i??Cn(a,t);return[s?u:void 0,await Mn(u)]}}});var st,it,Me,tn,Rn,Fn,Nn,Oe,I,ee=E(()=>{"use strict";Be();it=!1,Me=!1,tn=!1,Rn=()=>{if(typeof SharedArrayBuffer>"u")return!1;try{return typeof MessageChannel<"u"&&new MessageChannel().port1.postMessage(new SharedArrayBuffer(1)),WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,5,4,1,3,1,1,10,11,1,9,0,65,0,254,16,2,0,26,11]))}catch{return!1}},Fn=()=>{try{return WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,30,1,28,0,65,0,253,15,253,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,253,186,1,26,11]))}catch{return!1}},Nn=()=>{try{return WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,19,1,17,0,65,1,253,15,65,2,253,15,65,3,253,15,253,147,2,11]))}catch{return!1}},Oe=async e=>{if(it)return Promise.resolve();if(Me)throw new Error("multiple calls to 'initializeWebAssembly()' detected.");if(tn)throw new Error("previous call to 'initializeWebAssembly()' failed.");Me=!0;let t=e.initTimeout,n=e.numThreads;if(e.simd!==!1){if(e.simd==="relaxed"){if(!Nn())throw new Error("Relaxed WebAssembly SIMD is not supported in the current environment.")}else if(!Fn())throw new Error("WebAssembly SIMD is not supported in the current environment.")}let o=Rn();n>1&&!o&&(typeof self<"u"&&!self.crossOriginIsolated&&console.warn("env.wasm.numThreads is set to "+n+", but this will not work unless you enable crossOriginIsolated mode. See https://web.dev/cross-origin-isolation-guide/ for more info."),console.warn("WebAssembly multi-threading is not supported in the current environment. Falling back to single-threading."),e.numThreads=n=1);let r=e.wasmPaths,a=typeof r=="string"?r:void 0,i=r?.mjs,s=i?.href??i,u=r?.wasm,f=u?.href??u,c=e.wasmBinary,[l,d]=await en(s,a,n>1,!!c||!!f),p=!1,w=[];if(t>0&&w.push(new Promise(b=>{setTimeout(()=>{p=!0,b()},t)})),w.push(new Promise((b,B)=>{let m={numThreads:n};if(c)m.wasmBinary=c;else if(f||a)m.locateFile=h=>f??a+h;else if(s&&s.indexOf("blob:")!==0)m.locateFile=h=>new URL(h,s).href;else if(l){let h=Ce();h&&(m.locateFile=O=>h+O)}d(m).then(h=>{Me=!1,it=!0,st=h,b(),l&&URL.revokeObjectURL(l)},h=>{Me=!1,tn=!0,B(h)})})),await Promise.race(w),p)throw new Error(`WebAssembly backend initializing failed due to timeout: ${t}ms`)},I=()=>{if(it&&st)return st;throw new Error("WebAssembly is not initialized yet.")}});var F,we,T,Re=E(()=>{"use strict";ee();F=(e,t)=>{let n=I(),o=n.lengthBytesUTF8(e)+1,r=n._malloc(o);return n.stringToUTF8(e,r,o),t.push(r),r},we=(e,t,n,o)=>{if(typeof e=="object"&&e!==null){if(n.has(e))throw new Error("Circular reference in options");n.add(e)}Object.entries(e).forEach(([r,a])=>{let i=t?t+r:r;if(typeof a=="object")we(a,i+".",n,o);else if(typeof a=="string"||typeof a=="number")o(i,a.toString());else if(typeof a=="boolean")o(i,a?"1":"0");else throw new Error(`Can't handle extra config type: ${typeof a}`)})},T=e=>{let t=I(),n=t.stackSave();try{let o=t.PTR_SIZE,r=t.stackAlloc(2*o);t._OrtGetLastError(r,r+o);let a=Number(t.getValue(r,o===4?"i32":"i64")),i=t.getValue(r+o,"*"),s=i?t.UTF8ToString(i):"";throw new Error(`${e} ERROR_CODE: ${a}, ERROR_MESSAGE: ${s}`)}finally{t.stackRestore(n)}}});var nn,rn=E(()=>{"use strict";ee();Re();nn=e=>{let t=I(),n=0,o=[],r=e||{};try{if(e?.logSeverityLevel===void 0)r.logSeverityLevel=2;else if(typeof e.logSeverityLevel!="number"||!Number.isInteger(e.logSeverityLevel)||e.logSeverityLevel<0||e.logSeverityLevel>4)throw new Error(`log severity level is not valid: ${e.logSeverityLevel}`);if(e?.logVerbosityLevel===void 0)r.logVerbosityLevel=0;else if(typeof e.logVerbosityLevel!="number"||!Number.isInteger(e.logVerbosityLevel))throw new Error(`log verbosity level is not valid: ${e.logVerbosityLevel}`);e?.terminate===void 0&&(r.terminate=!1);let a=0;return e?.tag!==void 0&&(a=F(e.tag,o)),n=t._OrtCreateRunOptions(r.logSeverityLevel,r.logVerbosityLevel,!!r.terminate,a),n===0&&T("Can't create run options."),e?.extra!==void 0&&we(e.extra,"",new WeakSet,(i,s)=>{let u=F(i,o),f=F(s,o);t._OrtAddRunConfigEntry(n,u,f)!==0&&T(`Can't set a run config entry: ${i} - ${s}.`)}),[n,o]}catch(a){throw n!==0&&t._OrtReleaseRunOptions(n),o.forEach(i=>t._free(i)),a}}});var kn,Wn,Gn,Fe,$n,on,sn=E(()=>{"use strict";ee();Re();kn=e=>{switch(e){case"disabled":return 0;case"basic":return 1;case"extended":return 2;case"layout":return 3;case"all":return 99;default:throw new Error(`unsupported graph optimization level: ${e}`)}},Wn=e=>{switch(e){case"sequential":return 0;case"parallel":return 1;default:throw new Error(`unsupported execution mode: ${e}`)}},Gn=e=>{e.extra||(e.extra={}),e.extra.session||(e.extra.session={});let t=e.extra.session;t.use_ort_model_bytes_directly||(t.use_ort_model_bytes_directly="1"),e.executionProviders&&e.executionProviders.some(n=>(typeof n=="string"?n:n.name)==="webgpu")&&(e.enableMemPattern=!1)},Fe=(e,t,n,o)=>{let r=F(t,o),a=F(n,o);I()._OrtAddSessionConfigEntry(e,r,a)!==0&&T(`Can't set a session config entry: ${t} - ${n}.`)},$n=async(e,t,n)=>{for(let o of t){let r=typeof o=="string"?o:o.name,a=[];switch(r){case"webnn":if(r="WEBNN",typeof o!="string"){let l=o?.deviceType;l&&Fe(e,"deviceType",l,n)}break;case"webgpu":if(r="JS",typeof o!="string"){let c=o;if(c?.preferredLayout){if(c.preferredLayout!=="NCHW"&&c.preferredLayout!=="NHWC")throw new Error(`preferredLayout must be either 'NCHW' or 'NHWC': ${c.preferredLayout}`);Fe(e,"preferredLayout",c.preferredLayout,n)}}break;case"wasm":case"cpu":continue;default:throw new Error(`not supported execution provider: ${r}`)}let i=F(r,n),s=a.length,u=0,f=0;if(s>0){u=I()._malloc(s*I().PTR_SIZE),n.push(u),f=I()._malloc(s*I().PTR_SIZE),n.push(f);for(let c=0;c{let t=I(),n=0,o=[],r=e||{};Gn(r);try{let a=kn(r.graphOptimizationLevel??"all"),i=Wn(r.executionMode??"sequential"),s=typeof r.logId=="string"?F(r.logId,o):0,u=r.logSeverityLevel??2;if(!Number.isInteger(u)||u<0||u>4)throw new Error(`log severity level is not valid: ${u}`);let f=r.logVerbosityLevel??0;if(!Number.isInteger(f)||f<0||f>4)throw new Error(`log verbosity level is not valid: ${f}`);let c=typeof r.optimizedModelFilePath=="string"?F(r.optimizedModelFilePath,o):0;if(n=t._OrtCreateSessionOptions(a,!!r.enableCpuMemArena,!!r.enableMemPattern,i,!!r.enableProfiling,0,s,u,f,c),n===0&&T("Can't create session options."),r.executionProviders&&await $n(n,r.executionProviders,o),r.enableGraphCapture!==void 0){if(typeof r.enableGraphCapture!="boolean")throw new Error(`enableGraphCapture must be a boolean value: ${r.enableGraphCapture}`);Fe(n,"enableGraphCapture",r.enableGraphCapture.toString(),o)}if(r.freeDimensionOverrides)for(let[l,d]of Object.entries(r.freeDimensionOverrides)){if(typeof l!="string")throw new Error(`free dimension override name must be a string: ${l}`);if(typeof d!="number"||!Number.isInteger(d)||d<0)throw new Error(`free dimension override value must be a non-negative integer: ${d}`);let p=F(l,o);t._OrtAddFreeDimensionOverride(n,p,d)!==0&&T(`Can't set a free dimension override: ${l} - ${d}.`)}return r.extra!==void 0&&we(r.extra,"",new WeakSet,(l,d)=>{Fe(n,l,d,o)}),[n,o]}catch(a){throw n!==0&&t._OrtReleaseSessionOptions(n)!==0&&T("Can't release session options."),o.forEach(i=>t._free(i)),a}}});var ie,Ne,ae,an,un,ke,We,fn,at=E(()=>{"use strict";ie=e=>{switch(e){case"int8":return 3;case"uint8":return 2;case"bool":return 9;case"int16":return 5;case"uint16":return 4;case"int32":return 6;case"uint32":return 12;case"float16":return 10;case"float32":return 1;case"float64":return 11;case"string":return 8;case"int64":return 7;case"uint64":return 13;case"int4":return 22;case"uint4":return 21;default:throw new Error(`unsupported data type: ${e}`)}},Ne=e=>{switch(e){case 3:return"int8";case 2:return"uint8";case 9:return"bool";case 5:return"int16";case 4:return"uint16";case 6:return"int32";case 12:return"uint32";case 10:return"float16";case 1:return"float32";case 11:return"float64";case 8:return"string";case 7:return"int64";case 13:return"uint64";case 22:return"int4";case 21:return"uint4";default:throw new Error(`unsupported data type: ${e}`)}},ae=(e,t)=>{let n=[-1,4,1,1,2,2,4,8,-1,1,2,8,4,8,-1,-1,-1,-1,-1,-1,-1,.5,.5][e],o=typeof t=="number"?t:t.reduce((r,a)=>r*a,1);return n>0?Math.ceil(o*n):void 0},an=e=>{switch(e){case"float16":return typeof Float16Array<"u"&&Float16Array.from?Float16Array:Uint16Array;case"float32":return Float32Array;case"uint8":return Uint8Array;case"int8":return Int8Array;case"uint16":return Uint16Array;case"int16":return Int16Array;case"int32":return Int32Array;case"bool":return Uint8Array;case"float64":return Float64Array;case"uint32":return Uint32Array;case"int64":return BigInt64Array;case"uint64":return BigUint64Array;default:throw new Error(`unsupported type: ${e}`)}},un=e=>{switch(e){case"verbose":return 0;case"info":return 1;case"warning":return 2;case"error":return 3;case"fatal":return 4;default:throw new Error(`unsupported logging level: ${e}`)}},ke=e=>e==="float32"||e==="float16"||e==="int32"||e==="int64"||e==="uint32"||e==="uint8"||e==="bool"||e==="uint4"||e==="int4",We=e=>e==="float32"||e==="float16"||e==="int32"||e==="int64"||e==="uint32"||e==="uint64"||e==="int8"||e==="uint8"||e==="bool"||e==="uint4"||e==="int4",fn=e=>{switch(e){case"none":return 0;case"cpu":return 1;case"cpu-pinned":return 2;case"texture":return 3;case"gpu-buffer":return 4;case"ml-tensor":return 5;default:throw new Error(`unsupported data location: ${e}`)}}});var he,ut=E(()=>{"use strict";Ae();he=async e=>{if(typeof e=="string")if(!1)try{let{readFile:t}=Ye("node:fs/promises");return new Uint8Array(await t(e))}catch(t){if(t.code==="ERR_FS_FILE_TOO_LARGE"){let{createReadStream:n}=Ye("node:fs"),o=n(e),r=[];for await(let a of o)r.push(a);return new Uint8Array(Buffer.concat(r))}throw t}else{let t=await fetch(e);if(!t.ok)throw new Error(`failed to load external data file: ${e}`);let n=t.headers.get("Content-Length"),o=n?parseInt(n,10):0;if(o<1073741824)return new Uint8Array(await t.arrayBuffer());{if(!t.body)throw new Error(`failed to load external data file: ${e}, no response body.`);let r=t.body.getReader(),a;try{a=new ArrayBuffer(o)}catch(s){if(s instanceof RangeError){let u=Math.ceil(o/65536);a=new WebAssembly.Memory({initial:u,maximum:u}).buffer}else throw s}let i=0;for(;;){let{done:s,value:u}=await r.read();if(s)break;let f=u.byteLength;new Uint8Array(a,i,f).set(u),i+=f}return new Uint8Array(a,0,o)}}else return e instanceof Blob?new Uint8Array(await e.arrayBuffer()):e instanceof Uint8Array?e:new Uint8Array(e)}});var zn,Le,Pe,ue,Hn,cn,me,De,Ue,dn,_e,xe,ve,rt=E(()=>{"use strict";X();rn();sn();at();ee();Re();ut();zn=(e,t)=>{I()._OrtInit(e,t)!==0&&T("Can't initialize onnxruntime.")},Le=async e=>{zn(e.wasm.numThreads,un(e.logLevel))},Pe=async(e,t)=>{I().asyncInit?.();let n=e.webgpu.adapter;if(t==="webgpu"){if(typeof navigator>"u"||!navigator.gpu)throw new Error("WebGPU is not supported in current environment");if(n){if(typeof n.limits!="object"||typeof n.features!="object"||typeof n.requestDevice!="function")throw new Error("Invalid GPU adapter set in `env.webgpu.adapter`. It must be a GPUAdapter object.")}else{let o=e.webgpu.powerPreference;if(o!==void 0&&o!=="low-power"&&o!=="high-performance")throw new Error(`Invalid powerPreference setting: "${o}"`);let r=e.webgpu.forceFallbackAdapter;if(r!==void 0&&typeof r!="boolean")throw new Error(`Invalid forceFallbackAdapter setting: "${r}"`);if(n=await navigator.gpu.requestAdapter({powerPreference:o,forceFallbackAdapter:r}),!n)throw new Error('Failed to get GPU adapter. You may need to enable flag "--enable-unsafe-webgpu" if you are using Chrome.')}}if(t==="webnn"&&(typeof navigator>"u"||!navigator.ml))throw new Error("WebNN is not supported in current environment")},ue=new Map,Hn=e=>{let t=I(),n=t.stackSave();try{let o=t.PTR_SIZE,r=t.stackAlloc(2*o);t._OrtGetInputOutputCount(e,r,r+o)!==0&&T("Can't get session input/output count.");let i=o===4?"i32":"i64";return[Number(t.getValue(r,i)),Number(t.getValue(r+o,i))]}finally{t.stackRestore(n)}},cn=(e,t)=>{let n=I(),o=n.stackSave(),r=0;try{let a=n.PTR_SIZE,i=n.stackAlloc(2*a);n._OrtGetInputOutputMetadata(e,t,i,i+a)!==0&&T("Can't get session input/output metadata.");let u=Number(n.getValue(i,"*"));r=Number(n.getValue(i+a,"*"));let f=n.HEAP32[r/4];if(f===0)return[u,0];let c=n.HEAPU32[r/4+1],l=[];for(let d=0;d{let t=I(),n=t._malloc(e.byteLength);if(n===0)throw new Error(`Can't create a session. failed to allocate a buffer of size ${e.byteLength}.`);return t.HEAPU8.set(e,n),[n,e.byteLength]},De=async(e,t)=>{let n,o,r=I();Array.isArray(e)?[n,o]=e:e.buffer===r.HEAPU8.buffer?[n,o]=[e.byteOffset,e.byteLength]:[n,o]=me(e);let a=0,i=0,s=0,u=[],f=[],c=[];try{if([i,u]=await on(t),t?.externalData&&r.mountExternalData){let g=[];for(let S of t.externalData){let _=typeof S=="string"?S:S.path;g.push(he(typeof S=="string"?S:S.data).then(M=>{r.mountExternalData(_,M)}))}await Promise.all(g)}for(let g of t?.executionProviders??[])if((typeof g=="string"?g:g.name)==="webnn"){if(r.shouldTransferToMLTensor=!1,typeof g!="string"){let _=g,M=_?.context,v=_?.gpuDevice,re=_?.deviceType,de=_?.powerPreference;M?r.currentContext=M:v?r.currentContext=await r.webnnCreateMLContext(v):r.currentContext=await r.webnnCreateMLContext({deviceType:re,powerPreference:de})}else r.currentContext=await r.webnnCreateMLContext();break}a=await r._OrtCreateSession(n,o,i),r.webgpuOnCreateSession?.(a),a===0&&T("Can't create a session."),r.jsepOnCreateSession?.(),r.currentContext&&(r.webnnRegisterMLContext(a,r.currentContext),r.currentContext=void 0,r.shouldTransferToMLTensor=!0);let[l,d]=Hn(a),p=!!t?.enableGraphCapture,w=[],b=[],B=[],m=[],h=[];for(let g=0;gr._OrtFree(d)),c.forEach(d=>r._OrtFree(d)),s!==0&&r._OrtReleaseBinding(s)!==0&&T("Can't release IO binding."),a!==0&&r._OrtReleaseSession(a)!==0&&T("Can't release session."),l}finally{r._free(n),i!==0&&r._OrtReleaseSessionOptions(i)!==0&&T("Can't release session options."),u.forEach(l=>r._free(l)),r.unmountExternalData?.()}},Ue=e=>{let t=I(),n=ue.get(e);if(!n)throw new Error(`cannot release session. invalid session id: ${e}`);let[o,r,a,i,s]=n;i&&(s&&t._OrtClearBoundOutputs(i.handle)!==0&&T("Can't clear bound outputs."),t._OrtReleaseBinding(i.handle)!==0&&T("Can't release IO binding.")),t.jsepOnReleaseSession?.(e),t.webnnOnReleaseSession?.(e),t.webgpuOnReleaseSession?.(e),r.forEach(u=>t._OrtFree(u)),a.forEach(u=>t._OrtFree(u)),t._OrtReleaseSession(o)!==0&&T("Can't release session."),ue.delete(e)},dn=async(e,t,n,o,r,a,i=!1)=>{if(!e){t.push(0);return}let s=I(),u=s.PTR_SIZE,f=e[0],c=e[1],l=e[3],d=l,p,w;if(f==="string"&&(l==="gpu-buffer"||l==="ml-tensor"))throw new Error("String tensor is not supported on GPU.");if(i&&l!=="gpu-buffer")throw new Error(`External buffer must be provided for input/output index ${a} when enableGraphCapture is true.`);if(l==="gpu-buffer"){let m=e[2].gpuBuffer;w=ae(ie(f),c);{let h=s.jsepRegisterBuffer;if(!h)throw new Error('Tensor location "gpu-buffer" is not supported without using WebGPU.');p=h(o,a,m,w)}}else if(l==="ml-tensor"){let m=e[2].mlTensor;w=ae(ie(f),c);let h=s.webnnRegisterMLTensor;if(!h)throw new Error('Tensor location "ml-tensor" is not supported without using WebNN.');p=h(o,m,ie(f),c)}else{let m=e[2];if(Array.isArray(m)){w=u*m.length,p=s._malloc(w),n.push(p);for(let h=0;hs.setValue(B+O*u,h,u===4?"i32":"i64"));let m=s._OrtCreateTensor(ie(f),p,w,B,c.length,fn(d));m===0&&T(`Can't create tensor for input/output. session=${o}, index=${a}.`),t.push(m)}finally{s.stackRestore(b)}},_e=async(e,t,n,o,r,a)=>{let i=I(),s=i.PTR_SIZE,u=ue.get(e);if(!u)throw new Error(`cannot run inference. invalid session id: ${e}`);let f=u[0],c=u[1],l=u[2],d=u[3],p=u[4],w=u[5],b=t.length,B=o.length,m=0,h=[],O=[],g=[],S=[],_=i.stackSave(),M=i.stackAlloc(b*s),v=i.stackAlloc(b*s),re=i.stackAlloc(B*s),de=i.stackAlloc(B*s);try{[m,h]=nn(a),q("wasm prepareInputOutputTensor");for(let y=0;yU*L,1);P=Ne(be);let le=d?.outputPreferredLocations[o[y]];if(P==="string"){if(le==="gpu-buffer"||le==="ml-tensor")throw new Error("String tensor is not supported on GPU.");let U=[];for(let L=0;L0){let U=i.jsepGetBuffer;if(!U)throw new Error('preferredLocation "gpu-buffer" is not supported without using WebGPU.');let L=U(C),V=ae(be,j);if(V===void 0||!ke(P))throw new Error(`Unsupported data type: ${P}`);oe=!0,$.push([P,H,{gpuBuffer:L,download:i.jsepCreateDownloader(L,V,P),dispose:()=>{i._OrtReleaseTensor(z)!==0&&T("Can't release tensor.")}},"gpu-buffer"])}else if(le==="ml-tensor"&&j>0){let U=i.webnnEnsureTensor,L=i.webnnIsGraphInputOutputTypeSupported;if(!U||!L)throw new Error('preferredLocation "ml-tensor" is not supported without using WebNN.');if(ae(be,j)===void 0||!We(P))throw new Error(`Unsupported data type: ${P}`);if(!L(e,P,!1))throw new Error(`preferredLocation "ml-tensor" for ${P} output is not supported by current WebNN Context.`);let ge=await U(e,C,be,H,!1);oe=!0,$.push([P,H,{mlTensor:ge,download:i.webnnCreateMLTensorDownloader(C,P),dispose:()=>{i.webnnReleaseTensorId(C),i._OrtReleaseTensor(z)}},"ml-tensor"])}else if(le==="ml-tensor-cpu-output"&&j>0){let U=i.webnnCreateMLTensorDownloader(C,P)(),L=$.length;oe=!0,lt.push((async()=>{let V=[L,await U];return i.webnnReleaseTensorId(C),i._OrtReleaseTensor(z),V})()),$.push([P,H,[],"cpu"])}else{let U=an(P),L=new U(j);new Uint8Array(L.buffer,L.byteOffset,L.byteLength).set(i.HEAPU8.subarray(C,C+L.byteLength)),$.push([P,H,L,"cpu"])}}finally{i.stackRestore(pt),P==="string"&&C&&i._free(C),oe||i._OrtReleaseTensor(z)}}d&&!p&&(i._OrtClearBoundOutputs(d.handle)!==0&&T("Can't clear bound outputs."),ue.set(e,[f,c,l,d,p,!1]));for(let[y,z]of await Promise.all(lt))$[y][2]=z;return Z("wasm ProcessOutputTensor"),$}finally{i.webnnOnRunEnd?.(f),i.stackRestore(_),O.forEach(N=>i._OrtReleaseTensor(N)),g.forEach(N=>i._OrtReleaseTensor(N)),S.forEach(N=>i._free(N)),m!==0&&i._OrtReleaseRunOptions(m),h.forEach(N=>i._free(N))}},xe=e=>{let t=I(),n=ue.get(e);if(!n)throw new Error("invalid session id");let o=n[0],r=t._OrtEndProfiling(o);r===0&&T("Can't get an profile file name."),t._OrtFree(r)},ve=e=>{let t=[];for(let n of e){let o=n[2];!Array.isArray(o)&&"buffer"in o&&t.push(o.buffer)}return t}});var ne,W,ye,$e,ze,Ge,ft,ct,fe,ce,Vn,ln,pn,mn,wn,hn,yn,bn,dt=E(()=>{"use strict";X();rt();ee();Be();ne=()=>!!A.wasm.proxy&&typeof document<"u",ye=!1,$e=!1,ze=!1,ct=new Map,fe=(e,t)=>{let n=ct.get(e);n?n.push(t):ct.set(e,[t])},ce=()=>{if(ye||!$e||ze||!W)throw new Error("worker not ready")},Vn=e=>{switch(e.data.type){case"init-wasm":ye=!1,e.data.err?(ze=!0,ft[1](e.data.err)):($e=!0,ft[0]()),Ge&&(URL.revokeObjectURL(Ge),Ge=void 0);break;case"init-ep":case"copy-from":case"create":case"release":case"run":case"end-profiling":{let t=ct.get(e.data.type);e.data.err?t.shift()[1](e.data.err):t.shift()[0](e.data.out);break}default:}},ln=async()=>{if(!$e){if(ye)throw new Error("multiple calls to 'initWasm()' detected.");if(ze)throw new Error("previous call to 'initWasm()' failed.");if(ye=!0,ne())return new Promise((e,t)=>{W?.terminate(),Qt().then(([n,o])=>{try{W=o,W.onerror=a=>t(a),W.onmessage=Vn,ft=[e,t];let r={type:"init-wasm",in:A};if(!r.in.wasm.wasmPaths&&n){let a=Ce();a&&(r.in.wasm.wasmPaths=a)}W.postMessage(r),Ge=n}catch(r){t(r)}},t)});try{await Oe(A.wasm),await Le(A),$e=!0}catch(e){throw ze=!0,e}finally{ye=!1}}},pn=async e=>{if(ne())return ce(),new Promise((t,n)=>{fe("init-ep",[t,n]);let o={type:"init-ep",in:{epName:e,env:A}};W.postMessage(o)});await Pe(A,e)},mn=async e=>ne()?(ce(),new Promise((t,n)=>{fe("copy-from",[t,n]);let o={type:"copy-from",in:{buffer:e}};W.postMessage(o,[e.buffer])})):me(e),wn=async(e,t)=>{if(ne()){if(t?.preferredOutputLocation)throw new Error('session option "preferredOutputLocation" is not supported for proxy.');return ce(),new Promise((n,o)=>{fe("create",[n,o]);let r={type:"create",in:{model:e,options:{...t}}},a=[];e instanceof Uint8Array&&a.push(e.buffer),W.postMessage(r,a)})}else return De(e,t)},hn=async e=>{if(ne())return ce(),new Promise((t,n)=>{fe("release",[t,n]);let o={type:"release",in:e};W.postMessage(o)});Ue(e)},yn=async(e,t,n,o,r,a)=>{if(ne()){if(n.some(i=>i[3]!=="cpu"))throw new Error("input tensor on GPU is not supported for proxy.");if(r.some(i=>i))throw new Error("pre-allocated output tensor is not supported for proxy.");return ce(),new Promise((i,s)=>{fe("run",[i,s]);let u=n,f={type:"run",in:{sessionId:e,inputIndices:t,inputs:u,outputIndices:o,options:a}};W.postMessage(f,ve(u))})}else return _e(e,t,n,o,r,a)},bn=async e=>{if(ne())return ce(),new Promise((t,n)=>{fe("end-profiling",[t,n]);let o={type:"end-profiling",in:e};W.postMessage(o)});xe(e)}});var gn,Jn,He,En=E(()=>{"use strict";X();dt();at();Ae();ut();gn=(e,t)=>{switch(e.location){case"cpu":return[e.type,e.dims,e.data,"cpu"];case"gpu-buffer":return[e.type,e.dims,{gpuBuffer:e.gpuBuffer},"gpu-buffer"];case"ml-tensor":return[e.type,e.dims,{mlTensor:e.mlTensor},"ml-tensor"];default:throw new Error(`invalid data location: ${e.location} for ${t()}`)}},Jn=e=>{switch(e[3]){case"cpu":return new k(e[0],e[2],e[1]);case"gpu-buffer":{let t=e[0];if(!ke(t))throw new Error(`not supported data type: ${t} for deserializing GPU tensor`);let{gpuBuffer:n,download:o,dispose:r}=e[2];return k.fromGpuBuffer(n,{dataType:t,dims:e[1],download:o,dispose:r})}case"ml-tensor":{let t=e[0];if(!We(t))throw new Error(`not supported data type: ${t} for deserializing MLTensor tensor`);let{mlTensor:n,download:o,dispose:r}=e[2];return k.fromMLTensor(n,{dataType:t,dims:e[1],download:o,dispose:r})}default:throw new Error(`invalid data location: ${e[3]}`)}},He=class{async fetchModelAndCopyToWasmMemory(t){return mn(await he(t))}async loadModel(t,n){J();let o;typeof t=="string"?o=await this.fetchModelAndCopyToWasmMemory(t):o=t,[this.sessionId,this.inputNames,this.outputNames,this.inputMetadata,this.outputMetadata]=await wn(o,n),Y()}async dispose(){return hn(this.sessionId)}async run(t,n,o){J();let r=[],a=[];Object.entries(t).forEach(d=>{let p=d[0],w=d[1],b=this.inputNames.indexOf(p);if(b===-1)throw new Error(`invalid input '${p}'`);r.push(w),a.push(b)});let i=[],s=[];Object.entries(n).forEach(d=>{let p=d[0],w=d[1],b=this.outputNames.indexOf(p);if(b===-1)throw new Error(`invalid output '${p}'`);i.push(w),s.push(b)});let u=r.map((d,p)=>gn(d,()=>`input "${this.inputNames[a[p]]}"`)),f=i.map((d,p)=>d?gn(d,()=>`output "${this.outputNames[s[p]]}"`):null),c=await yn(this.sessionId,a,u,s,f,o),l={};for(let d=0;dje,initializeFlags:()=>Tn,wasmBackend:()=>Yn});var Tn,je,Yn,In=E(()=>{"use strict";X();dt();En();Tn=()=>{(typeof A.wasm.initTimeout!="number"||A.wasm.initTimeout<0)&&(A.wasm.initTimeout=0);let e=A.wasm.simd;if(typeof e!="boolean"&&e!==void 0&&e!=="fixed"&&e!=="relaxed"&&(console.warn(`Property "env.wasm.simd" is set to unknown value "${e}". Reset it to \`false\` and ignore SIMD feature checking.`),A.wasm.simd=!1),typeof A.wasm.proxy!="boolean"&&(A.wasm.proxy=!1),typeof A.wasm.trace!="boolean"&&(A.wasm.trace=!1),typeof A.wasm.numThreads!="number"||!Number.isInteger(A.wasm.numThreads)||A.wasm.numThreads<=0)if(typeof self<"u"&&!self.crossOriginIsolated)A.wasm.numThreads=1;else{let t=typeof navigator>"u"?Ye("node:os").cpus().length:navigator.hardwareConcurrency;A.wasm.numThreads=Math.min(4,Math.ceil((t||1)/2))}},je=class{async init(t){Tn(),await ln(),await pn(t)}async createInferenceSessionHandler(t,n){let o=new He;return await o.loadModel(t,n),o}},Yn=new je});var Zn={};Ee(Zn,{InferenceSession:()=>kt,TRACE:()=>et,TRACE_EVENT_BEGIN:()=>q,TRACE_EVENT_END:()=>Z,TRACE_FUNC_BEGIN:()=>J,TRACE_FUNC_END:()=>Y,Tensor:()=>k,default:()=>qn,env:()=>A,registerBackend:()=>se});X();X();X();var jt="1.23.0";var qn=nt;{let e=(In(),qe(Sn)).wasmBackend;se("cpu",e,10),se("wasm",e,10)}Object.defineProperty(A.versions,"web",{value:jt,enumerable:!0});return qe(Zn);})(); +typeof exports=="object"&&typeof module=="object"&&(module.exports=ort); +//# sourceMappingURL=ort.wasm.min.js.map diff --git a/src/hooks/useAnalysisController/useEngineAnalysis.ts b/src/hooks/useAnalysisController/useEngineAnalysis.ts index 300fcf4d..2bb68714 100644 --- a/src/hooks/useAnalysisController/useEngineAnalysis.ts +++ b/src/hooks/useAnalysisController/useEngineAnalysis.ts @@ -84,6 +84,8 @@ export const useEngineAnalysis = ( const board = new Chess(currentNode.fen) const nodeFen = currentNode.fen + let maiaCancelled = false + const attemptMaiaAnalysis = async () => { const hasSelectedModelAnalysis = !!currentNode?.analysis.maia?.[currentMaiaModel] @@ -111,12 +113,18 @@ export const useEngineAnalysis = ( inProgressAnalyses.add(nodeFen) try { - if (currentNode.moveNumber <= 5) { - const [openingBookMoves, maiaEvaluations] = await Promise.all([ - fetchOpeningBook(board), - inferenceMaiaModel(board), - ]) + const openingBookPromise = + currentNode.moveNumber <= 5 + ? fetchOpeningBook(board) + : Promise.resolve(null) + + const maiaEvaluations = await inferenceMaiaModel(board) + + if (maiaCancelled) return + const openingBookMoves = await openingBookPromise + + if (openingBookMoves && currentNode.moveNumber <= 5) { const analysis: { [key: string]: MaiaEvaluation } = {} for (const model of MAIA_MODELS) { const policySource = Object.keys(openingBookMoves[model] || {}) @@ -135,15 +143,11 @@ export const useEngineAnalysis = ( ) as MaiaEvaluation['policy'], } } - currentNode.addMaiaAnalysis(analysis, currentMaiaModel) - setAnalysisState((state) => state + 1) - return } else { - const maiaEvaluations = await inferenceMaiaModel(board) currentNode.addMaiaAnalysis(maiaEvaluations, currentMaiaModel) - setAnalysisState((state) => state + 1) } + setAnalysisState((state) => state + 1) } finally { inProgressAnalyses.delete(nodeFen) } @@ -155,6 +159,7 @@ export const useEngineAnalysis = ( }, 100) return () => { + maiaCancelled = true clearTimeout(timeoutId) } }, [ diff --git a/src/hooks/useOpeningDrillController/useOpeningDrillController.ts b/src/hooks/useOpeningDrillController/useOpeningDrillController.ts index dee4b5c2..c1eecbff 100644 --- a/src/hooks/useOpeningDrillController/useOpeningDrillController.ts +++ b/src/hooks/useOpeningDrillController/useOpeningDrillController.ts @@ -631,7 +631,7 @@ export const useOpeningDrillController = ( } try { - const { result } = await maiaInstance.batchEvaluate( + const { result } = await maiaInstance.batchEvaluateMaia3( [fen], [rating], [rating], @@ -944,7 +944,7 @@ export const useOpeningDrillController = ( try { const boards = Array(MAIA_MODELS.length).fill(node.fen) - const { result } = await maiaInstance.batchEvaluate( + const { result } = await maiaInstance.batchEvaluateMaia3( boards, MAIA_ELO_VALUES, MAIA_ELO_VALUES, diff --git a/src/lib/engine/maia.ts b/src/lib/engine/maia.ts index 834efb49..8d7695dc 100644 --- a/src/lib/engine/maia.ts +++ b/src/lib/engine/maia.ts @@ -1,11 +1,9 @@ import { MaiaStatus } from 'src/types' -import { InferenceSession, Tensor } from 'onnxruntime-web' +import { Tensor } from 'onnxruntime-web' import { mirrorMove, - preprocess, preprocessMaia3, - allPossibleMovesReversed, allPossibleMovesMaia3Reversed, } from './tensor' import { MaiaModelStorage } from './storage' @@ -18,99 +16,86 @@ interface MaiaOptions { setError: (error: string) => void } +interface PendingInference { + resolve: (value: { + logitsMove: Float32Array + logitsValue: Float32Array + }) => void + reject: (error: Error) => void +} + class Maia { - private model!: InferenceSession - private modelUrl: string - private modelVersion: string + private worker: Worker | null = null private options: MaiaOptions private storage: MaiaModelStorage + private pendingInferences: Map = new Map() + private nextRequestId = 0 constructor(options: MaiaOptions) { - this.modelUrl = options.model - this.modelVersion = options.modelVersion this.options = options this.storage = new MaiaModelStorage() - - this.initialize() + this.initialize(options.model, options.modelVersion) } - private async initialize() { - // Request persistent storage for better reliability - await this.storage.requestPersistentStorage() - - console.log('Attempting to get model from IndexedDB...') - const buffer = await this.storage.getModel(this.modelUrl, this.modelVersion) - - if (buffer) { - console.log('Model found in IndexedDB, initializing...') - try { - await this.initializeModel(buffer) - console.log('Model initialized successfully') - } catch (e) { - console.error('Failed to initialize model:', e) - this.options.setStatus('error') - } - } else { - console.log('Model not found in cache, will show download modal') - - const storageInfo = await this.storage.getStorageInfo() - console.log('Maia cache status:', { - modelUrl: this.modelUrl, - userAgent: navigator.userAgent, - indexedDBSupported: storageInfo.supported, - storageEstimate: storageInfo.quota - ? { quota: storageInfo.quota, usage: storageInfo.usage } - : 'not supported', - modelSize: storageInfo.modelSize, - modelTimestamp: storageInfo.modelTimestamp, - }) - - this.options.setStatus('no-cache') + private initialize(modelUrl: string, modelVersion: string) { + if (typeof window === 'undefined' || typeof Worker === 'undefined') { + return } - } - - public async downloadModel() { - const response = await fetch(this.modelUrl) - if (!response.ok) throw new Error('Failed to fetch model') - - const reader = response.body?.getReader() - const contentLength = +(response.headers.get('Content-Length') ?? 0) - if (!reader) throw new Error('No response body') - - const chunks: Uint8Array[] = [] - let receivedLength = 0 - let lastReportedProgress = 0 - - while (true) { - const { done, value } = await reader.read() - if (done) break - - chunks.push(value) - receivedLength += value.length - - const currentProgress = Math.floor((receivedLength / contentLength) * 100) - if (currentProgress >= lastReportedProgress + 10) { - this.options.setProgress(currentProgress) - lastReportedProgress = currentProgress + this.worker = new Worker('/maia-worker.js') + + this.worker.onmessage = (e) => { + const msg = e.data + + switch (msg.type) { + case 'status': + this.options.setStatus(msg.status) + break + + case 'progress': + this.options.setProgress(msg.progress) + break + + case 'error': { + if (msg.id !== undefined) { + const pending = this.pendingInferences.get(msg.id) + if (pending) { + pending.reject(new Error(msg.message)) + this.pendingInferences.delete(msg.id) + } + } else { + this.options.setError(msg.message) + this.options.setStatus('error') + } + break + } + + case 'inference-result': { + const pending = this.pendingInferences.get(msg.id) + if (pending) { + pending.resolve({ + logitsMove: new Float32Array(msg.logitsMove), + logitsValue: new Float32Array(msg.logitsValue), + }) + this.pendingInferences.delete(msg.id) + } + break + } } } - const buffer = new Uint8Array(receivedLength) - let position = 0 - for (const chunk of chunks) { - buffer.set(chunk, position) - position += chunk.length + this.worker.onerror = (err) => { + console.error('Maia worker error:', err) + this.options.setError(err.message || 'Worker crashed') + this.options.setStatus('error') } - await this.storage.storeModel( - this.modelUrl, - this.modelVersion, - buffer.buffer, - ) + this.worker.postMessage({ type: 'init', modelUrl, modelVersion }) + } - await this.initializeModel(buffer.buffer) - this.options.setStatus('ready') + public async downloadModel() { + if (!this.worker) throw new Error('Worker not initialized') + this.worker.postMessage({ type: 'download' }) } public async getStorageInfo() { @@ -121,95 +106,63 @@ class Maia { return await this.storage.clearAllStorage() } - public async initializeModel(buffer: ArrayBuffer) { - this.model = await InferenceSession.create(buffer) - this.options.setStatus('ready') - } - - /** - * Evaluates a given chess position using the Maia model. - * - * @param board - The FEN string representing the chess position. - * @param eloSelf - The ELO rating of the player making the move. - * @param eloOppo - The ELO rating of the opponent. - * @returns A promise that resolves to an object containing the policy and value predictions. - */ - async evaluate(board: string, eloSelf: number, eloOppo: number) { - if (!this.model) { - throw new Error('Maia model not initialized') - } - - const { boardInput, legalMoves, eloSelfCategory, eloOppoCategory } = - preprocess(board, eloSelf, eloOppo) - - // Load and run the model - const feeds: Record = { - boards: new Tensor('float32', boardInput, [1, 18, 8, 8]), - elo_self: new Tensor( - 'int64', - BigInt64Array.from([BigInt(eloSelfCategory)]), - ), - elo_oppo: new Tensor( - 'int64', - BigInt64Array.from([BigInt(eloOppoCategory)]), - ), + private runInference( + tokens: Float32Array, + eloSelfs: Float32Array, + eloOppos: Float32Array, + batchSize: number, + ): Promise<{ logitsMove: Float32Array; logitsValue: Float32Array }> { + if (!this.worker) { + return Promise.reject(new Error('Worker not initialized')) } - const { logits_maia, logits_value } = await this.model.run(feeds) - - const { policy, value } = processOutputs( - board, - logits_maia, - logits_value, - legalMoves, - ) - return { - policy, - value, - } + const id = this.nextRequestId++ + + return new Promise((resolve, reject) => { + this.pendingInferences.set(id, { resolve, reject }) + + // Transfer ArrayBuffers for zero-copy send + this.worker!.postMessage( + { + type: 'inference', + id, + tokens: tokens.buffer, + eloSelfs: eloSelfs.buffer, + eloOppos: eloOppos.buffer, + batchSize, + }, + [tokens.buffer, eloSelfs.buffer, eloOppos.buffer], + ) + }) } /** - * Evaluates a chess position using the Maia3 model. - * Maia3 uses continuous ELO (float) instead of categorical buckets, - * and outputs WDL logits instead of a single value. + * Evaluates a chess position using the Maia3 model (off main thread). */ async evaluateMaia3(board: string, eloSelf: number, eloOppo: number) { - if (!this.model) { - throw new Error('Maia model not initialized') - } - const { boardTokens, legalMoves } = preprocessMaia3(board) - const feeds: Record = { - tokens: new Tensor('float32', boardTokens, [1, 64, 12]), - elo_self: new Tensor('float32', [eloSelf]), - elo_oppo: new Tensor('float32', [eloOppo]), - } - const { logits_move, logits_value } = await this.model.run(feeds) - - const { policy, value } = processOutputsMaia3( - board, - logits_move, - logits_value, - legalMoves, + const { logitsMove, logitsValue } = await this.runInference( + boardTokens, + Float32Array.from([eloSelf]), + Float32Array.from([eloOppo]), + 1, ) - return { policy, value } + const policyTensor = new Tensor('float32', logitsMove, [logitsMove.length]) + const valueTensor = new Tensor('float32', logitsValue, [logitsValue.length]) + + return processOutputsMaia3(board, policyTensor, valueTensor, legalMoves) } /** - * Evaluates a batch of chess positions using the Maia3 model. + * Evaluates a batch of chess positions using the Maia3 model (off main thread). */ async batchEvaluateMaia3( boards: string[], eloSelfs: number[], eloOppos: number[], ) { - if (!this.model) { - throw new Error('Maia model not initialized') - } - const batchSize = boards.length const boardInputs: Float32Array[] = [] const legalMovesArr: Float32Array[] = [] @@ -225,14 +178,13 @@ class Maia { combinedTokens.set(boardInputs[i], i * 64 * 12) } - const feeds: Record = { - tokens: new Tensor('float32', combinedTokens, [batchSize, 64, 12]), - elo_self: new Tensor('float32', Float32Array.from(eloSelfs), [batchSize]), - elo_oppo: new Tensor('float32', Float32Array.from(eloOppos), [batchSize]), - } - const start = performance.now() - const { logits_move, logits_value } = await this.model.run(feeds) + const { logitsMove, logitsValue } = await this.runInference( + combinedTokens, + Float32Array.from(eloSelfs), + Float32Array.from(eloOppos), + batchSize, + ) const end = performance.now() const results = [] @@ -241,22 +193,20 @@ class Maia { for (let i = 0; i < batchSize; i++) { const moveStart = i * moveLogitsPerItem - const moveEnd = moveStart + moveLogitsPerItem - const policyLogits = logits_move.data.slice( + const policyLogits = logitsMove.slice( moveStart, - moveEnd, - ) as Float32Array + moveStart + moveLogitsPerItem, + ) const policyTensor = new Tensor('float32', policyLogits, [ moveLogitsPerItem, ]) const valueStart = i * valueLogitsPerItem - const valueEnd = valueStart + valueLogitsPerItem - const valueLogits = logits_value.data.slice( + const valueLogitsSlice = logitsValue.slice( valueStart, - valueEnd, - ) as Float32Array - const valueTensor = new Tensor('float32', valueLogits, [ + valueStart + valueLogitsPerItem, + ) + const valueTensor = new Tensor('float32', valueLogitsSlice, [ valueLogitsPerItem, ]) @@ -272,174 +222,10 @@ class Maia { return { result: results, time: end - start } } - - /** - * Evaluates a batch of chess positions using the Maia model. - * - * @param boards - An array of FEN strings representing the chess positions. - * @param eloSelfs - An array of ELO ratings for the player making the move. - * @param eloOppos - An array of ELO ratings for the opponent. - * @returns A promise that resolves to an array of objects containing the policy and value predictions. - */ - async batchEvaluate( - boards: string[], - eloSelfs: number[], - eloOppos: number[], - ) { - if (!this.model) { - throw new Error('Maia model not initialized') - } - - const batchSize = boards.length - const boardInputs = [] - const eloSelfCategories = [] - const eloOppoCategories = [] - const legalMoves = [] - - for (let i = 0; i < boards.length; i++) { - const { - boardInput, - legalMoves: legalMoves_, - eloSelfCategory, - eloOppoCategory, - } = preprocess(boards[i], eloSelfs[i], eloOppos[i]) - - boardInputs.push(boardInput) - eloSelfCategories.push(eloSelfCategory) - eloOppoCategories.push(eloOppoCategory) - legalMoves.push(legalMoves_) - } - - const combinedBoardInputs = new Float32Array(batchSize * 18 * 8 * 8) - for (let i = 0; i < batchSize; i++) { - combinedBoardInputs.set(boardInputs[i], i * 18 * 8 * 8) - } - - const feeds: Record = { - boards: new Tensor('float32', combinedBoardInputs, [batchSize, 18, 8, 8]), - elo_self: new Tensor( - 'int64', - BigInt64Array.from(eloSelfCategories.map(BigInt)), - [batchSize], - ), - elo_oppo: new Tensor( - 'int64', - BigInt64Array.from(eloOppoCategories.map(BigInt)), - [batchSize], - ), - } - - const start = performance.now() - const { logits_maia, logits_value } = await this.model.run(feeds) - const end = performance.now() - - const results = [] - - for (let i = 0; i < batchSize; i++) { - const logitsPerItem = logits_maia.size / batchSize - const startIdx = i * logitsPerItem - const endIdx = startIdx + logitsPerItem - - const policyLogitsArray = logits_maia.data.slice( - startIdx, - endIdx, - ) as Float32Array - const policyTensor = new Tensor('float32', policyLogitsArray, [ - logitsPerItem, - ]) - const valueLogit = logits_value.data[i] as number - const valueTensor = new Tensor('float32', [valueLogit], [1]) - - const { policy, value: winProb } = processOutputs( - boards[i], - policyTensor, - valueTensor, - legalMoves[i], - ) - - results.push({ policy, value: winProb }) - } - - return { - result: results, - time: end - start, - } - } -} - -/** - * Processes the outputs of the ONNX model to compute the policy and value. - * - * @param {string} fen - The FEN string representing the current board state. - * @param {ort.Tensor} logits_maia - The logits tensor for the policy output from the model. - * @param {ort.Tensor} logits_value - The logits tensor for the value output from the model. - * @param {Float32Array} legalMoves - An array indicating the legal moves. - * @returns {{ policy: Record, value: number }} An object containing the policy (move probabilities) and the value (win probability). - */ -function processOutputs( - fen: string, - logits_maia: Tensor, - logits_value: Tensor, - legalMoves: Float32Array, -) { - const logits = logits_maia.data as Float32Array - const value = logits_value.data as Float32Array - - let winProb = Math.min(Math.max((value[0] as number) / 2 + 0.5, 0), 1) - - let black_flag = false - if (fen.split(' ')[1] === 'b') { - black_flag = true - winProb = 1 - winProb - } - - winProb = Math.round(winProb * 10000) / 10000 - - // Get indices of legal moves - const legalMoveIndices = legalMoves - .map((value, index) => (value > 0 ? index : -1)) - .filter((index) => index !== -1) - - const legalMovesMirrored = [] - for (const moveIndex of legalMoveIndices) { - let move = allPossibleMovesReversed[moveIndex] - if (black_flag) { - move = mirrorMove(move) - } - - legalMovesMirrored.push(move) - } - - // Extract logits for legal moves - const legalLogits = legalMoveIndices.map((idx) => logits[idx]) - - // Compute softmax over the legal logits - const maxLogit = Math.max(...legalLogits) - const expLogits = legalLogits.map((logit) => Math.exp(logit - maxLogit)) - const sumExp = expLogits.reduce((a, b) => a + b, 0) - const probs = expLogits.map((expLogit) => expLogit / sumExp) - - // Map the probabilities back to their move indices - const moveProbs: Record = {} - for (let i = 0; i < legalMoveIndices.length; i++) { - moveProbs[legalMovesMirrored[i]] = probs[i] - } - - const sortedMoveProbs = Object.keys(moveProbs) - .sort((a, b) => moveProbs[b] - moveProbs[a]) - .reduce( - (acc, key) => { - acc[key] = moveProbs[key] - return acc - }, - {} as Record, - ) - - return { policy: sortedMoveProbs, value: winProb } } /** - * Processes maia3 ONNX outputs. Maia3 outputs WDL (win/draw/loss) logits + * Processes maia3 ONNX outputs. Maia3 outputs LDW (loss/draw/win) logits * and uses a 4352-dimensional move space. */ function processOutputsMaia3( @@ -451,14 +237,12 @@ function processOutputsMaia3( const logits = logits_move.data as Float32Array const wdl = logits_value.data as Float32Array - // Convert LDW logits to win probability via softmax // Model output channels: index 0 = Loss, 1 = Draw, 2 = Win (for side-to-move) const maxWdl = Math.max(wdl[0], wdl[1], wdl[2]) const expL = Math.exp(wdl[0] - maxWdl) const expD = Math.exp(wdl[1] - maxWdl) const expW = Math.exp(wdl[2] - maxWdl) const sumExp = expL + expD + expW - // Win probability = P(win) + 0.5 * P(draw) let winProb = (expW + 0.5 * expD) / sumExp let black_flag = false @@ -469,7 +253,6 @@ function processOutputsMaia3( winProb = Math.round(winProb * 10000) / 10000 - // Get indices of legal moves const legalMoveIndices = legalMoves .map((value, index) => (value > 0 ? index : -1)) .filter((index) => index !== -1) @@ -483,7 +266,6 @@ function processOutputsMaia3( legalMovesMirrored.push(move) } - // Softmax over legal move logits const legalLogits = legalMoveIndices.map((idx) => logits[idx]) const maxLogit = Math.max(...legalLogits) const expLogits = legalLogits.map((logit) => Math.exp(logit - maxLogit))