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

Deepgram

Streaming speech-to-text with DeepgramSTTService (Nova) and DeepgramFluxSTTService (Flux, with model-side turn detection).

Overview

Deepgram streams transcripts over a WebSocket. pipedog ports both of Pipecat's Deepgram speech-to-text services:

  • DeepgramSTTService: Deepgram's /v1/listen API (Nova models), with interim results, smart formatting, keyterms and the other Deepgram query options.
  • DeepgramFluxSTTService: Deepgram Flux (/v2/listen), which also detects the end of the user's turn, with optional eager end-of-turn events.

Installation

bun add @pipedog/deepgram
import { DeepgramSTTService } from "@pipedog/deepgram/stt";
import { DeepgramFluxSTTService } from "@pipedog/deepgram/flux/stt";

Prerequisites

  • A Deepgram account and an API key from the Deepgram console.
  • Pass the key as apiKey. The examples read it from DEEPGRAM_API_KEY.

DeepgramSTTService

Configuration

Prop

Type

Settings

Runtime-updatable settings, passed as settings: new DeepgramSTTService.Settings({...}). Any setting you leave out keeps the default below. Other Deepgram query parameters can go in extra.

SettingTypeDefaultDescription
modelstring"nova-3-general"Deepgram model.
languageLanguageLanguage.ENTranscription language.
interimResultsbooleantrueEmit InterimTranscriptionFrames.
punctuatebooleantrueAdd punctuation.
smartFormatbooleanfalseSmart formatting.
endpointingnumber | false | nullnullEndpointing sensitivity in ms, or false to disable.
utteranceEndMsnumber | nullnullSilence in ms before an utterance-end event.
keytermstring | string[] | nullnullKeyterms to boost.
keywordsstring | string[] | nullnullKeywords to boost.
diarizebooleanfalseSpeaker diarization.
detectEntitiesbooleanfalseNamed entity detection.
dictationbooleanfalseDictation mode.
numeralsbooleanfalseSpoken numbers as numerals.
profanityFilterboolean | nullnullFilter profanity.
redactstring | string[] | nullnullRedaction types.
replacestring | string[] | nullnullWord replacement rules.
searchstring | string[] | nullnullSearch terms to highlight.
versionstring | nullnullModel version; null leaves Deepgram on "latest".

Usage

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

const stt = new DeepgramSTTService({
  apiKey: process.env.DEEPGRAM_API_KEY ?? "",
  settings: new DeepgramSTTService.Settings({
    model: "nova-3-general",
    language: Language.EN,
    smartFormat: true,
    keyterm: ["pipedog", "Pipecat"],
  }),
});

Change settings mid-call with an STTUpdateSettingsFrame. The service reconnects with the new settings:

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

Notes

  • Emits InterimTranscriptionFrame while the user speaks and TranscriptionFrame for final results. A VADUserStoppedSpeakingFrame from the user aggregator's VAD makes it finalize early.
  • sampleRate defaults to the pipeline's input rate.
  • If the connection keeps failing quickly (an invalid key, say), the service stops retrying and pushes an error.

DeepgramFluxSTTService

Configuration

Prop

Type

Settings

SettingTypeDefaultDescription
modelstring"flux-general-en"Flux model; "flux-general-multi" for multilingual.
eagerEotThresholdnumber | nullnull (off)Threshold for eager end-of-turn and turn-resumed events.
eotThresholdnumber | nullnull (Deepgram: 0.7)End-of-turn confidence to finish a turn.
eotTimeoutMsnumber | nullnull (Deepgram: 5000)Finish a turn this long after speech, regardless of confidence.
keytermstring[][]Keyterms to boost.
minConfidencenumber | nullnullMinimum confidence to emit a TranscriptionFrame.
numeralsboolean | nullnullSpoken numbers as numerals.
profanityFilterboolean | nullnullMask profanity.
redactstring | nullnull"numbers" or "aggressive_numbers". Changing it reconnects.
languageHintsLanguage[] | nullnullBias detection (flux-general-multi only).

Usage

flux.ts
import { Language } from "@pipedog/core/transcriptions/language";
import { DeepgramFluxSTTService } from "@pipedog/deepgram/flux/stt";

const stt = new DeepgramFluxSTTService({
  apiKey: process.env.DEEPGRAM_API_KEY ?? "",
  settings: new DeepgramFluxSTTService.Settings({
    model: "flux-general-en",
    eagerEotThreshold: 0.5,
    eotThreshold: 0.8,
  }),
});

stt.addEventHandler("on_end_of_turn", async (_service, transcript: string) => {
  console.log("end of turn:", transcript);
});

Multilingual, with language hints:

const multilingual = new DeepgramFluxSTTService({
  apiKey: process.env.DEEPGRAM_API_KEY ?? "",
  settings: new DeepgramFluxSTTService.Settings({
    model: "flux-general-multi",
    languageHints: [Language.EN, Language.ES],
  }),
});

Event handlers

EventDescription
on_start_of_turnDeepgram detected the start of speech.
on_end_of_turnDeepgram detected the end of the turn.
on_eager_end_of_turnDeepgram predicted the end of the turn (with eagerEotThreshold).
on_turn_resumedThe user kept speaking after an eager end of turn.
on_updateA transcript update for the turn in progress.

Notes

  • Emits an InterimTranscriptionFrame on every Flux update and a TranscriptionFrame at the end of the turn.
  • Flux needs linear16 audio, which is what pipedog transports produce.

Runtime notes

RuntimeWorksWhat it needs
Bun✅ yesNothing.
Node.js✅ yesNothing.
Deno✅ yesNothing.
Cloudflare Workers✅ yesNothing.

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

Both services use the global WebSocket and send the key as an Authorization header on the handshake. That works on Bun, Node, Deno and Cloudflare Workers (where the socket is opened through fetch). Pass webSocketFactory to open the socket some other way, through a proxy for example. A standard WebSocket doesn't expose the HTTP status of a refused handshake, so DeepgramApiError is only raised when the runtime's error carries one.

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