File size: 3,211 Bytes
519a20c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// kokoro-worker.js
/** @type {import('./lib/kokoro.web.js').KokoroTTS} */
let tts = null;
/** @type {boolean} */
let ready = false;
/** @type {string[]} */
let voices = [];

// Handle messages from the main thread
self.onmessage = async function(e) {
    const { action, data } = e.data;

    switch (action) {
        case 'initialize':
            try {
                const result = await initializeTts(data);
                self.postMessage({
                    action: 'initialized',
                    success: result,
                    voices,
                });
            } catch (error) {
                self.postMessage({
                    action: 'initialized',
                    success: false,
                    error: error.message,
                });
            }
            break;

        case 'generateTts':
            try {
                const audioBlob = await generateTts(data.text, data.voice, data.speakingRate);
                const blobUrl = URL.createObjectURL(audioBlob);
                self.postMessage({
                    action: 'generatedTts',
                    success: true,
                    blobUrl,
                    requestId: data.requestId,
                });
            } catch (error) {
                self.postMessage({
                    action: 'generatedTts',
                    success: false,
                    error: error.message,
                    requestId: data.requestId,
                });
            }
            break;

        case 'checkReady':
            self.postMessage({ action: 'readyStatus', ready });
            break;
    }
};

// Initialize the TTS engine
async function initializeTts(settings) {
    try {
        const { KokoroTTS } = await import('./lib/kokoro.web.js');

        console.log('Worker: Initializing Kokoro TTS with settings:', {
            modelId: settings.modelId,
            dtype: settings.dtype,
            device: settings.device,
        });

        // Create TTS instance
        tts = await KokoroTTS.from_pretrained(settings.modelId, {
            dtype: settings.dtype,
            device: settings.device,
        });

        // Get available voices
        voices = Object.keys(tts.voices);

        // Check if generate method exists
        if (typeof tts.generate !== 'function') {
            throw new Error('TTS instance does not have generate method');
        }

        console.log('Worker: TTS initialized successfully');
        ready = true;
        return true;
    } catch (error) {
        console.error('Worker: Kokoro TTS initialization failed:', error);
        ready = false;
        throw error;
    }
}

// Generate TTS audio
async function generateTts(text, voiceId, speakingRate) {
    if (!ready || !tts) {
        throw new Error('TTS engine not initialized');
    }

    if (text.trim().length === 0) {
        throw new Error('Empty text');
    }

    try {
        const audio = await tts.generate(text, {
            voice: voiceId,
            speed: speakingRate || 1.0,
        });

        return audio.toBlob();
    } catch (error) {
        console.error('Worker: TTS generation failed:', error);
        throw error;
    }
}