Split everything up into dynamically loaded modules.

This commit is contained in:
2025-04-04 00:00:43 +00:00
parent 2f7cda4b6d
commit aa29a6fd93
32 changed files with 8768 additions and 3935 deletions
+120
View File
@@ -0,0 +1,120 @@
/**
* Kokoro Web Worker
* Handles TTS processing in a separate thread to keep UI responsive
*/
// Global variables
let kokoroLoaded = false;
let isProcessing = false;
let voiceOptions = {
voice: 'bf_alice',
speed: 1.0
};
// Initialize when receiving init message
self.onmessage = function(e) {
const message = e.data;
try {
switch (message.type) {
case 'init':
// Just acknowledge initialization - actual model loading happens on first generate call
self.postMessage({ type: 'ready' });
break;
case 'generate':
if (!message.data || !message.data.text) {
self.postMessage({
type: 'error',
error: 'No text provided for generation'
});
return;
}
// Store voice options
if (message.data.voice) voiceOptions.voice = message.data.voice;
if (message.data.speed) voiceOptions.speed = message.data.speed;
// Generate speech
generateSpeech(message.data.text)
.catch(error => {
self.postMessage({
type: 'error',
error: `Generation error: ${error.message || error}`
});
});
break;
default:
self.postMessage({
type: 'error',
error: `Unknown message type: ${message.type}`
});
}
} catch (error) {
self.postMessage({
type: 'error',
error: `Worker error: ${error.message || error}`
});
}
};
/**
* Generate speech from text
* @param {string} text - Text to convert to speech
*/
async function generateSpeech(text) {
if (isProcessing) {
throw new Error('Already processing another request');
}
isProcessing = true;
try {
// Load Kokoro if not already loaded
if (!kokoroLoaded) {
// Load the Kokoro script
self.importScripts('/js/kokoro-js.js');
if (!self.kokoro || !self.kokoro.KokoroTTS) {
throw new Error('Kokoro failed to load correctly');
}
kokoroLoaded = true;
}
// Create a new Kokoro instance for this generation
// We can't easily transfer the instance from the main thread, so we create it here
const kokoroTTS = self.kokoro.KokoroTTS;
// Create instance using from_pretrained
const tts = await kokoroTTS.from_pretrained("onnx-community/Kokoro-82M-v1.0-ONNX", {
dtype: "fp32",
device: "wasm",
cache: true // Use cache to speed up subsequent loads
});
// Generate speech
const result = await tts.generate(text, {
voice: voiceOptions.voice,
speed: voiceOptions.speed
});
// Send the result back to the main thread
// We can't transfer the Float32Array directly, so let's transfer the buffer
const audioBuffer = result.audio.buffer;
self.postMessage({
type: 'generated',
result: {
audio: audioBuffer,
sampling_rate: result.sampling_rate
}
}, [audioBuffer]); // Transfer the buffer for better performance
} catch (error) {
throw error;
} finally {
isProcessing = false;
}
}