Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1458fa8382 | ||
|
|
145c025f05 | ||
|
|
c618d2e31e | ||
|
|
696a47a9a2 | ||
|
|
95d308b326 |
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user