import { APP_CONFIG } from './config' import { configureOrt, createTtsSessions, ensureWebGpuSupport, fetchCondEmb, fetchTokenizerJson } from './onnx' import { runFinnishPipeline, type TtsSessions } from './pipeline' import { createTokenizer, type BrowserTokenizer } from './tokenizer' import type { WorkerRequest, WorkerResponse } from './types' let sessionsPromise: Promise | null = null let tokenizerPromise: Promise | null = null let condEmbPromise: Promise | null = null const workerScope = self as typeof self & { postMessage: (message: WorkerResponse, transfer?: Transferable[]) => void onmessage: ((event: MessageEvent) => void | Promise) | null } function postMessageToMain(message: WorkerResponse, transfer: Transferable[] = []): void { workerScope.postMessage(message, transfer) } function reportStatus(message: string): void { postMessageToMain({ type: 'status', message }) } async function ensureInitialized(): Promise<{ sessions: TtsSessions tokenizer: BrowserTokenizer condEmb: Float32Array }> { ensureWebGpuSupport() configureOrt() sessionsPromise ??= createTtsSessions(reportStatus) tokenizerPromise ??= fetchTokenizerJson().then((json) => createTokenizer(json)) condEmbPromise ??= fetchCondEmb() const [sessions, tokenizer, condEmb] = await Promise.all([ sessionsPromise, tokenizerPromise, condEmbPromise, ]) postMessageToMain({ type: 'ready' }) return { sessions, tokenizer, condEmb } } async function handleSpeakRequest(message: Extract): Promise { const { sessions, tokenizer, condEmb } = await ensureInitialized() const result = await runFinnishPipeline({ sessions, tokenizer, condEmb, referenceAudio: message.referenceAudio, text: message.text, reportStatus, }) postMessageToMain( { type: 'result', audio: result.audio, sampleRate: APP_CONFIG.sampleRate, speechTokenCount: result.speechTokenCount, }, [result.audio.buffer], ) } workerScope.onmessage = async (event: MessageEvent) => { try { if (event.data.type === 'speak') { await handleSpeakRequest(event.data) } } catch (error) { const message = error instanceof Error ? error.message : String(error) postMessageToMain({ type: 'error', message }) } }