pipedog is an unofficial community port of Pipecat, not affiliated with Daily.
pipedog
Speech-to-text

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.

Overview

  • FunASRSTTService: a segmented STT service that transcribes each speech segment, cut by the pipeline's VAD, with SenseVoiceSmall on your machine. SenseVoice is multilingual (Chinese, Cantonese, English, Japanese, Korean), with strong Chinese accuracy and fast non-autoregressive inference. No account, no API key.
  • AutoModel (@pipedog/funasr/funasr): the engine. Upstream runs the model with the funasr Python package (PyTorch). This one runs the same weights on ONNX Runtime through @pipedog/onnx, and mirrors the part of funasr the service uses: AutoModel, generate() and richTranscriptionPostprocess(). Its transcripts match sherpa-onnx's for the same model.

Installation

bun add @pipedog/funasr onnxruntime-node

onnxruntime-node is an optional peer of @pipedog/onnx. onnxruntime-web@1.30.0 (WebAssembly) works too, about 10x slower (1.2 s instead of 0.11 s for a 7 s clip on an M4 Pro).

import { FunASRSTTService } from "@pipedog/funasr/stt";

What you need

Modelsherpa-onnx's ONNX export of iic/SenseVoiceSmall, from Hugging Face csukuangfj/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17 (pinned revision): model.int8.onnx (239 MB, the default) or model.onnx (938 MB, with modelOptions: { quantized: false }), plus tokens.txt (316 KB)
DownloadAutomatic, once, when the pipeline starts (or on the first transcription). No account or token needed
Cache$PIPEDOG_CACHE_DIR/funasr, else $XDG_CACHE_HOME/pipedog/funasr, else ~/.cache/pipedog/funasr, or modelOptions: { cacheDir }
Input16 kHz, 16-bit mono PCM, and a VAD in the pipeline

To use local files instead, set the model setting to a directory holding model.int8.onnx (or model.onnx) and tokens.txt, or to the .onnx file's path with tokens.txt next to it, or pass explicit files:

// A directory holding model.int8.onnx (or model.onnx) and tokens.txt...
const fromDir = new FunASRSTTService({
  settings: new FunASRSTTService.Settings({ model: "/models/sense-voice" }),
});
// ...or explicit files.
const fromFiles = new FunASRSTTService({
  modelOptions: { modelFile: "/models/model.int8.onnx", tokens: "/models/tokens.txt" },
});

Runtimes

RuntimeWorksWhat it needs
Bun✅ yesonnxruntime-node (or onnxruntime-web) and the SenseVoiceSmall ONNX export (model.int8.onnx 239 MB + tokens.txt), downloaded once from Hugging Face to ~/.cache/pipedog/funasr.
Node.js✅ yesonnxruntime-node (or onnxruntime-web) and the SenseVoiceSmall ONNX export (model.int8.onnx 239 MB + tokens.txt), downloaded once from Hugging Face to ~/.cache/pipedog/funasr.
Deno✅ yesonnxruntime-node (or onnxruntime-web) and the SenseVoiceSmall ONNX export (model.int8.onnx 239 MB + tokens.txt), downloaded once from Hugging Face to ~/.cache/pipedog/funasr.
Cloudflare Workers❌ noonnxruntime-node (or onnxruntime-web) and the SenseVoiceSmall ONNX export (model.int8.onnx 239 MB + tokens.txt), downloaded once from Hugging Face to ~/.cache/pipedog/funasr. Not supported: the model (239 MB int8) exceeds Workers' memory and bundle limits.

Generated from pipecat.runtimes and pipecat.compat in packages/funasr/package.json: ✅ means the compat smoke test passes on that runtime.

Cloudflare Workers is not supported: the model (239 MB as int8) doesn't fit a Worker's 128 MB of memory or its 10 MB bundle limit.

FunASRSTTService

Configuration

Prop

Type

modelOptions (pipedog only) takes cacheDir, quantized, modelFile, tokens, backend, shareSession and fetch.

Settings

Runtime-updatable settings, passed as settings: new FunASRSTTService.Settings({...}) (FunASRSTTSettings). Any setting you leave out keeps the default below.

SettingTypeDefaultDescription
modelstring"iic/SenseVoiceSmall""iic/SenseVoiceSmall" or "FunAudioLLM/SenseVoiceSmall" to download the model, or a local directory or .onnx path.
languageLanguageLanguage.ENZH, EN, JA, KO or YUE. Any other language means auto-detect.
useItnbooleantrueInverse text normalization: punctuation and digits ("nine" becomes "9").

Usage

stt.ts
import { STTUpdateSettingsFrame } from "@pipedog/core/frames/frames";
import { Language } from "@pipedog/core/transcriptions/language";
import { FunASRSTTService } from "@pipedog/funasr/stt";

// Downloads SenseVoiceSmall (model.int8.onnx, 239 MB, and tokens.txt) on first start.
const stt = new FunASRSTTService({
  settings: new FunASRSTTService.Settings({ language: Language.ZH, useItn: true }),
});

Change the language mid-call with an STTUpdateSettingsFrame:

// Queue it on the worker, or push it from a processor upstream of the service.
const update = new STTUpdateSettingsFrame({
  delta: new FunASRSTTService.Settings({ language: Language.JA }),
});

The engine works on its own too. generate() returns FunASR's raw text with its <|...|> language, emotion and event tags, and richTranscriptionPostprocess() strips them:

import { AutoModel, richTranscriptionPostprocess } from "@pipedog/funasr/funasr";

const model = new AutoModel({ model: "iic/SenseVoiceSmall" });
const samples = new Float32Array(16000); // 16 kHz mono audio in [-1, 1]
const [result] = await model.generate({ input: samples, language: "auto", useItn: true });
if (result) {
  console.log(result.text); // "<|en|><|NEUTRAL|><|Speech|><|withitn|>..."
  console.log(richTranscriptionPostprocess(result.text)); // the text without the tags
}

Notes

  • Emits one TranscriptionFrame per segment, with the detected language. There are no interim results.
  • The front end computes FunASR's WavFrontend features (Kaldi fbank, LFR, CMVN from the model's metadata), within 2e-4 of kaldi-native-fbank's, then decodes with CTC greedy search, as FunASR does.
  • FunASR's PyTorch checkpoints and other ModelScope model ids are not supported.

Differences from upstream

  • The model runs on onnxruntime on the CPU, not PyTorch. device is accepted, but "cuda" doesn't select a GPU.
  • The model downloads and loads in start() (or on the first transcription), not in the constructor.
  • No dither in the front end (FunASR's WavFrontend adds dither 1.0 by default), so results are deterministic.
  • modelOptions is a pipedog option, and the engine's options are camelCase (disableUpdate, useItn).

Licenses

  • @pipedog/funasr: BSD 2-Clause. postprocess_utils.ts is adapted from FunASR (MIT, Copyright (c) 2022 Alibaba).
  • SenseVoiceSmall weights: the FunASR model license (attribution required; check its terms for your use). The ONNX export is by k2-fsa/sherpa-onnx.

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).

On this page