52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
// Web Worker for Kokoro TTS — runs ONNX neural network inference off the main thread.
|
|||
|
|
// This prevents the 1-5 second freezes that occur when generate() runs on the UI thread.
|
||
|
|
|
||
|
|
let tts: any = null
|
||
|
|
|
||
|
|
self.addEventListener('message', async (e: MessageEvent) => {
|
||
|
|
const msg = e.data
|
||
|
|
|
||
|
|
switch (msg.type) {
|
||
|
|
case 'init': {
|
||
|
|
try {
|
||
|
|
const { KokoroTTS } = await import('kokoro-js')
|
||
|
|
tts = await KokoroTTS.from_pretrained('onnx-community/Kokoro-82M-ONNX', {
|
||
|
|
dtype: 'q8',
|
||
|
|
device: null,
|
||
|
|
progress_callback: (p: any) => {
|
||
|
|
if (p.progress !== undefined) {
|
||
|
|
self.postMessage({ type: 'progress', progress: p.progress })
|
||
|
|
}
|
||
|
|
},
|
||
|
|
})
|
||
|
|
self.postMessage({ type: 'init-done' })
|
||
|
|
} catch (err) {
|
||
|
|
self.postMessage({ type: 'init-failed', error: String(err) })
|
||
|
|
}
|
||
|
|
break
|
||
|
|
}
|
||
|
|
|
||
|
|
case 'generate': {
|
||
|
|
if (!tts) {
|
||
|
|
self.postMessage({ type: 'generate-failed', id: msg.id, error: 'not initialized' })
|
||
|
|
break
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
const result = await tts.generate(msg.text, {
|
||
|
|
voice: msg.voice,
|
||
|
|
speed: msg.speed,
|
||
|
|
})
|
||
|
|
// Copy to a standalone ArrayBuffer so we can transfer ownership (zero-copy to main thread)
|
||
|
|
const audio = new Float32Array(result.audio)
|
||
|
|
self.postMessage(
|
||
|
|
{ type: 'generate-done', id: msg.id, audio, sampleRate: result.sampling_rate },
|
||
|
|
{ transfer: [audio.buffer] },
|
||
|
|
)
|
||
|
|
} catch (err) {
|
||
|
|
self.postMessage({ type: 'generate-failed', id: msg.id, error: String(err) })
|
||
|
|
}
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|