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

Speechify

Text-to-speech with Speechify: SpeechifyHttpTTSService streams audio and word timestamps over Server-Sent Events.

Overview

SpeechifyHttpTTSService posts each sentence to Speechify's /v1/audio/stream/with-timestamps endpoint and reads the Server-Sent Events it answers with: PCM audio chunks and word-level speech marks. The marks become word timestamps, so the bot's TTSTextFrames follow the audio.

Installation

bun add @pipedog/speechify
import { SpeechifyHttpTTSService } from "@pipedog/speechify/tts";

Prerequisites

  • A Speechify API account and an API key.
  • Pass the key as apiKey. The examples read it from SPEECHIFY_API_KEY.

Configuration

Prop

Type

Settings

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

SettingTypeDefaultDescription
modelstring"simba-3.5"Speech model, such as simba-3.5 or simba-3.0 (multilingual).
voicestring"geffen_32"Voice id.
languageLanguage | nullnullLanguage, sent as a tag such as en-US.
loudnessNormalizationboolean | nullnullNormalize the audio's loudness. Adds latency.
textNormalizationboolean | nullnullSpell out numbers, dates and similar tokens. Adds latency.
safetyIdentifierstring | nullnullA stable, opaque id for the end user (1 to 64 characters), so Speechify can limit one user instead of the workspace. Never an email address.
pronunciationsDict[] | nullnullHow specific words are spoken (up to 200), by IPA phones or a spoken alias. Applied on simba-3.5 in the languages Speechify lists for pronunciations, which excludes English.

Usage

tts.ts
import { TTSUpdateSettingsFrame } from "@pipedog/core/frames/frames";
import { SpeechifyHttpTTSService } from "@pipedog/speechify/tts";

const tts = new SpeechifyHttpTTSService({
  apiKey: process.env.SPEECHIFY_API_KEY ?? "",
  settings: new SpeechifyHttpTTSService.Settings({
    model: "simba-3.5",
    voice: "geffen_32",
    textNormalization: true,
  }),
});

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 SpeechifyHttpTTSService.Settings({ voice: "another-voice-id" }),
});

Notes

  • The sample rate must be one of Speechify's PCM rates (8000, 16000, 22050, 24000, 44100 or 48000). For any other pipeline rate the service asks for 24000 Hz, tags its audio frames with that rate, and the output transport resamples.
  • Requests pin Speechify's API version (Speechify-Version: 2026-09-30), and send Speechify-Caller: pipecat with the pipedog version.
  • Speechify marks the pieces of a hyphenated word separately. The service joins marks that touch in the text, so text-to-speech is one word timestamp.
  • A mid-stream speech.error event is reported as an error frame. A non-200 response is too.

Runtime notes

  • It uses the global fetch and reads the response as a stream, so it works on Bun, Node, Deno and Cloudflare Workers. Pass fetch to use another one (upstream takes an aiohttp session).
  • Tested against a local server that replays Speechify's event format, as upstream's tests do for the parsing, not against Speechify itself.
RuntimeWorksWhat it needs
Bun✅ yesNothing.
Node.js✅ yesNothing.
Deno✅ yesNothing.
Cloudflare Workers✅ yesNothing.

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

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