AssemblyAI
Streaming text-to-speech with per-word timings over AssemblyAI's Streaming TTS WebSocket API.
Overview
AssemblyAITTSService streams text to AssemblyAI's Streaming TTS WebSocket API over one session
and plays the audio as it arrives, with per-word timings for word-level TTSTextFrames. It is a
port of Pipecat's AssemblyAITTSService. AssemblyAI's speech-to-text services, in the same
package, are on the AssemblyAI speech-to-text page.
Installation
bun add @pipedog/assemblyaiPrerequisites
- An AssemblyAI account and API key, passed as
apiKey(the examples readASSEMBLYAI_API_KEY). A temporary token opens a single session, so it can't carry the service's reconnects and session renewals.
AssemblyAITTSService
Configuration
Prop
Type
The default URL is wss://tts.us.assemblyai.com/v1/ws. Use wss://tts.eu.assemblyai.com/v1/ws
to process text and audio in the EU. A cloned voice works only on the host of the zone it was
created in.
Settings
Runtime-updatable settings, passed as settings: new AssemblyAITTSService.Settings({...})
(AssemblyAITTSSettings). Settings you leave out keep their defaults. The session is configured
when it connects, so changing any of them reconnects.
| Setting | Type | Default | Description |
|---|---|---|---|
voice | string | null | "49c443a4-8a1d-5f7e-b70b-98bdbd9823c3" (Audrey) | Sent as voice_id: any voice by its ID, an AssemblyAI voice by its library slug such as aai-jane, or a cloned voice by the slug the dashboard shows. null leaves the voice to the server. |
language | Language | null | null | The language the session speaks: German, English, Spanish, French, Italian or Portuguese. Unset, the voice's own language. |
model | string | null | null | The model, such as assemblyai-tts-1. Unset, the language's default model. |
Usage
import { AssemblyAITTSService } from "@pipedog/assemblyai/tts";
import { TTSUpdateSettingsFrame } from "@pipedog/core/frames/frames";
import { Language } from "@pipedog/core/transcriptions/language";
// Speaks in Audrey, the default voice.
const tts = new AssemblyAITTSService({ apiKey: process.env.ASSEMBLYAI_API_KEY ?? "" });Pick a voice and a region:
// A library voice by its slug, processed in the EU.
const eu = new AssemblyAITTSService({
apiKey: process.env.ASSEMBLYAI_API_KEY ?? "",
url: "wss://tts.eu.assemblyai.com/v1/ws",
settings: new AssemblyAITTSService.Settings({ voice: "aai-jane", language: Language.EN }),
});Change settings mid-call with a TTSUpdateSettingsFrame:
// The session is configured at connect time, so a new voice reconnects.
const update = new TTSUpdateSettingsFrame({
delta: new AssemblyAITTSService.Settings({ voice: "987db62e-a2c2-569a-9c4d-82460cdea1bd" }),
});Notes
- Each sentence is sent as its own request (a
Generate, then aFlush). WithTextAggregationMode.TOKEN, the turn's text streams as it is generated and is flushed when the turn ends. Text longer than the session's limit is split acrossGeneratemessages. - Interruptions send
Cancel, which stops synthesis in flight and keeps the session open. - The service keeps an idle session open with a
KeepAliveevery 30 seconds, replaces a session between requests before its one-hour limit, and waits as long as an error asks before reconnecting. sampleRateleft out uses the pipeline's output rate.
Runtimes
| 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/assemblyai/package.json: ✅ means the compat smoke test passes on that runtime.
The service uses the global WebSocket (through core's websocketConnect, which sends the
Authorization header on the handshake on Cloudflare Workers too). No AssemblyAI SDK is needed.
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).