Compare commits

..
5 Commits
Author SHA1 Message Date
Gitea Actions 1458fa8382 Release 0.1.49 [auto-version-bump] 2026-10-16 07:16:18 +02:00
Ein Anderssono 145c025f05 Update Piper asset MIME source check
Build and publish frontend / publish (push) Successful in 1m32s
2026-10-16 07:15:30 +02:00
Ein Anderssono c618d2e31e Fix Piper ONNX runtime asset URLs
Build and publish frontend / publish (push) Failing after 2s
2026-10-16 07:15:12 +02:00
Gitea Actions 696a47a9a2 Release 0.1.48 [auto-version-bump] 2026-10-16 07:11:26 +02:00
Ein Anderssono 95d308b326 Serve Piper voice credits as readable text
Build and publish frontend / publish (push) Successful in 1m10s
2026-10-16 07:10:55 +02:00
9 changed files with 46 additions and 11 deletions
+1
View File
@@ -45,6 +45,7 @@ jobs:
test -s public/tts/piper-wasm-v1/voices/sv/sv_SE/lisa/medium/sv_SE-lisa-medium.onnx.json test -s public/tts/piper-wasm-v1/voices/sv/sv_SE/lisa/medium/sv_SE-lisa-medium.onnx.json
test -s public/tts/piper-wasm-v1/voices/sv/sv_SE/nst/medium/sv_SE-nst-medium.onnx test -s public/tts/piper-wasm-v1/voices/sv/sv_SE/nst/medium/sv_SE-nst-medium.onnx
test -s public/tts/piper-wasm-v1/voices/sv/sv_SE/nst/medium/sv_SE-nst-medium.onnx.json test -s public/tts/piper-wasm-v1/voices/sv/sv_SE/nst/medium/sv_SE-nst-medium.onnx.json
test -s public/tts/piper-wasm-v1/voices/ATTRIBUTION.txt
- name: Ensure Helm is available - name: Ensure Helm is available
shell: bash shell: bash
+1 -1
View File
@@ -1 +1 @@
0.1.47 0.1.49
+2 -2
View File
@@ -2,5 +2,5 @@ apiVersion: v2
name: ai-spel-frontend name: ai-spel-frontend
description: Static web frontend for the Swedish life simulator description: Static web frontend for the Swedish life simulator
type: application type: application
version: 0.1.47 version: 0.1.49
appVersion: "0.1.47" appVersion: "0.1.49"
+2 -1
View File
@@ -12,9 +12,10 @@ server {
location ^~ /tts/piper-wasm-v1/ { location ^~ /tts/piper-wasm-v1/ {
types { types {
application/wasm wasm; application/wasm wasm;
application/javascript js; application/javascript js mjs;
application/json json; application/json json;
application/octet-stream onnx; application/octet-stream onnx;
text/plain txt;
} }
add_header Cache-Control "public, max-age=31536000, immutable" always; add_header Cache-Control "public, max-age=31536000, immutable" always;
add_header Cross-Origin-Opener-Policy "same-origin" always; add_header Cross-Origin-Opener-Policy "same-origin" always;
+7
View File
@@ -0,0 +1,7 @@
const assetRoot = '/tts/piper-wasm-v1/onnx/';
export function createOnnxWasmPaths(origin) {
const absoluteAssetRoot = new URL(assetRoot, origin).href;
return absoluteAssetRoot;
}
+2 -1
View File
@@ -1,5 +1,6 @@
import {TtsSession} from '@mintplex-labs/piper-tts-web'; import {TtsSession} from '@mintplex-labs/piper-tts-web';
import {localPiperModelUrl} from './piper-model-routing.mjs'; import {localPiperModelUrl} from './piper-model-routing.mjs';
import {createOnnxWasmPaths} from './piper-onnx-config.mjs';
const VOICE_ID = 'sv_SE-nst-medium'; const VOICE_ID = 'sv_SE-nst-medium';
const ASSET_ROOT = '/tts/piper-wasm-v1'; const ASSET_ROOT = '/tts/piper-wasm-v1';
@@ -24,7 +25,7 @@ async function getSession(onProgress) {
voiceId: VOICE_ID, voiceId: VOICE_ID,
progress: onProgress, progress: onProgress,
wasmPaths: { wasmPaths: {
onnxWasm: `${ASSET_ROOT}/onnx/`, onnxWasm: createOnnxWasmPaths(self.location.origin),
piperData: `${ASSET_ROOT}/piper/piper_phonemize.data`, piperData: `${ASSET_ROOT}/piper/piper_phonemize.data`,
piperWasm: `${ASSET_ROOT}/piper/piper_phonemize.wasm`, piperWasm: `${ASSET_ROOT}/piper/piper_phonemize.wasm`,
}, },
+12 -5
View File
@@ -64,10 +64,16 @@ await mkdir(join(assetRoot, 'piper'), {recursive: true});
for (const file of voiceFiles) await downloadVoiceFile(file); for (const file of voiceFiles) await downloadVoiceFile(file);
await cp(join(root, 'PIPER_VOICE_NOTICES.txt'), join(assetRoot, 'voices', 'ATTRIBUTION.txt')); await cp(join(root, 'PIPER_VOICE_NOTICES.txt'), join(assetRoot, 'voices', 'ATTRIBUTION.txt'));
const wasmFiles = (await readdir(onnxSource)) const onnxRuntimeFiles = (await readdir(onnxSource))
.filter(name => name.endsWith('.wasm')); .filter(name => name.endsWith('.wasm') || name.endsWith('.mjs'));
if (wasmFiles.length === 0) throw new Error('ONNX Runtime WebAssembly files are missing'); const requiredOnnxRuntimeFiles = [
for (const file of wasmFiles) { 'ort-wasm-simd-threaded.wasm',
'ort-wasm-simd-threaded.mjs',
];
for (const file of requiredOnnxRuntimeFiles) {
if (!onnxRuntimeFiles.includes(file)) throw new Error(`Missing ONNX Runtime asset: ${file}`);
}
for (const file of onnxRuntimeFiles) {
await cp(join(onnxSource, file), join(assetRoot, 'onnx', file)); await cp(join(onnxSource, file), join(assetRoot, 'onnx', file));
} }
for (const file of [piperWasm, piperData]) { for (const file of [piperWasm, piperData]) {
@@ -106,7 +112,8 @@ for (const file of voiceFiles) {
} }
const workerBundle = await (await import('node:fs/promises')).readFile(join(assetRoot, 'piper-worker.js'), 'utf8'); const workerBundle = await (await import('node:fs/promises')).readFile(join(assetRoot, 'piper-worker.js'), 'utf8');
if (!workerBundle.includes('https://huggingface.co/diffusionstudio/piper-voices/resolve/main/') || if (!workerBundle.includes('https://huggingface.co/diffusionstudio/piper-voices/resolve/main/') ||
!workerBundle.includes('/tts/piper-wasm-v1/voices/')) { !workerBundle.includes('/tts/piper-wasm-v1/voices/') ||
!workerBundle.includes('/tts/piper-wasm-v1/onnx/')) {
throw new Error('The Piper worker is missing its same-origin model download route.'); throw new Error('The Piper worker is missing its same-origin model download route.');
} }
+4 -1
View File
@@ -10,7 +10,7 @@ grep -q 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0' nginx
grep -q 'Cross-Origin-Embedder-Policy "require-corp"' nginx/default.conf grep -q 'Cross-Origin-Embedder-Policy "require-corp"' nginx/default.conf
grep -q 'add_header Cross-Origin-Embedder-Policy "require-corp" always;' nginx/default.conf grep -q 'add_header Cross-Origin-Embedder-Policy "require-corp" always;' nginx/default.conf
grep -q 'add_header Cross-Origin-Resource-Policy "same-origin" always;' nginx/default.conf grep -q 'add_header Cross-Origin-Resource-Policy "same-origin" always;' nginx/default.conf
grep -q 'application/javascript js;' nginx/default.conf grep -q 'application/javascript js mjs;' nginx/default.conf
grep -q "request('/version')" index.html grep -q "request('/version')" index.html
grep -Fq "credentials: 'same-origin'" index.html grep -Fq "credentials: 'same-origin'" index.html
grep -q 'id="dialogue" aria-label="Dialoghistorik" role="log" aria-live="polite"' index.html grep -q 'id="dialogue" aria-label="Dialoghistorik" role="log" aria-live="polite"' index.html
@@ -47,6 +47,9 @@ grep -q 'new Worker(workerUrl)' piper-runtime.js
grep -q 'worker.js?v=' piper-runtime.js grep -q 'worker.js?v=' piper-runtime.js
grep -q 'worker.onmessageerror' piper-runtime.js grep -q 'worker.onmessageerror' piper-runtime.js
grep -q 'localPiperModelUrl' piper-worker.js grep -q 'localPiperModelUrl' piper-worker.js
grep -q 'createOnnxWasmPaths(self.location.origin)' piper-worker.js
grep -q 'ort-wasm-simd-threaded.mjs' scripts/build-piper.mjs
grep -q 'ort-wasm-simd-threaded.wasm' scripts/build-piper.mjs
grep -q 'PIPER_MODEL_ORIGIN' piper-model-routing.mjs grep -q 'PIPER_MODEL_ORIGIN' piper-model-routing.mjs
grep -q '/tts/piper-wasm-v1/voices/' piper-model-routing.mjs grep -q '/tts/piper-wasm-v1/voices/' piper-model-routing.mjs
grep -q 'same-origin.*voice' README.md grep -q 'same-origin.*voice' README.md
+15
View File
@@ -0,0 +1,15 @@
const test = require('node:test');
const assert = require('node:assert/strict');
test('ONNX Runtime receives an absolute same-origin base URL', async () => {
const {createOnnxWasmPaths} = await import('../piper-onnx-config.mjs');
const wasmPaths = createOnnxWasmPaths('https://ai-spel.k3s.k0.nu');
assert.equal(wasmPaths, 'https://ai-spel.k3s.k0.nu/tts/piper-wasm-v1/onnx/');
assert.equal(new URL('ort-wasm-simd-threaded.mjs', wasmPaths).href,
'https://ai-spel.k3s.k0.nu/tts/piper-wasm-v1/onnx/ort-wasm-simd-threaded.mjs');
});
test('ONNX Runtime base URL rejects an invalid worker origin', async () => {
const {createOnnxWasmPaths} = await import('../piper-onnx-config.mjs');
assert.throws(() => createOnnxWasmPaths('undefined'), TypeError);
});