144 lines
7.3 KiB
Markdown
144 lines
7.3 KiB
Markdown
# @suaveplan/voice-elevenlabs - ElevenLabs domain adapter for @suaveplan/voice: TTS, STT, voice repository, sound effects, and voice isolation engines implemented by delegating to @suaveplan/third-party-elevenlabs.
|
|
|
|
ElevenLabs domain adapter for the `@suaveplan/voice` interface family.
|
|
|
|
This package implements every `@suaveplan/voice` engine contract —
|
|
`VoiceSynthesizer`, `TranscriptionEngine`, `VoiceRepository`,
|
|
`SoundEffectEngine`, `VoiceIsolationEngine` — by delegating to the typed
|
|
HTTP/WebSocket transport in `@suaveplan/third-party-elevenlabs`. It owns
|
|
DTO ↔ domain mapping, ElevenLabs-specific error remapping into the
|
|
`VOICE.*` namespace, multipart/stream plumbing for the voice surface,
|
|
and a composite factory that wires every engine against a shared
|
|
transport.
|
|
|
|
<!-- begin:auto-docs -->
|
|
## Documentation tree
|
|
|
|
- [factory](./src/factory/create-elevenlabs-voice.md) — Composition root for the `@suaveplan/voice` engine adapters that target ElevenLabs. One call, one shared transport, fiv…
|
|
- [create-elevenlabs-voice](./src/factory/create-elevenlabs-voice.md) — Composition root for the `@suaveplan/voice` engine adapters that target ElevenLabs. One call, one shared transport, fiv…
|
|
- [models](./src/models/models.md) — ElevenLabs model catalog. Lists every model the API key has access to, along with capability flags (TTS / voice convers…
|
|
- [models](./src/models/models.md) — ElevenLabs model catalog. Lists every model the API key has access to, along with capability flags (TTS / voice convers…
|
|
- [sound-effects](./src/sound-effects/sound-effects.md) — ElevenLabs implementation of `@suaveplan/voice`'s `SoundEffectEngine` interface. Posts a JSON body to `POST /v1/sound-g…
|
|
- [sound-effects](./src/sound-effects/sound-effects.md) — ElevenLabs implementation of `@suaveplan/voice`'s `SoundEffectEngine` interface. Posts a JSON body to `POST /v1/sound-g…
|
|
- [speech-to-speech](./src/speech-to-speech/speech-to-speech.md) — ElevenLabs Speech-to-Speech (voice conversion) adapter. Given source audio and a target `voiceId`, produces audio that…
|
|
- [speech-to-speech](./src/speech-to-speech/speech-to-speech.md) — ElevenLabs Speech-to-Speech (voice conversion) adapter. Given source audio and a target `voiceId`, produces audio that…
|
|
- [stt](./src/stt/stt.md) — ElevenLabs implementation of `@suaveplan/voice`'s `TranscriptionEngine` interface. Posts the audio as multipart form-da…
|
|
- [stt](./src/stt/stt.md) — ElevenLabs implementation of `@suaveplan/voice`'s `TranscriptionEngine` interface. Posts the audio as multipart form-da…
|
|
- [tts](./src/tts/tts.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceSynthesizer` interface. Posts to `/v1/text-to-speech/{voice_id}…
|
|
- [tts](./src/tts/tts.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceSynthesizer` interface. Posts to `/v1/text-to-speech/{voice_id}…
|
|
- [voice-isolation](./src/voice-isolation/voice-isolation.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceIsolationEngine` interface. Posts the audio as multipart form-d…
|
|
- [voice-isolation](./src/voice-isolation/voice-isolation.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceIsolationEngine` interface. Posts the audio as multipart form-d…
|
|
- [voices](./src/voices/voices.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceRepository` interface. Lists voices via `GET /v1/voices` and lo…
|
|
- [voices](./src/voices/voices.md) — ElevenLabs implementation of `@suaveplan/voice`'s `VoiceRepository` interface. Lists voices via `GET /v1/voices` and lo…
|
|
<!-- end:auto-docs -->
|
|
|
|
## Install
|
|
|
|
```sh
|
|
bun add @suaveplan/voice-elevenlabs @suaveplan/voice
|
|
```
|
|
|
|
## Quick start
|
|
|
|
```ts
|
|
import { createElevenLabsVoice } from "@suaveplan/voice-elevenlabs";
|
|
|
|
const { tts, voices } = createElevenLabsVoice({
|
|
apiKey: process.env.ELEVENLABS_KEY!,
|
|
});
|
|
|
|
const all = await voices.list();
|
|
const result = await tts.synthesize({
|
|
text: "hello",
|
|
voiceId: all.voices[0]!.id,
|
|
});
|
|
```
|
|
|
|
## Modules
|
|
|
|
| Subpath | Engine | `@suaveplan/voice` contract |
|
|
| --- | --- | --- |
|
|
| `./tts/tts` | `ElevenLabsVoiceSynthesizer` | `VoiceSynthesizer` |
|
|
| `./stt/stt` | `ElevenLabsTranscriptionEngine` | `TranscriptionEngine` |
|
|
| `./voices/voices` | `ElevenLabsVoiceRepository` | `VoiceRepository` |
|
|
| `./sound-effects/sound-effects` | `ElevenLabsSoundEffectEngine` | `SoundEffectEngine` |
|
|
| `./voice-isolation/voice-isolation` | `ElevenLabsVoiceIsolationEngine` | `VoiceIsolationEngine` |
|
|
| `./factory/create-elevenlabs-voice` | `createElevenLabsVoice` | bundle factory |
|
|
|
|
## Composing with other ElevenLabs surfaces
|
|
|
|
The factory accepts a pre-constructed `ElevenLabsClient` from
|
|
`@suaveplan/third-party-elevenlabs` so the same transport (with its
|
|
retry, rate-limit, OTel, base URL, and event-bus configuration) can be
|
|
shared with ElevenLabs-specific surfaces that are *not* part of the
|
|
voice domain — for example the model catalogue or the
|
|
speech-to-speech (voice-conversion) endpoint:
|
|
|
|
```ts
|
|
import {
|
|
ElevenLabsClient,
|
|
ElevenLabsModelCatalog,
|
|
ElevenLabsSpeechToSpeech,
|
|
} from "@suaveplan/third-party-elevenlabs";
|
|
import { createElevenLabsVoice } from "@suaveplan/voice-elevenlabs";
|
|
|
|
const client = new ElevenLabsClient({
|
|
apiKey: process.env.ELEVENLABS_KEY!,
|
|
baseUrl: "https://eu.api.elevenlabs.io",
|
|
});
|
|
const voice = createElevenLabsVoice({ client });
|
|
const models = new ElevenLabsModelCatalog(client);
|
|
const s2s = new ElevenLabsSpeechToSpeech(client);
|
|
```
|
|
|
|
## Error remapping
|
|
|
|
Every `ElevenLabsApiError` subclass raised by the underlying transport
|
|
is remapped into a `VoiceError` from `@suaveplan/voice`, preserving the
|
|
original via `.cause`. The full table is documented inline at the call
|
|
sites; a representative subset:
|
|
|
|
| Third-party error | Voice domain error |
|
|
| --- | --- |
|
|
| `UnauthorizedError`, `ForbiddenError` | `ProviderNotConfiguredError` |
|
|
| `RequestNotFoundError` (from `voices.get`) | resolves to `null` (no throw) |
|
|
| `RequestValidationFailedError`, `RequestInvalidError` | `VoiceValidationError` |
|
|
| `RateLimitExceededError`, `RateLimitQuotaExhaustedError` | `ProviderRateLimitedError` (with `retryAfterMs`) |
|
|
| `ServerTransientError` / `ServerUnavailableError` (TTS) | `TtsSynthesisFailedError` |
|
|
| `ServerTransientError` (STT) | `SttTranscriptionFailedError` |
|
|
| `StreamInterruptedError` | `TtsStreamInterruptedError` |
|
|
| `ResponseUnsupportedFormatError` | `AudioFormatUnsupportedError` |
|
|
|
|
`voices.get(voiceId)` follows the `VoiceRepository` null-on-not-found
|
|
contract: any upstream 404 is mapped to `null` rather than thrown.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
@suaveplan/voice abstract engine interfaces
|
|
▲
|
|
│ implements
|
|
│
|
|
@suaveplan/voice-elevenlabs domain adapter (this package)
|
|
│
|
|
│ delegates HTTP / WebSocket / multipart
|
|
▼
|
|
@suaveplan/third-party-elevenlabs typed transport, retry, OTel,
|
|
rate-limit headers, raw DTOs
|
|
```
|
|
|
|
Future ElevenLabs surfaces (music, dubbing, conversational AI) compose
|
|
against the same `@suaveplan/third-party-elevenlabs` client; they do not
|
|
fan out from this package. This keeps each surface's domain-mapping
|
|
concerns isolated.
|
|
|
|
## Verification
|
|
|
|
```sh
|
|
bunx turbo lint typecheck test --filter=@suaveplan/voice-elevenlabs
|
|
bunx turbo test:coverage --filter=@suaveplan/voice-elevenlabs
|
|
```
|
|
|
|
Coverage gate: 100/100/100/100 statements/branches/functions/lines.
|
|
|