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
+51
View File
@@ -0,0 +1,51 @@
import {build} from 'esbuild';
import {cp, mkdir, readdir, rm, stat} from 'node:fs/promises';
import {join, resolve} from 'node:path';
const root = process.cwd();
const publicRoot = join(root, 'public');
const assetRoot = join(publicRoot, 'tts', 'piper-wasm-v1');
const onnxSource = join(root, 'node_modules', 'onnxruntime-web', 'dist');
const piperSource = join(root, 'node_modules', '@diffusionstudio', 'piper-wasm', 'build');
const piperWasm = join(piperSource, 'piper_phonemize.wasm');
const piperData = join(piperSource, 'piper_phonemize.data');
await rm(assetRoot, {recursive: true, force: true});
await mkdir(join(assetRoot, 'onnx'), {recursive: true});
await mkdir(join(assetRoot, 'piper'), {recursive: true});
const wasmFiles = (await readdir(onnxSource))
.filter(name => name.endsWith('.wasm'));
if (wasmFiles.length === 0) throw new Error('ONNX Runtime WebAssembly files are missing');
for (const file of wasmFiles) {
await cp(join(onnxSource, file), join(assetRoot, 'onnx', file));
}
for (const file of [piperWasm, piperData]) {
const fileStat = await stat(file).catch(() => null);
if (!fileStat?.isFile() || fileStat.size === 0) throw new Error(`Missing Piper WebAssembly asset: ${file}`);
await cp(file, join(assetRoot, 'piper', file.split('/').at(-1)));
}
await build({
entryPoints: [resolve(root, 'piper-runtime.js')],
outfile: join(publicRoot, 'piper-runtime.js'),
bundle: true,
format: 'iife',
platform: 'browser',
target: ['es2022'],
sourcemap: false,
legalComments: 'none',
});
await build({
entryPoints: [resolve(root, 'piper-worker.js')],
outfile: join(assetRoot, 'piper-worker.js'),
bundle: true,
format: 'iife',
platform: 'browser',
target: ['es2022'],
sourcemap: false,
legalComments: 'none',
});
console.log(`Piper browser assets prepared at ${assetRoot}`);
+9
View File
@@ -5,7 +5,9 @@ test -s index.html
grep -q '<html lang="sv">' index.html
grep -q 'id="frontend-version">__FRONTEND_VERSION__' index.html
grep -q '<script src="/voice.js?v=__FRONTEND_VERSION__"></script>' index.html
grep -q '<script src="/piper-runtime.js?v=__FRONTEND_VERSION__"></script>' index.html
grep -q 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0' nginx/default.conf
grep -q 'Cross-Origin-Embedder-Policy "require-corp"' nginx/default.conf
grep -q "request('/version')" index.html
grep -Fq "credentials: 'same-origin'" index.html
grep -q 'id="dialogue" aria-label="Dialoghistorik" role="log" aria-live="polite"' index.html
@@ -33,6 +35,13 @@ grep -q 'WebKit versions before Safari 27' voice.js
grep -q "voiceIdentity: speakingNpc.voice_identity" index.html
grep -q "role: 'narrator', voiceIdentity: 'neutral'" index.html
grep -q 'COPY voice.js /usr/share/nginx/html/voice.js' Dockerfile
grep -q 'COPY public/piper-runtime.js /usr/share/nginx/html/piper-runtime.js' Dockerfile
grep -q 'COPY public/tts/piper-wasm-v1/' Dockerfile
grep -q 'build:piper' .gitea/workflows/publish.yaml
grep -q 'Piper' piper-runtime.js
grep -q 'sv_SE-nst-medium' piper-worker.js
grep -q 'new Worker(workerUrl)' piper-runtime.js
grep -q 'worker.js?v=' piper-runtime.js
grep -q "SpeechRecognition || win.webkitSpeechRecognition" voice.js
grep -q "submitMessage(text, 'voice')" index.html
grep -q 'Spelets repliker läses alltid upp' index.html