// Line-level ONNX Runtime Web loader. Full document routing is a separate layer. const sessions=new Map(); export function flipVisual(text,tables){ const marks=new Set(tables.marks),kind=c=>['R','AL'].includes(tables.directions[c])?'R':['L','EN','AN'].includes(tables.directions[c])?'L':'N'; const clusters=[];for(const c of text){if(clusters.length&&marks.has(c))clusters[clusters.length-1]+=c;else clusters.push(c);} if(!clusters.some(c=>kind([...c][0])==='R'))return text; const mirror=new Map([..."()[]{}<>«»‹›"].map((c,i)=>[c,[...")(][}{><»«›‹"][i]])); const units=[];let i=0; while(i=0){ for(let k=i;kr.json()),fetch(new URL('unicode-directions.json',base)).then(r=>r.json()),fetch(modelURL).then(r=>r.arrayBuffer())]); const modelHash=[...new Uint8Array(await crypto.subtle.digest('SHA-256',bytes))].map(x=>x.toString(16).padStart(2,'0')).join(''),identity=modelHash+':'+backend; if(!sessions.has(identity))sessions.set(identity,ort.InferenceSession.create(bytes,{executionProviders:[backend],graphOptimizationLevel:'all'})); const session=await sessions.get(identity),cache=new Map(),pending=new Map(); async function infer(ink,width){ if(!(ink instanceof Float32Array)||ink.length!==64*width||width<1)throw Error('Float32 ink map64×true_width required'); const hash=[...new Uint8Array(await crypto.subtle.digest('SHA-256',ink))].map(x=>x.toString(16).padStart(2,'0')).join(''),key=identity+':'+width+':'+hash; if(cache.has(key)){const value=cache.get(key);cache.delete(key);cache.set(key,value);return {...value,cached:true};} if(pending.has(key))return pending.get(key); const task=(async()=>{ const bucket=Math.max(512,2**Math.ceil(Math.log2(width)));if(bucket>8192)throw Error('Width exceeds validated8192 bound; never truncated'); const pixels=new Float32Array(64*bucket);for(let y=0;y<64;y++)pixels.set(ink.subarray(y*width,(y+1)*width),y*bucket); const inputs={pixels:new ort.Tensor('float32',pixels,[1,1,64,bucket]),widths:new ort.Tensor('int64',BigInt64Array.of(BigInt(width)),[1])};let outputs; try{ outputs=await session.run(inputs);const n=Number(outputs.lengths.data[0]);let visual='',confidence=0,count=0,previous=-1; for(let i=0;i0){cache.set(key,result);while(cache.size>cacheEntries)cache.delete(cache.keys().next().value);}return result; }finally{if(outputs)Object.values(outputs).forEach(t=>t.dispose());Object.values(inputs).forEach(t=>t.dispose());} })();pending.set(key,task);try{return await task;}finally{pending.delete(key);} } return {read:infer,modelHash,clearCache:()=>cache.clear()}; }