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

Async

Text-to-speech with Async: AsyncAITTSService over WebSocket and AsyncAIHttpTTSService over HTTP streaming.

Overview

  • AsyncAITTSService: keeps one WebSocket open and sends each sentence as a forced transcript on its own context, closing the context when its audio has played or the bot is interrupted.
  • AsyncAIHttpTTSService: one HTTP request per sentence. The audio is collected and pushed as one frame.

Installation

bun add @pipedog/asyncai
import { AsyncAIHttpTTSService, AsyncAITTSService } from "@pipedog/asyncai/tts";

Prerequisites

  • An Async account, an API key and the UUID of a voice.
  • Pass the key as apiKey. The examples read it from ASYNC_API_KEY.

AsyncAITTSService

Connects to wss://api.async.com/text_to_speech/websocket/ws, with the key and API version as query parameters.

Configuration

Prop

Type

Settings

Runtime-updatable settings, passed as settings: new AsyncAITTSService.Settings({...}) (AsyncAITTSSettings). Any setting you leave out keeps the default below. A change to model, voice or language opens a new session, because they are sent once, in the init message.

SettingTypeDefaultDescription
modelstring"async_flash_v1.5"Speech model.
voicestring | nullnullVoice UUID.
languageLanguage | nullnullLanguage, sent as a two-letter code.

Usage

tts.ts
import { AsyncAIHttpTTSService, AsyncAITTSService } from "@pipedog/asyncai/tts";
import { TTSUpdateSettingsFrame } from "@pipedog/core/frames/frames";

const tts = new AsyncAITTSService({
  apiKey: process.env.ASYNC_API_KEY ?? "",
  settings: new AsyncAITTSService.Settings({
    model: "async_flash_v1.5",
    voice: "your-voice-uuid",
    language: "en",
  }),
});

Change settings mid-call with a TTSUpdateSettingsFrame:

// Opens a new session, since the voice is part of the init message.
const update = new TTSUpdateSettingsFrame({
  delta: new AsyncAITTSService.Settings({ voice: "another-voice-uuid" }),
});

Event handlers

EventDescription
on_connectedThe WebSocket connected.
on_disconnectedThe WebSocket closed.
on_connection_errorThe connection failed.

AsyncAIHttpTTSService

Posts each sentence to https://api.async.com/text_to_speech/streaming.

Configuration

Prop

Type

It takes the same settings as the WebSocket service.

Usage

const httpTts = new AsyncAIHttpTTSService({
  apiKey: process.env.ASYNC_API_KEY ?? "",
  settings: new AsyncAIHttpTTSService.Settings({ voice: "your-voice-uuid" }),
});

Notes

  • Audio is raw pcm_s16le by default (encoding and container change that) at the pipeline's sample rate.
  • The WebSocket sends a blank transcript every 10 seconds to keep the connection open.

Runtime notes

  • The WebSocket opens through the core websocketConnect. Async takes the key in the URL, so no header is needed. The HTTP service uses the global fetch; pass fetch to use another one (upstream takes an aiohttp session). Both work on Bun, Node, Deno and Cloudflare Workers.
  • The deprecated params (InputParams), voiceId, model and aggregateSentences options are not ported. Use settings and textAggregationMode.
  • Tested against local servers, as upstream's tests do for the settings updates, not against Async itself.
RuntimeWorksWhat it needs
Bun✅ yesNothing.
Node.js✅ yesNothing.
Deno✅ yesNothing.
Cloudflare Workers✅ yesNothing.

Generated from pipecat.runtimes and pipecat.compat in packages/asyncai/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