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/listenAPI (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.
Upstream page
Pipecat's documentation for the same services.
Source
packages/deepgram/src/stt.ts and flux/stt.ts.
Deepgram docs
Models, languages and query parameters.
Installation
bun add @pipedog/deepgramimport { 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 fromDEEPGRAM_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.
| Setting | Type | Default | Description |
|---|---|---|---|
model | string | "nova-3-general" | Deepgram model. |
language | Language | Language.EN | Transcription language. |
interimResults | boolean | true | Emit InterimTranscriptionFrames. |
punctuate | boolean | true | Add punctuation. |
smartFormat | boolean | false | Smart formatting. |
endpointing | number | false | null | null | Endpointing sensitivity in ms, or false to disable. |
utteranceEndMs | number | null | null | Silence in ms before an utterance-end event. |
keyterm | string | string[] | null | null | Keyterms to boost. |
keywords | string | string[] | null | null | Keywords to boost. |
diarize | boolean | false | Speaker diarization. |
detectEntities | boolean | false | Named entity detection. |
dictation | boolean | false | Dictation mode. |
numerals | boolean | false | Spoken numbers as numerals. |
profanityFilter | boolean | null | null | Filter profanity. |
redact | string | string[] | null | null | Redaction types. |
replace | string | string[] | null | null | Word replacement rules. |
search | string | string[] | null | null | Search terms to highlight. |
version | string | null | null | Model version; null leaves Deepgram on "latest". |
Usage
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
InterimTranscriptionFramewhile the user speaks andTranscriptionFramefor final results. AVADUserStoppedSpeakingFramefrom the user aggregator's VAD makes it finalize early. sampleRatedefaults 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
| Setting | Type | Default | Description |
|---|---|---|---|
model | string | "flux-general-en" | Flux model; "flux-general-multi" for multilingual. |
eagerEotThreshold | number | null | null (off) | Threshold for eager end-of-turn and turn-resumed events. |
eotThreshold | number | null | null (Deepgram: 0.7) | End-of-turn confidence to finish a turn. |
eotTimeoutMs | number | null | null (Deepgram: 5000) | Finish a turn this long after speech, regardless of confidence. |
keyterm | string[] | [] | Keyterms to boost. |
minConfidence | number | null | null | Minimum confidence to emit a TranscriptionFrame. |
numerals | boolean | null | null | Spoken numbers as numerals. |
profanityFilter | boolean | null | null | Mask profanity. |
redact | string | null | null | "numbers" or "aggressive_numbers". Changing it reconnects. |
languageHints | Language[] | null | null | Bias detection (flux-general-multi only). |
Usage
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
| Event | Description |
|---|---|
on_start_of_turn | Deepgram detected the start of speech. |
on_end_of_turn | Deepgram detected the end of the turn. |
on_eager_end_of_turn | Deepgram predicted the end of the turn (with eagerEotThreshold). |
on_turn_resumed | The user kept speaking after an eager end of turn. |
on_update | A transcript update for the turn in progress. |
Notes
- Emits an
InterimTranscriptionFrameon every Flux update and aTranscriptionFrameat the end of the turn. - Flux needs
linear16audio, which is what pipedog transports produce.
Runtime notes
| Runtime | Works | What it needs |
|---|---|---|
| Bun | ✅ yes | Nothing. |
| Node.js | ✅ yes | Nothing. |
| Deno | ✅ yes | Nothing. |
| Cloudflare Workers | ✅ yes | Nothing. |
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).