Add browser-local Piper WebAssembly speech
Build and publish frontend / publish (push) Failing after 6s

This commit is contained in:
Ein Anderssono
2026-10-16 06:47:59 +02:00
parent 474fd80a95
commit aed6b15a20
14 changed files with 332 additions and 22 deletions
+41
View File
@@ -0,0 +1,41 @@
import {TtsSession} from '@mintplex-labs/piper-tts-web';
const VOICE_ID = 'sv_SE-nst-medium';
const ASSET_ROOT = '/tts/piper-wasm-v1';
let sessionPromise;
let inferenceQueue = Promise.resolve();
async function getSession(onProgress) {
if (!sessionPromise) {
sessionPromise = TtsSession.create({
voiceId: VOICE_ID,
progress: onProgress,
wasmPaths: {
onnxWasm: `${ASSET_ROOT}/onnx/`,
piperData: `${ASSET_ROOT}/piper/piper_phonemize.data`,
piperWasm: `${ASSET_ROOT}/piper/piper_phonemize.wasm`,
},
}).catch(error => {
sessionPromise = null;
throw error;
});
}
return sessionPromise;
}
async function synthesizeMessage(event) {
const {id, text} = event.data || {};
if (!Number.isSafeInteger(id) || typeof text !== 'string') return;
try {
const session = await getSession(progress => self.postMessage({id, type: 'progress', progress}));
const blob = await session.predict(text);
const audio = await blob.arrayBuffer();
self.postMessage({id, type: 'audio', audio}, [audio]);
} catch (error) {
self.postMessage({id, type: 'error', error: String(error?.message || error)});
}
}
self.addEventListener('message', event => {
inferenceQueue = inferenceQueue.then(() => synthesizeMessage(event));
});