Moonshine
Local speech-to-text with MoonshineSTTService, running Moonshine's small, fast ASR models on the CPU. No API key.
Overview
MoonshineSTTService: a segmented STT service that transcribes each speech segment, cut by the pipeline's VAD, with a Moonshine model on your machine. Moonshine is a small, fast ASR family that runs on the CPU: no GPU, no account, no API key.Transcriber(@pipedog/moonshine/moonshine_voice): the engine. Upstream wraps themoonshine_voicePython package (a C++ core on ONNX Runtime). This one runs the same quantized.ortmodel files through@pipedog/onnx, with the part of Moonshine's C++ core thattranscribe_without_streamingruns ported to TypeScript.
Moonshine is the default transcriber of upstream's keyless local defaults for evals: it transcribes the bot's speech in audio scenarios.
Upstream page
Pipecat's documentation for the same service.
Source
packages/moonshine/src/stt.ts and the engine, moonshine_voice.ts.
Moonshine
The models, languages and licenses.
Installation
bun add @pipedog/moonshine onnxruntime-nodeonnxruntime-node is an optional peer of @pipedog/onnx. onnxruntime-web@1.30.0 (WebAssembly)
loads the same .ort files and gives the same transcripts, about 3x slower.
import { Model, MoonshineSTTService } from "@pipedog/moonshine/stt";What you need
| Models | Moonshine's quantized ORT-format models from https://download.moonshine.ai/model/..., the files and versions moonshine_voice 0.1.5 uses. Each download is checked against Moonshine's published size and CRC32C |
| Sizes | English: tiny 44 MB, tiny-streaming 45 MB, base 141 MB, small-streaming 142 MB (the default), medium-streaming 269 MB. Other languages: tiny-streaming 32 MB, small-streaming 122 MB, base 65-141 MB, tiny (ja, ko) 72 MB |
| Download | Automatic, once, when the pipeline starts (or on the first transcription) |
| Cache | $PIPEDOG_CACHE_DIR/moonshine, else $XDG_CACHE_HOME/pipedog/moonshine, else ~/.cache/pipedog/moonshine, or the cacheRoot option |
| VAD | Silero VAD, the silero_vad.onnx shipped with @pipedog/audio-silero (a dependency), for the segmentation Moonshine applies inside each batch |
| Input | 16 kHz, 16-bit mono PCM, and a VAD in the pipeline |
Files go in <cacheRoot>/download.moonshine.ai/model/<model>/..., the layout moonshine_voice
uses, so you can copy a moonshine_voice cache over. To use files you already have, pass
cacheRoot:
// Models already on disk, in <cacheRoot>/download.moonshine.ai/model/<model>/...
// (the layout moonshine_voice uses, so a moonshine_voice cache can be copied over).
const fromDisk = new MoonshineSTTService({
cacheRoot: "/models/moonshine",
settings: new MoonshineSTTService.Settings({ model: Model.TINY }),
});Or give the engine any model directory directly (see Usage), or the model files in
memory with transcriberOptions.files. downloadModel(language, arch?) downloads a model ahead
of time.
Runtimes
| Runtime | Works | What it needs |
|---|---|---|
| Bun | ✅ yes | onnxruntime-node (or onnxruntime-web) and a filesystem for the model cache: models download on first use from download.moonshine.ai (tiny 44 MB; the default, small-streaming, 142 MB). |
| Node.js | ✅ yes | onnxruntime-node (or onnxruntime-web) and a filesystem for the model cache: models download on first use from download.moonshine.ai (tiny 44 MB; the default, small-streaming, 142 MB). |
| Deno | ✅ yes | onnxruntime-node (or onnxruntime-web) and a filesystem for the model cache: models download on first use from download.moonshine.ai (tiny 44 MB; the default, small-streaming, 142 MB). |
| Cloudflare Workers | ❌ no | onnxruntime-node (or onnxruntime-web) and a filesystem for the model cache: models download on first use from download.moonshine.ai (tiny 44 MB; the default, small-streaming, 142 MB). Not supported: the models (32-269 MB) and their inference sessions exceed Workers' memory and bundle limits. |
Generated from pipecat.runtimes and pipecat.compat in packages/moonshine/package.json: ✅ means the compat smoke test passes on that runtime.
Cloudflare Workers is not supported: the models (32-269 MB) and their inference sessions don't fit a Worker's 128 MB of memory or its 10 MB bundle limit.
For the 11 s JFK clip (4 segments), on an Apple M4 Pro with Bun and onnxruntime-node: tiny
0.1 s, base 0.12 s, tiny-streaming 0.2 s, small-streaming 0.35 s.
MoonshineSTTService
Configuration
Prop
Type
transcriberOptions (pipedog only) takes the Transcriber's options: backend (any
OnnxBackend), fetch for downloads, files (model files in memory), vadModel,
shareSessions, and Moonshine's maxTokensPerSecond (6.5), vadThreshold (0.5),
vadWindowDuration (0.5 s), vadHopSize (512), vadLookBehindSampleCount (8192) and
vadMaxSegmentDuration (15 s).
Settings
Runtime-updatable settings, passed as settings: new MoonshineSTTService.Settings({...})
(MoonshineSTTSettings). Any setting you leave out keeps the default below. A change reloads the
model, and keeps the old one if the new one fails to load.
| Setting | Type | Default | Description |
|---|---|---|---|
model | Model | string | Model.SMALL_STREAMING | Architecture: TINY, BASE, TINY_STREAMING, BASE_STREAMING, SMALL_STREAMING or MEDIUM_STREAMING (or the string, such as "small-streaming"). |
language | Language | Language.EN | Arabic, Chinese, English, German, Japanese, Korean, Spanish, Tagalog, Ukrainian or Vietnamese. Regional variants resolve to the base code. An architecture a language doesn't publish falls back to that language's default, as upstream. |
Usage
import { STTUpdateSettingsFrame } from "@pipedog/core/frames/frames";
import { Language } from "@pipedog/core/transcriptions/language";
import { Model, MoonshineSTTService } from "@pipedog/moonshine/stt";
// Downloads small-streaming (142 MB) from download.moonshine.ai on first start.
const stt = new MoonshineSTTService({
settings: new MoonshineSTTService.Settings({
model: Model.SMALL_STREAMING,
language: Language.EN,
}),
});Change the language or model mid-call with an STTUpdateSettingsFrame:
// Queue it on the worker, or push it from a processor upstream of the service.
// A model or language change reloads the model.
const update = new STTUpdateSettingsFrame({
delta: new MoonshineSTTService.Settings({ language: Language.ES }),
});
The engine works on its own, with any model directory:
import { ModelArch, Transcriber } from "@pipedog/moonshine/moonshine_voice";
const transcriber = new Transcriber("/models/tiny-en", ModelArch.TINY);
const samples = new Float32Array(16000); // mono audio in [-1, 1]
const transcript = await transcriber.transcribeWithoutStreaming(samples, 16000);
console.log(transcript.lines.map((line) => line.text).join(" "));Notes
- Emits one
TranscriptionFrameper segment. There are no interim results. - Every model, streaming ones included, is run in one batch per segment
(
transcribeWithoutStreaming). - The constructor rejects a missing model or language, a model that names no architecture, and a language Moonshine publishes no model for.
Differences from upstream
- The model is resolved in the constructor but downloaded and loaded in
start()(or on the first transcription). Upstream downloads and loads it in the constructor. - Upstream also prefetches the optional English spelling model, which
transcribe_without_streamingnever uses. It is not downloaded. - Only what
transcribe_without_streamingneeds is ported: no streaming API (create_stream), word timestamps, speaker diarization, key-term biasing or spelling mode. - Inference runs on onnxruntime 1.30, where Moonshine bundles 1.23.2: the same graphs, so the same transcripts up to floating-point rounding.
cacheRootandtranscriberOptionsare pipedog options.
Licenses
@pipedog/moonshine: BSD 2-Clause. The engine ports parts of Moonshine (MIT).- Models: MIT in every language and size, except the non-streaming models (
tiny,base) for languages other than English, which are under the non-commercial Moonshine Community License. They are downloaded at runtime, not shipped. - Silero VAD (through
@pipedog/audio-silero): MIT.
pipedog is an unofficial community TypeScript port of Pipecat. It is not affiliated with or endorsed by Daily or the Pipecat project.
Portions adapted from the Pipecat documentation, Copyright (c) 2024–2025 Daily, BSD-2-Clause (see apps/docs/LICENSE-pipecat-docs).
Whisper
Speech-to-text with Whisper. WhisperSTTService and WhisperSTTServiceMLX run Whisper locally on ONNX Runtime, and BaseWhisperSTTService is the base for Whisper-compatible APIs.
FunASR
Local multilingual speech-to-text with FunASRSTTService, running SenseVoiceSmall on ONNX Runtime. Strong on Chinese, with emotion and audio-event tags. No API key.