Publish audio.transcribe-speech@1.0.0 (Whisper-tiny, greedy English ASR) - #474
Merged
Merged
Conversation
…SR). Fifth and final model from this session's AI-WASM-model review (registry#473, following #455/#460/#465/#469) -- fourth genuinely ai.model_backed agent (text.detect-language/#469 correctly did not qualify). Real openai/whisper-tiny forward pass: log-mel spectrogram front end, 4-layer/384-dim/6-head transformer encoder, 4-layer decoder with causal self-attention + cross-attention, greedy English-forced no-timestamps decoding (an officially-sanctioned minimal decoding path, not an invented shortcut). Verified against a from-scratch pure-numpy implementation (not just onnxruntime), which caught a real bug (a forgotten v_proj.bias, defaulting to zero) before it shipped. Quantization (int8, incl. the tied 51865x384 embed_tokens table) tested end to end on real audio (openai/whisper's own tests/jfk.flac fixture): matched the float32 baseline's transcript exactly except one comma token -- autoregressive token decisions proved robust to quantization noise, unlike audio.detect-speech-segments' recurrent Silero VAD (registry#460). Compiled wasm32-unknown-unknown artifact verified via wasmtime against the same real audio: byte-for-byte match with the Python reference. Building against real ~180K-sample audio input surfaced a genuine bump-allocator OOM at the shared 64 MiB heap ceiling (not from this capability's own scratch buffers, but from the shared JSON parser's Vec<Value> growth-by-reallocation for a long input array, never freed). Fixed by raising capability-src/wasi-capability-runtime's shared HEAP_SIZE 64 -> 192 MiB (same allocator/rationale as the prior 16->64 MiB raise, registry#384) -- re-ran cargo test for text.detect-entities, audio.detect-speech-segments, text.detect-language, and report.translate-fr-semantic after the change; no regressions. capability-src/audio-transcribe-speech: 14 #[test] cases; cargo llvm-cov functions=100%, lines=98.46%, regions=98.59%. License: dual-attested -- openai/whisper's own GitHub LICENSE is MIT; the HF model card's own metadata says apache-2.0. Both primary sources, both permissive; logged as-is rather than picking one. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Publishes
audio.transcribe-speech@1.0.0-- a real Whisper-tiny (encoder-decoder transformer) speech-to-text forward pass, greedy English-forced decoding. Closes #473, the fifth and final model from this session's AI-WASM-model review (following #455/#460/#465/#469).Why this capability
Natural complement to
audio.detect-speech-segments(#460): an app that already gates on "is there speech in this clip" (e.g. Callweave) is a short step from "what did it say," and free-text transcription feeds directly intotext.detect-entities(#465) andtext.detect-language(#469) as a pipeline.Architecture / decoding
80-channel log-mel spectrogram front end -> 2-conv1d/4-layer/384-dim/6-head transformer encoder -> 4-layer decoder (causal self-attention + cross-attention to the full 1500-frame encoder output) -> greedy (argmax) autoregressive decoding, seeded with a fixed
<|startoftranscript|><|en|><|transcribe|><|notimestamps|>prompt. This is an officially-sanctioned minimal decoding path, not an invented shortcut -- HF's owngeneration_config.jsonships exactly this forced-token configuration foropenai/whisper-tiny. No KV-cache: each step recomputes the full decoder stack over the sequence so far (matching the non-cacheddecoder_model.onnxvariant this was verified against), which is correctness-first and tractable at this model's scale.Verification
Xenova/whisper-tiny) -- not just callingonnxruntime. This caught a real bug before it shipped: a forgottenv_proj.biasin the weight dict (silently defaulting to zero), producing a ~17-magnitude hidden-state divergence invisible without this independent cross-check.openai/whisper's owntests/jfk.flacfixture (the famous JFK inaugural excerpt). The numpy reference matchedonnxruntimetoken-for-token, exactly.embed_tokenstable) tested empirically on the same real audio through the full greedy autoregressive loop, not assumed safe: matched the float32 baseline's transcript exactly except one comma token (arguably the more accurate rendering of the real quote) -- unlikeaudio.detect-speech-segments' recurrent Silero VAD (audio.detect-speech-segments@1.0.0 — Silero VAD, generic speech-risk scorer #460), where int8 measurably broke the LSTM's output, autoregressive token decisions here proved robust to per-weight quantization noise.wasm32-unknown-unknown --features full-modelartifact run underwasmtime(CLI) on the same real audio (11s clip and a 1s excerpt): output matched the quantized Python reference exactly, byte for byte.capability-src/audio-transcribe-speech: 14#[test]cases against a synthetic fixture;cargo llvm-covfunctions=100%, lines=98.46%, regions=98.59%.Shared-crate change: heap size 64 -> 192 MiB
Building the wasm artifact against real ~176,000-sample (11s) audio input surfaced a genuine bump-allocator OOM (
exit(2)) at the prior 64 MiB shared heap ceiling. Root cause was not this capability's own ~41 MiB of audio/attention scratch buffers (which are allocated once and reused, never per-layer/step) -- it was the shared JSON parser'sVec<Value>being grown by repeated reallocation for a long input array (parser doesn't know the final length up front), with every abandoned smaller buffer from each doubling staying allocated forever in a bump allocator that never frees.Fixed by raising
capability-src/wasi-capability-runtime's sharedHEAP_SIZEconstant 64 -> 192 MiB -- same allocator, same "zero-cost headroom" rationale documented at the prior 16 -> 64 MiB raise (registry#384). Re-rancargo testfortext.detect-entities,audio.detect-speech-segments,text.detect-language, andreport.translate-fr-semanticafter the change to confirm no regression from this shared-crate edit -- all green.License
Dual-attested, logged as-is rather than picking one:
openai/whisper's own GitHubLICENSEfile is MIT (verified directly); theopenai/whisper-tinyHugging Face model card's own metadata (cardData.license) says apache-2.0. Both primary sources, both permissive.Governing Spec
Project Item
https://github.com/orgs/traverse-framework/projects/3 -- #473
Definition of Done
capability-src/audio-transcribe-speech/#![no_std]; ABI-clean (imports exactly{fd_read, fd_write, proc_exit});#[test]coverage functions=100%/lines®ions>=95%.capabilities/audio/audio.transcribe-speech/1.0.0/contract.json-- full I/O schema,ai.model_backed: true, spec-024risk.determinism_class: model_derived, spec-023authoring, provenance citing audio.transcribe-speech@1.0.0 — Whisper-tiny ASR, fifth/final model from the AI-WASM-model list #473.scripts/model/prepare_whisper_tiny_int8.py); digest-pinned release asset (weight table too large to commit inline, unlike text.detect-language@1.0.0 — CLD2 language ID, FR-017 status TBD #469's small trigram table)..wasm,pre_pr_check.shgreen, human merge.Validation
bash scripts/ci/pre_pr_check.sh <this body>with BASE/HEAD wired as CI wires them.🤖 Generated with Claude Code