# Hume

> Text-to-speech with HumeTTSService, Hume's Octave voices over HTTP streaming, with word timestamps.

Source: https://polvallverdu.github.io/pipedog/docs/services/tts/hume/



## Overview [#overview]

Hume's Octave models give speech acting directions and expressive control. pipedog ports
Pipecat's **`HumeTTSService`**: it posts each request to Hume's `tts/stream/json` endpoint and
reads the newline-delimited JSON stream back, emitting 48 kHz PCM audio and word-level timestamps.

<Cards>
  <Card title="Upstream page" href="https://docs.pipecat.ai/api-reference/server/services/tts/hume">
    Pipecat's documentation for the same service.
  </Card>

  <Card title="Source" href="https://github.com/polvallverdu/pipedog/tree/main/packages/hume/src">
    `packages/hume/src/tts.ts`.
  </Card>

  <Card title="Hume docs" href="https://dev.hume.ai/reference/text-to-speech-tts/synthesize-json-streaming">
    The streaming endpoint, voices and Octave versions.
  </Card>
</Cards>

## Installation [#installation]

```bash
bun add @pipedog/hume
```

```ts
import { HumeTTSService } from "@pipedog/hume/tts";
```

## Prerequisites [#prerequisites]

* A Hume account and an API key from the [Hume platform](https://platform.hume.ai).
* A voice id, set as `voice`. Voice names are not supported, and without a voice the service
  reports an error.
* Pass the key as `apiKey`, or set the `HUME_API_KEY` environment variable.

## HumeTTSService [#humettsservice]

### Configuration [#configuration]

| Option | Type | Required | Description |
|---|---|---|---|
| `apiKey` | `string \| null \| undefined` | no | Hume API key. If omitted, reads the `HUME_API_KEY` environment variable. |
| `fetch` | `{ (input: RequestInfo \| URL, init?: RequestInit): Promise<Response>; (input: string \| URL \| Request, init?: RequestInit): Promise<Response>; } \| null \| undefined` | no | `fetch` used for HTTP requests. Defaults to the global `fetch`. DIVERGENCE: replaces the Hume SDK's HTTP client. |
| `baseUrl` | `string \| undefined` | no | Base URL of the Hume API. Defaults to "https://api.hume.ai". |
| `settings` | `HumeTTSSettings \| null \| undefined` | no | Runtime-updatable settings. |
| `name` | `string \| null \| undefined` | no | Custom name; defaults to `ClassName#count`. |
| `taskManager` | `BaseTaskManager \| null \| undefined` | no | Task manager for handling tasks. |
| `enableDirectMode` | `boolean \| undefined` | no | Process frames immediately instead of using internal queues. |
| `metrics` | `FrameProcessorMetrics \| null \| undefined` | no | Optional metrics collector for this processor. |
| `textAggregationMode` | `TextAggregationMode \| null \| undefined` | no | How to aggregate incoming text before synthesis. `TextAggregationMode.SENTENCE` (default) buffers until sentence boundaries, `TextAggregationMode.TOKEN` streams tokens directly for lower latency. |
| `pushTextFrames` | `boolean \| undefined` | no | Whether to push TextFrames and LLMFullResponseEndFrames. |
| `pushStopFrames` | `boolean \| undefined` | no | Whether to automatically push TTSStoppedFrames. |
| `pushStartFrame` | `boolean \| undefined` | no | Whether to automatically create audio contexts and push TTSStartedFrames. When true, the base class handles `createAudioContext` and yields `TTSStartedFrame` before each synthesis call, so `runTts` implementations do not need to. |
| `stopFrameTimeoutS` | `number \| undefined` | no | Idle time before pushing TTSStoppedFrame when pushStopFrames is true. |
| `pushSilenceAfterStop` | `boolean \| undefined` | no | Whether to push silence audio after TTSStoppedFrame. |
| `silenceTimeS` | `number \| undefined` | no | Duration of silence to push when pushSilenceAfterStop is true. |
| `pauseFrameProcessing` | `boolean \| undefined` | no | Whether to hold incoming frames after a turn until its audio contexts end. Needed by services whose audio doesn't carry its request's context ID. |
| `maxConsecutiveZeroAudioContexts` | `number \| undefined` | no | How many consecutive TTS contexts may complete without producing any audio before the service is reported unable to do its job. Catches a provider that accepts requests and stays silent — an unknown voice ID, say — which no error ever surfaces. Every silent context reports an error the service can carry on from, whatever the limit is; on reaching the limit the service reports a permanent error instead, stops being given work, and the pipeline worker applies its `ProcessorUnusablePolicy`. Set to 0 to report silent contexts without ever writing the service off. |
| `appendTrailingSpace` | `boolean \| undefined` | no | Whether to append a trailing space to text before sending to TTS. This helps prevent some TTS services from vocalizing trailing punctuation (e.g., "dot"). Only applied in sentence aggregation mode; when streaming tokens, the incoming text's own whitespace is preserved. |
| `sampleRate` | `number \| null \| undefined` | no | Output sample rate for generated audio. |
| `skipTextTypes` | `string[] \| null \| undefined` | no | List of text types that should not be spoken. |
| `textTransforms` | `[string, TextTransform][] \| null \| undefined` | no | A list of TextTransforms to transform text just before sending it to TTS. Each TextTransform takes the aggregated text and its type, and returns the transformed text. To register, provide a list of tuples of `[textType \| "*", transformFunction]`. |
| `transportDestination` | `string \| null \| undefined` | no | Destination for generated audio frames. |
| `reuseContextIdWithinTurn` | `boolean \| undefined` | no | Whether the service should reuse context IDs within the same turn. |
| `audioCache` | `TTSAudioCacheStore \| null \| undefined` | no | Where to keep synthesized audio for reuse (e.g. a shared `TTSAudioCache`). Text whose audio is in the cache is served from it, with no request to the provider. Lines get there through `warmAudioCache()`, and also from live synthesis when `cacheSynthesizedAudio` allows it. Only services that yield their audio from `runTts` (HTTP and streaming-RPC services, see `supportsAudioCache`) use it, and only in sentence aggregation mode. Defaults to null (no cache). pipedog only. |
| `cacheSynthesizedAudio` | `boolean \| ((text: string) => boolean) \| undefined` | no | Whether audio synthesized live is stored in `audioCache`, or a function that decides per text. Defaults to false: only warmed lines are stored, since a generated reply can repeat what the user said. pipedog only. |
| `audioCacheNamespace` | `string \| undefined` | no | Extra part of the cache key, for constructor options that change the audio but are not in `settings`. pipedog only. |

### Settings [#settings]

Runtime-updatable settings, passed as `settings: new HumeTTSService.Settings({...})`.

| Setting           | Type             | Default | Description                                                                         |
| ----------------- | ---------------- | ------- | ----------------------------------------------------------------------------------- |
| `voice`           | `string \| null` | `null`  | Hume voice id. Required to synthesize.                                              |
| `description`     | `string \| null` | `null`  | Natural-language acting directions, up to 100 characters. Selects Octave version 1. |
| `speed`           | `number \| null` | `null`  | Speaking-rate multiplier, 0.5 to 2.0.                                               |
| `trailingSilence` | `number \| null` | `null`  | Seconds of silence to add at the end, 0 to 5.                                       |
| `temperature`     | `number \| null` | `null`  | Sampling temperature. Hume's per-model default applies when unset.                  |

### Usage [#usage]

```ts title="tts.ts"
import { TTSUpdateSettingsFrame } from "@pipedog/core/frames/frames";
import { HumeTTSService } from "@pipedog/hume/tts";

const tts = new HumeTTSService({
  // Defaults to the HUME_API_KEY environment variable.
  apiKey: process.env.HUME_API_KEY,
  settings: new HumeTTSService.Settings({
    // A Hume voice id. Voice names are not supported.
    voice: "your-voice-id",
    speed: 1.1,
    trailingSilence: 0.3,
  }),
});
```

Acting directions and temperature:

```ts
// Acting directions switch Hume to Octave version 1.
const acting = new HumeTTSService({
  apiKey: process.env.HUME_API_KEY,
  settings: new HumeTTSService.Settings({
    voice: "your-voice-id",
    description: "warm, unhurried",
    temperature: 0.7,
  }),
});
```

Change settings mid-call with a `TTSUpdateSettingsFrame`:

```ts
// Queue it on the worker, or push it from a processor upstream of the service.
// It applies from the next request.
const update = new TTSUpdateSettingsFrame({
  delta: new HumeTTSService.Settings({ voice: "another-voice-id", speed: 0.9 }),
});
```

### Event handlers [#event-handlers]

Inherited from `TTSService`:

| Event            | Description                                     |
| ---------------- | ----------------------------------------------- |
| `on_tts_request` | A text chunk is about to be sent for synthesis. |

### Notes [#notes]

* Hume streams at 48 kHz. Another `sampleRate` is accepted with a warning, and the service labels
  the frames with it without resampling.
* Audio is buffered until it reaches a full chunk, to avoid glitches.
* Instant mode is always on, and word timestamps are always requested. Octave version 2 is used,
  or version 1 when a `description` is set.
* Word timestamps keep a running offset across the utterances of a turn. It resets on an
  interruption and when the context ends.

## Runtime notes [#runtime-notes]

* The service calls Hume's HTTP endpoint with `fetch` (the global one unless you pass `fetch`)
  instead of Hume's SDK, so it runs on Bun, Node, Deno and Cloudflare Workers. The request and
  response formats follow the `hume` TypeScript SDK and Hume's API reference.
* Requests carry `X-Hume-Client-Name: pipedog` and the pipedog version, where Pipecat sends its
  own name and version.
* Not ported: the deprecated `InputParams`, `update_setting()` and the `voiceId` and `params`
  constructor options. Use `settings`.

| 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/hume/package.json`: ✅ means the compat smoke test passes on that runtime.
