Skip to main content

TTS

Charivo's TTS layer combines @charivo/tts with a concrete player.

For production browser apps, use the remote player with a server route backed by @charivo/server/openai.

@charivo/tts
@charivo/tts/remote
your /api/tts route
@charivo/server/openai

Basic Setup

import { Charivo } from "@charivo/core";
import { createTTSManager } from "@charivo/tts";
import { createRemoteTTSPlayer } from "@charivo/tts/remote";

const charivo = new Charivo();

charivo.attachTTS(
createTTSManager(createRemoteTTSPlayer({ apiEndpoint: "/api/tts" })),
);

Player Choices

Remote

  • @charivo/tts/remote
  • production-oriented browser path
  • sends text and voice options to your own API route

Direct OpenAI

  • @charivo/tts/openai
  • useful for local development and testing
  • exposes credentials to the browser

Browser-Native

  • @charivo/tts/web
  • built on the Web Speech API
  • useful for prototypes and zero-server flows
  • voice behavior depends on browser and OS support

What @charivo/tts Owns

  • playback lifecycle
  • lip-sync analysis and event emission
  • player capability normalization through playbackMode and optional audioMimeType

TTSManager intentionally uses setEventEmitter(...), not the full event bus. It emits TTS lifecycle and lip-sync events back into core, but it does not subscribe to upstream Charivo events.

For "audio" playback mode, the manager analyzes the audio element it creates from the generated bytes with the shared core lip-sync analyzer (createLipSyncAnalyzer from @charivo/core) and emits tts:lipsync:update. "audio" mode requires the player to implement generateAudio(); createTTSManager(player) throws an explicit error otherwise. Players that only implement speak() (e.g. the Web Speech API) must use "web-speech" mode, whose lip-sync comes from a text-driven simulation instead of real audio analysis.

Call ttsManager.prepareAudio?.() from a user-gesture handler before the first speak() so the lip-sync AudioContext starts cleanly on mobile browsers. Call ttsManager.dispose?.() to release lip-sync audio resources if your app tears a TTSManager down outside Charivo.dispose(), which already calls it automatically.

Provider Route

The remote player usually pairs with @charivo/server/openai on the server:

const provider = createOpenAITTSProvider({
apiKey: process.env.OPENAI_API_KEY!,
defaultVoice: "marin",
defaultModel: "gpt-4o-mini-tts",
});

const audio = await provider.generateSpeech(text, {
voice: "marin",
rate: 1,
});

Alternatives

  • Use @charivo/tts/web when you want no backend and browser variability is acceptable.
  • Use @charivo/tts/openai when you are debugging OpenAI TTS behavior directly.
  • Skip TTS when text chat is enough for the current experience.

References