# Nari Labs narration

Use `nari-tts` alongside ElevenLabs through VideoClaw's existing narration and dialogue commands. Narration produces `artifacts/audio/narration.wav` and `artifacts/narration.json`, ready for the existing audio assembly path. Existing backend priority is unchanged; select Nari explicitly with `--backend nari-tts`.

## Secure setup

Revoke the key previously pasted into chat in your Nari account and create a replacement. Never reuse it, commit it, put it in a prompt or pass it as a CLI argument.

Configure `NARI_API_KEY` using your environment or the workspace `.env.local` secrets file, outside the installed package. The CLI loads this file from the workspace selected by `--root`. Keep it excluded from version control. Library callers can pass `env: { NARI_API_KEY: secret }` to the narration API; an explicit environment is authoritative.

| Setting | Default | Purpose |
|---|---|---|
| `NARI_API_KEY` | Required | Nari bearer credential |
| `NARI_TTS_MODEL` | `qwen3-tts:free` | One of `qwen3-tts:free`, `qwen3-tts-fast:free`, `qwen3-tts`, `qwen3-tts-fast` |
| `--voice` | `diana` | Case-sensitive model-specific voice ID, such as `leon` |

The selected voice determines the language. VideoClaw omits `language` so Nari uses that voice's assigned language; it does not translate the script. Consult the model's current voice catalogue before selecting a voice. Partner models require access and credits; free models have usage limits.

## Generate narration

For an existing project, after configuring a replacement key:

```sh
vclaw video narrate --project my-film --backend nari-tts \
  --voice diana --text "Welcome to our film." --confirm-spend
```

Add `--root /path/to/workspace` when using a non-default workspace. Use `--text-file script.txt` for a script file. The existing generation confirmation gate also applies to free models.

For an offline CLI check, use a dummy environment value and a dry run:

```sh
NARI_API_KEY=offline-placeholder vclaw video narrate --project my-film \
  --backend nari-tts --text "Welcome to our film." --dry-run
```

A dry run writes a zero-byte placeholder and estimated duration, not playable audio. Run it in a test project: it updates narration artefacts. The backend itself needs no credential in dry-run mode, but the narration command's existing availability gate requires a non-empty value.

## Limits and failure behaviour

- Each trimmed script must contain 1–2,048 Unicode code points. Split longer scripts at sentence boundaries; this adapter does not silently truncate or split them. Each dialogue turn uses its own request.
- Requests use `POST https://api.narilabs.com/v1/audio/speech`, complete-response WAV, and a 120-second deadline including response consumption. JSON bodies must fit within 64 KiB.
- Successful audio is validated as 24 kHz, PCM16 little-endian mono WAV. Duration comes from the delivered sample count, not a text-length estimate. Narration's existing duration probe remains in place.
- HTTP, network, timeout and invalid-audio failures use the existing `tts_failed` error. Errors include HTTP status where available, without API response bodies, credentials or raw network exception text.
- Generation is not retried automatically because a lost response may already have consumed allowance. Check Nari request logs and quota before retrying. Authentication failures need a valid key; 403 may require model access; 429 requires checking concurrency/daily limits; 5xx may be transient.
- Explicit `--backend nari-tts` never falls back to another provider. Without explicit selection, the existing narration fallback order may reach Nari when its credential is configured.

## Verification

Offline coverage is in `src/tests/audio-platform-tts-nari.test.ts`. After `npm run build`, run:

```sh
node --test dist/tests/audio-platform-tts-nari.test.js
```

An optional live smoke test is the generation command above, run with a fresh key and a test project. Play the resulting WAV and check its duration before treating live voice quality as verified. Offline tests do not prove account access or live voice quality.

API contract checked 13 September 2026: [speech generation](https://docs.narilabs.com/generate-speech), [voices](https://docs.narilabs.com/voices), [models](https://docs.narilabs.com/models-and-pricing), [limits](https://docs.narilabs.com/rate-limits).
