From 3fc32edd5869b111a93dbe0732790e475a524002 Mon Sep 17 00:00:00 2001 From: Kresna Date: Sat, 1 Aug 2026 13:01:20 +0700 Subject: [PATCH] fix(voice-to-text): use per-module dtype so the Whisper session loads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported: 'Can't create a session … MatMulNBits Missing required scale: model.decoder.embed_tokens.weight … DequantizeLinear'. Whisper is an encoder-decoder model. A single-string dtype ('q8', the WASM default) left the decoder — which holds embed_tokens — on a 4-bit (MatMulNBits) variant whose scale tensor the bundled ONNX Runtime can't resolve, so the session fails to create. Switch to a per-module dtype and force decoder_model_merged to fp32 (unquantized, proper scales); the encoder stays q8 on WASM / fp32 on WebGPU to limit the download. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/tools/media/stt.engine.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tools/media/stt.engine.ts b/src/tools/media/stt.engine.ts index 2566c9a..2fe0461 100644 --- a/src/tools/media/stt.engine.ts +++ b/src/tools/media/stt.engine.ts @@ -45,8 +45,11 @@ export async function createTranscriber( const pipe = await pipeline('automatic-speech-recognition', model, { device: backend, - // Quantize on WASM to shrink the download; full precision on WebGPU for quality. - dtype: backend === 'wasm' ? 'q8' : 'fp32', + // Whisper is an encoder-decoder model. Per-module dtype is required: the + // quantized (q8/q4) decoder — which holds embed_tokens — trips an ONNX Runtime + // "MatMulNBits: Missing required scale" error, so load the decoder full + // precision. The encoder can stay quantized to keep the download smaller. + dtype: { encoder_model: backend === 'webgpu' ? 'fp32' : 'q8', decoder_model_merged: 'fp32' }, progress_callback: (p: { status?: string; progress?: number }) => { if (onProgress && p?.status === 'progress' && typeof p.progress === 'number') { onProgress(Math.min(1, Math.max(0, p.progress / 100)));