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
+42
View File
@@ -0,0 +1,42 @@
const version = document.querySelector('#frontend-version')?.textContent || 'dev';
const workerUrl = `/tts/piper-wasm-v1/piper-worker.js?v=${encodeURIComponent(version)}`;
let worker;
let requestId = 0;
const pending = new Map();
function getWorker() {
if (worker) return worker;
worker = new Worker(workerUrl);
worker.onmessage = event => {
const message = event.data || {};
const request = pending.get(message.id);
if (!request) return;
if (message.type === 'progress') {
request.onProgress?.(message.progress);
} else {
pending.delete(message.id);
if (message.type === 'audio') request.resolve(new Blob([message.audio], {type: 'audio/x-wav'}));
else request.reject(new Error(message.error || 'Piper-arbetaren misslyckades.'));
}
};
worker.onerror = event => {
const error = new Error(event.message || 'Piper-arbetaren kunde inte startas.');
for (const request of pending.values()) request.reject(error);
pending.clear();
worker?.terminate();
worker = null;
};
return worker;
}
window.GamePiper = {
voiceId: 'sv_SE-nst-medium',
synthesize(text, onProgress) {
return new Promise((resolve, reject) => {
const id = ++requestId;
pending.set(id, {resolve, reject, onProgress});
try { getWorker().postMessage({id, text: String(text)}); }
catch (error) { pending.delete(id); reject(error); }
});
},
};