Smallest AI
Realtime text-to-speech with SmallestTTSService, over Smallest AI's WebSocket API, with word timestamps.
Overview
SmallestTTSService: streams text over a WebSocket and pushes audio as it arrives. Fragments of one LLM turn share a continuation context, so the voice keeps its prosody across them. An interruption reconnects the socket.
Upstream page
Pipecat's documentation for the same service.
Source
packages/smallest/src/tts.ts.
Smallest AI docs
The text-to-speech API reference.
Installation
bun add @pipedog/smallestimport { SmallestTTSService } from "@pipedog/smallest/tts";Prerequisites
- A Smallest AI account and an API key from Smallest AI.
- Pass the key as
apiKey. The examples read it fromSMALLEST_API_KEY.
SmallestTTSService
Connects to wss://api.smallest.ai, with the key as a Bearer token on the handshake.
Configuration
Prop
Type
Settings
Runtime-updatable settings, passed as settings: new SmallestTTSService.Settings({...})
(SmallestTTSSettings). Any setting you leave out keeps the default below.
| Setting | Type | Default | Description |
|---|---|---|---|
model | "lightning_v3.1" | "lightning_v3.1_pro" | "lightning_v3.1_pro" | Speech model. |
voice | string | "meher" ("sophia" for lightning_v3.1) | Voice. |
language | Language | Language.EN | Language. |
speed | number | null | null | Speed multiplier, 0.5 to 2.0. null uses the API default. |
mathNotation | boolean | null | null | Read operators between digits as words ("2 + 2" as "two plus two"). |
contentFilter | "reject" | "flag" | "redact" | string | null | null | Check the text against a profanity list; "reject" fails the request, "flag" synthesizes and records the match, "redact" drops the matched term and speaks the rest. |
dateFormat | "EU" | "US" | string | null | null | Read all-numeric dates day-first ("EU") or month-first ("US"). |
Usage
import { TTSUpdateSettingsFrame } from "@pipedog/core/frames/frames";
import { Language } from "@pipedog/core/transcriptions/language";
import { SmallestTTSService } from "@pipedog/smallest/tts";
const tts = new SmallestTTSService({
apiKey: process.env.SMALLEST_API_KEY ?? "",
settings: new SmallestTTSService.Settings({ voice: "sophia", language: Language.EN }),
});Change settings mid-call with a TTSUpdateSettingsFrame:
// Queue it on the worker, or push it from a processor upstream of the service.
const update = new TTSUpdateSettingsFrame({
delta: new SmallestTTSService.Settings({ speed: 1.1 }),
});Notes
outputFormatis"pcm"by default; it is fixed when the service is created.wordTimestamps(on by default) makes the service push aligned per-wordTTSTextFrames. It works onmeher,devansh,kartik,maithili,liamandavery; other voices send no word events, so leaving it on is safe.maxBufferDelayMs(0 to 5000) bounds how long the server holds a continuation fragment.nullkeeps the server's 3000 ms.- The same package has Smallest AI's LLM and speech-to-text services.
| 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/smallest/package.json: ✅ means the compat smoke test passes on that runtime.
Runtime notes
- The WebSocket goes through the core
websocketConnect, with headers on the handshake. - Tested against local WebSocket servers, as upstream's tests do, not against Smallest AI itself.
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).