( params: ElevenLabsTtsUnifiedParams )
| 431 | } |
| 432 | |
| 433 | async function synthesizeWithElevenLabs( |
| 434 | params: ElevenLabsTtsUnifiedParams |
| 435 | ): Promise<{ audioBuffer: Buffer; format: string; mimeType: string }> { |
| 436 | const { |
| 437 | text, |
| 438 | apiKey, |
| 439 | voiceId, |
| 440 | modelId = 'eleven_turbo_v2_5', |
| 441 | stability = 0.5, |
| 442 | similarityBoost = 0.8, |
| 443 | style, |
| 444 | useSpeakerBoost = true, |
| 445 | } = params |
| 446 | |
| 447 | const voiceSettings: any = { |
| 448 | stability: Math.max(0, Math.min(1, stability)), |
| 449 | similarity_boost: Math.max(0, Math.min(1, similarityBoost)), |
| 450 | use_speaker_boost: useSpeakerBoost, |
| 451 | } |
| 452 | |
| 453 | if (style !== undefined) { |
| 454 | voiceSettings.style = Math.max(0, Math.min(1, style)) |
| 455 | } |
| 456 | |
| 457 | const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, { |
| 458 | method: 'POST', |
| 459 | headers: { |
| 460 | Accept: 'audio/mpeg', |
| 461 | 'Content-Type': 'application/json', |
| 462 | 'xi-api-key': apiKey, |
| 463 | }, |
| 464 | body: JSON.stringify({ |
| 465 | text, |
| 466 | model_id: modelId, |
| 467 | voice_settings: voiceSettings, |
| 468 | }), |
| 469 | }) |
| 470 | |
| 471 | if (!response.ok) { |
| 472 | const error = await readTtsErrorJson(response, 'ElevenLabs TTS error response') |
| 473 | const errorMessage = getTtsErrorMessage(error, response.statusText) |
| 474 | throw new Error(`ElevenLabs TTS API error: ${errorMessage}`) |
| 475 | } |
| 476 | |
| 477 | const audioBuffer = await readResponseToBufferWithLimit(response, { |
| 478 | maxBytes: MAX_TTS_AUDIO_BYTES, |
| 479 | label: 'ElevenLabs TTS audio response', |
| 480 | }) |
| 481 | |
| 482 | return { |
| 483 | audioBuffer, |
| 484 | format: 'mp3', |
| 485 | mimeType: 'audio/mpeg', |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | async function synthesizeWithCartesia( |
| 490 | params: Partial<CartesiaTtsParams> |
no test coverage detected