Cactus Fits Seven-Language Speech Recognition Into a 16.9 MB Whistle Model

Cactus Compute released Whistle on October 2, 2026. The Apache-2.0 speech-to-text model fits in one 16.9 MB file, runs on CPUs alongside its Needle tool-calling model, and transcribes seven languages with word timestamps on phones, wearables, and microcontrollers.

Cactus Whistle on-device speech recognition model transcribing audio on a small CPU device
Cactus Whistle on-device speech recognition model transcribing audio on a small CPU device

Cactus Compute released Whistle on October 2, 2026. The speech recognition model ships as a single 16.9 MB file, runs on a CPU with no extra dependencies, and transcribes English, German, French, Spanish, Italian, Dutch, and Polish. The weights are on Hugging Face under Apache 2.0, and the engine source is in the Apache-2.0 cactus-compute/needle repository on GitHub. Cactus aims Whistle at phones, wearables, robots, smart-home hubs, cars, and microcontrollers, the places where a 145 MB Whisper checkpoint or a round trip to a cloud API is the bottleneck.

One engine for speech and tool calls

Whistle runs on the C++ engine Cactus built for Needle, its small tool-calling model. It uses the same .cact container, the same Cactus Quants quantization at 2 to 4 bits, and the same SIMD kernels and KV cache. A device that already runs Needle can add speech without a second runtime. Loading both models lets one call take an audio clip and return tool calls. The engine transcribes the clip, answers the transcript against the supplied tools, and returns a single JSON object holding the function calls plus audio_-prefixed fields for the text and detected language.

The model does three jobs, all on the device. It transcribes 16 kHz mono audio of up to 30 seconds in one pass and detects the language unless the caller sets it. It returns per-word timestamps with probabilities, aligned from the decoder’s own attention. And it can output the raw encoder embedding, one row per 80 ms frame, for matching or retrieval without decoding text. Keyword biasing lets an app pass names and product terms, which the beam search then favors. When the clip is below a loudness threshold, the engine returns an empty transcript and never starts decoding, so silence does not produce invented sentences.

Inside a 16.9 MB recognizer

Cactus publishes the architecture in detail. Audio becomes 80 log-mel bins with a 25 ms window and 10 ms hop, band-limited to 250–3,500 Hz. A 128-channel convolutional stem then halves the frame count three times, so 30 seconds of audio becomes 375 frames. The encoder is eight non-causal attention blocks borrowed from Needle. The decoder is eight “laddered” blocks at width 512, with 8 query heads sharing 2 KV heads. Each decoder layer reads the audio through a gated cross-attention, and the projections for that attention are computed once per clip. As a result, five beams cost five short transcript caches rather than five passes over the audio. The vocabulary has 8,192 text pieces plus seven language tokens, so the detected language comes out as a token.

The ladder is a deployment feature. Cactus trained every decoder depth from two layers up as its own model, and the --audio-depth flag picks one at load time. Developers can trade accuracy for speed on weaker chips without retraining.

How it compares with Whisper base and Moonshine

On an Apple M4 Pro CPU with 10 seconds of audio, Cactus reports 11.1 ms to the first token for Whistle, against 73.2 ms for Whisper base and 22.8 ms for Moonshine tiny v2. It reports decoding at 1,319 tokens per second, against 266 and 262. By file size the three are 16.9 MB, 145.3 MB, and 41.9 MB. Whistle’s time to first token scales with clip length, from 5.9 ms at five seconds to 36.3 ms at 30. Whisper pads every input to 30 seconds, so its time stays flat.

On accuracy, the post states the result in words rather than only on the chart: Whistle is ahead on LibriSpeech test-clean and test-other, on SPGISpeech, on Earnings-22, and on the FLEURS average, while Whisper base is ahead on TED-LIUM, on AMI, and on the MLS average. The comparison uses the Whisper and Moonshine figures their authors published, while Whistle was measured across 86,174 utterances. Cactus says it checked audio checksums and speaker IDs to confirm that no test audio appears in Whistle’s training or validation data.

Getting it onto hardware

Developers can install it with pip install cactus-needle and transcribe a WAV file in two lines of Python. Microphone capture and resampling come with an optional [mic] extra. Prebuilt engine folders cover seventeen targets, including macOS, Linux, Android, iOS, watchOS, Windows on ARM, RISC-V, MIPS, the browser, and a WASI component. The engine reads no environment variables, so a given model file behaves identically on every run.

Whistle is not a general-purpose replacement for large multilingual ASR. It handles seven languages and clips of up to 30 seconds. For voice interfaces that need a fast local transcript and a tool call in one step, though, an Apache-2.0 model this small widens what can run offline.

Topics
  • #Voice AI
  • #Speech Recognition
  • #On-Device AI
  • #Cactus Compute
  • #Open Weights
Raj M

Author

Raj M

Contributor

AI Systems Architect is a seasoned technology leader with over 15 years of experience in the IT industry working with Fortune 500 companies. With a solid foundation in multi-agent systems, open-source LLM infrastructure, and enterprise deployment, he excels at building scalable production-grade AI platforms.