Files
botfights/frontend/src/game/tts-worker.ts
T
DorianandClaude Opus 4.6 010e18fbd3 refactor: eliminate any types across server and TTS worker
- app.ts: type serveFile context parameter as Hono Context
- bets.ts: replace catch(err: any) with err: unknown + narrowing
- fight-loop.ts: type pickMatchup style as union literal, replace
  as any casts with proper result type
- tts-worker.ts: import KokoroTTS type, use ProgressInfo inference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 20:34:11 +00:00

54 lines
1.7 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.
import type { KokoroTTS } from 'kokoro-js'
let tts: KokoroTTS | null = 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) => {
if ('progress' in p && typeof p.progress === 'number') {
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
}
}
})