// Only model assets leave/enter the network. User inputs go to a local Worker. let worker; let serial = 0; const pending = new Map(); function client() { if (!worker) { worker = new Worker(new URL('./inference-worker.js?v=20260921-load-progress-v1', import.meta.url), {type: 'module'}); worker.onmessage = ({data}) => { const call = pending.get(data.id); if (!call) return; if (data.progress) { call.onProgress?.(data.progress); return; } pending.delete(data.id); data.error ? call.reject(new Error(data.error)) : call.resolve(data.result); }; worker.onerror = event => { for (const call of pending.values()) call.reject(new Error(event.message || 'ブラウザ内の推論処理に失敗しました。')); pending.clear(); worker.terminate(); worker = null; }; } return worker; } function request(type, payload, onProgress) { const id = ++serial; return new Promise((resolve, reject) => { pending.set(id, {resolve, reject, onProgress}); client().postMessage({id, type, ...payload}); }); } export function loadModel({onProgress, backend = 'auto'} = {}) { return request('load', {backend}, onProgress); } export function analyze(samples16k, samples48k, context, questions, {onProgress} = {}) { return request('analyze', {samples: samples16k, samples48k, context, questions}, onProgress); }