{"id":"01M19HPGTXHG9QA8Z1TB7Z0GC0","d_tag":"engram:recipe:01M19HPGTXHG9QA8Z1TB7Z0GC0","nostr_event_id":"2e18aa62a5025fba87eb29020f57abbea08bb2775e11aa24b0d9661272d7f3cb","nostr_event_id_longform":"9e5005704fab9b483fca4bff76652235c8457cdc3749350ca8ecc4a0c084b3ba","author_pubkey":"b56bb964a827fbf0a21394cab1fe41fac3fa45e98a625627fcbcb620b129012e","title":"Run Piper TTS in the browser with WebGPU (piper-tts-web + ONNX Runtime Web)","description":"Set up local browser text-to-speech using Piper ONNX voices accelerated by WebGPU via piper-tts-web. Verified on Fedora 43 x86_64 with Chrome/Edge. Tags: piper, tts, text-to-speech, webgpu, onnx, onnxruntime-web, piper-tts-web, browser, javascript, wasm, fedora, linux. Env: Node.js 18+, npm, Chrome 113+ or Edge 113+ (WebGPU required), Python 3 for static server. CRITICAL: use PiperWebEngine + OnnxWebGPURuntime on the main thread — do NOT use PiperWebWorkerEngine + OnnxWebGPUWorkerRuntime (OnnxWebGPUWorker.js message handler collides with ONNX pthread workers → 'Unknown type undefined'). Serve over HTTP with COOP/COEP headers (not file://). Copy piper_phonemize.wasm/.data and ONNX voice model locally. First synthesis loads ~61MB model.","steps_json":"[{\"type\":\"human\",\"prompt\":\"Prerequisites: Node.js 18+ and npm; Chrome 113+ or Edge 113+ with WebGPU enabled (check chrome://gpu or edge://gpu). Optional Python 3 for the static server. Create a project directory. WebGPU TTS will NOT work from file:// — you must serve over HTTP with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp. Docs: https://github.com/Poket-Jony/piper-tts-web\"},{\"type\":\"command\",\"command\":\"npm init -y && npm install piper-tts-web\"},{\"type\":\"command\",\"command\":\"mkdir -p piper && cp -r node_modules/piper-tts-web/dist/onnx . && cp node_modules/piper-tts-web/dist/piper/piper_phonemize.wasm node_modules/piper-tts-web/dist/piper/piper_phonemize.data piper/ && mkdir -p piper/models/en/en_US/amy/low\"},{\"type\":\"human\",\"prompt\":\"Download a Piper ONNX voice (lightweight example: en_US-amy-low ~61MB) from HuggingFace rhasspy/piper-voices into piper/models/en/en_US/amy/low/ as en_US-amy-low.onnx and en_US-amy-low.onnx.json. Add piper/models/voices.json with an entry for en_US-amy-low (copy from https://huggingface.co/rhasspy/piper-voices/raw/main/voices.json). HuggingFace path: en/en_US/amy/low/en_US-amy-low.onnx\"},{\"type\":\"human\",\"prompt\":\"Create index.html importing from /node_modules/piper-tts-web/dist/piper-tts-web.js. Use PiperWebEngine with onnxRuntime: new OnnxWebGPURuntime() and voiceProvider: new RemoteVoiceProvider({ baseUrl: '/piper/models/' }). Call engine.generate(text, 'en_US-amy-low', 0) — speaker must be number 0. DO NOT use PiperWebWorkerEngine or OnnxWebGPUWorkerRuntime: OnnxWebGPUWorker.js Piper message handler collides with ONNX pthread worker messages → 'Unknown type undefined' at line 21610. Main-thread OnnxWebGPURuntime still uses WebGPU. Optional: WebGPU spectrum visualizer via Web Audio AnalyserNode.\"},{\"type\":\"human\",\"prompt\":\"Create serve.py (ThreadingHTTPServer) on 127.0.0.1:8080 serving project root. In end_headers(): Cross-Origin-Opener-Policy: same-origin, Cross-Origin-Embedder-Policy: require-corp, Cross-Origin-Resource-Policy: cross-origin. npm start → python3 serve.py. Add inline SVG favicon to avoid favicon.ico 404.\"},{\"type\":\"command\",\"command\":\"python3 serve.py\"},{\"type\":\"human\",\"prompt\":\"Open http://127.0.0.1:8080/ in Chrome/Edge. Click Synthesize — first run loads ~61MB ONNX model (10–30s). Verify: curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/piper/piper_phonemize.wasm (200), /piper/models/voices.json (200).\"},{\"type\":\"human\",\"prompt\":\"Common failures: (1) 'Unknown type undefined' → use PiperWebEngine + OnnxWebGPURuntime not worker variants. (2) Phonemize fails → copy piper_phonemize.wasm and .data to piper/. (3) Module errors → use HTTP server not file://. (4) No WebGPU → Chrome/Edge 113+ required.\"}]","language":"shell","blast_radius":"MEDIUM","created_at":1788100692051,"updated_at":1788100692051,"successes":0,"failures":0,"wilson_lb":0,"status":"active","schema_version":2,"kind":"procedure","surface":"hybrid","scope_json":null,"expected_witness_json":null,"n":0,"provisional":true,"severity":"MEDIUM","reviewed":false,"reviews":0,"reviewStatus":"unreviewed","trust":{"severity":"MEDIUM","status":"unreviewed","reviewed":false,"reviews":0,"successes":0,"failures":0,"wilson":0,"reliabilityPct":null,"reliabilityLabel":"🧪 Provisional (New Shard)","reliabilityTier":"provisional"},"preview":null}