Module: RubyLLM::Protocols::ElevenLabs::Speech

Defined in:
lib/ruby_llm/protocols/elevenlabs/speech.rb

Overview

Speech dialect for the ElevenLabs text-to-speech API. The voice id is a path segment and the container is an output_format query value, so the endpoint cannot be named without the voice and format the caller asked for. The response is raw audio bytes.

Constant Summary collapse

DEFAULT_VOICE =
'JBFqnCBsd6RMkjVDRZzb'
DEFAULT_OUTPUT_FORMAT =
'mp3_44100_128'
OUTPUT_FORMATS =
{
  'alaw' => 'alaw_8000',
  'mp3' => 'mp3_44100_128',
  'opus' => 'opus_48000_128',
  'pcm' => 'pcm_44100',
  'ulaw' => 'ulaw_8000',
  'wav' => 'wav_44100'
}.freeze

Instance Method Summary collapse

Instance Method Details

#container_for(format) ⇒ Object



61
62
63
# File 'lib/ruby_llm/protocols/elevenlabs/speech.rb', line 61

def container_for(format)
  output_format_for(format).split('_').first
end

#output_format_for(format) ⇒ Object



55
56
57
58
59
# File 'lib/ruby_llm/protocols/elevenlabs/speech.rb', line 55

def output_format_for(format)
  return DEFAULT_OUTPUT_FORMAT unless format

  OUTPUT_FORMATS.fetch(format.to_s, format.to_s)
end

#parse_speech_response(response, model:, voice:, format:) ⇒ Object



46
47
48
49
50
51
52
53
# File 'lib/ruby_llm/protocols/elevenlabs/speech.rb', line 46

def parse_speech_response(response, model:, voice:, format:)
  RubyLLM::Speech.new(
    data: response.body,
    model: model,
    voice: voice || DEFAULT_VOICE,
    format: container_for(format)
  )
end

#render_speech_payload(input, model:, voice: nil, format: nil, provider_options: {}) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



42
43
44
# File 'lib/ruby_llm/protocols/elevenlabs/speech.rb', line 42

def render_speech_payload(input, model:, voice: nil, format: nil, provider_options: {}) # rubocop:disable Lint/UnusedMethodArgument
  Support::Utils.deep_merge({ text: input, model_id: model }, provider_options)
end

#speak(input, model:, voice:, format:, provider_options: {}, &block) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/ruby_llm/protocols/elevenlabs/speech.rb', line 23

def speak(input, model:, voice:, format:, provider_options: {}, &block)
  track_usage(:speech) do
    payload = render_speech_payload(input, model:, voice:, format:, provider_options:)
    if block
      next stream_speech_response(speech_url(voice:, format:, streaming: true), payload,
                                  model:, voice:, format:, &block)
    end

    response = @connection.post speech_url(voice:, format:), payload, usage: @usage_tracker
    parse_speech_response(response, model:, voice:, format:)
  end
end

#speech_url(voice: nil, format: nil, streaming: false) ⇒ Object



36
37
38
39
40
# File 'lib/ruby_llm/protocols/elevenlabs/speech.rb', line 36

def speech_url(voice: nil, format: nil, streaming: false)
  path = "v1/text-to-speech/#{voice || DEFAULT_VOICE}"
  path += '/stream' if streaming
  "#{path}?output_format=#{output_format_for(format)}"
end