Module: RubyLLM::Protocols::ElevenLabs::Flows::Images
- Defined in:
- lib/ruby_llm/protocols/elevenlabs/flows/images.rb
Overview
:nodoc: all
Constant Summary collapse
- MASK_MODELS =
%w[gpt-image-1 gpt-image-1.5 gpt-image-2].freeze
Instance Method Summary collapse
- #image_aspect_ratio(size) ⇒ Object
- #images_url ⇒ Object
- #parse_image_response(response, model:) ⇒ Object
- #post_image(payload) ⇒ Object
- #render_image_payload(prompt, model:, size:, with: nil, mask: nil, provider_options: {}) ⇒ Object
- #validate_paint_inputs!(with:, mask:) ⇒ Object
- #wait_for_image(id) ⇒ Object
Instance Method Details
#image_aspect_ratio(size) ⇒ Object
62 63 64 65 66 67 68 69 |
# File 'lib/ruby_llm/protocols/elevenlabs/flows/images.rb', line 62 def image_aspect_ratio(size) match = size.to_s.match(/\A([1-9]\d*)x([1-9]\d*)\z/) raise ArgumentError, 'size must be widthxheight or auto' unless match width, height = match.captures.map(&:to_i) divisor = width.gcd(height) "#{width / divisor}:#{height / divisor}" end |
#images_url ⇒ Object
10 11 12 |
# File 'lib/ruby_llm/protocols/elevenlabs/flows/images.rb', line 10 def images_url(**) 'v1/flows/image' end |
#parse_image_response(response, model:) ⇒ Object
31 32 33 34 35 |
# File 'lib/ruby_llm/protocols/elevenlabs/flows/images.rb', line 31 def parse_image_response(response, model:) id = response.body.fetch('id') body = wait_for_image(id) Image.new(url: body.fetch('content_url'), mime_type: body.fetch('content_mime_type'), model:) end |
#post_image(payload) ⇒ Object
14 15 16 |
# File 'lib/ruby_llm/protocols/elevenlabs/flows/images.rb', line 14 def post_image(payload, **) @connection.post images_url, payload, usage: @usage_tracker, idempotent: false end |
#render_image_payload(prompt, model:, size:, with: nil, mask: nil, provider_options: {}) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/ruby_llm/protocols/elevenlabs/flows/images.rb', line 18 def render_image_payload(prompt, model:, size:, with: nil, mask: nil, provider_options: {}, **) images = Attachment.wrap(with, config: @config) payload = { model_id: model, prompt: } payload[:images] = images.map { |image| render_media_reference(image) } if images.any? payload[:aspect_ratio] = image_aspect_ratio(size) if size && size != 'auto' if mask raise ArgumentError, 'ElevenLabs image masks require a GPT Image model' unless MASK_MODELS.include?(model) payload[:mask] = render_media_reference(Attachment.wrap(mask, config: @config).first) end Support::Utils.deep_merge(payload, ) end |
#validate_paint_inputs!(with:, mask:) ⇒ Object
52 53 54 55 56 57 58 59 60 |
# File 'lib/ruby_llm/protocols/elevenlabs/flows/images.rb', line 52 def validate_paint_inputs!(with:, mask:) images = Attachment.wrap(with, config: @config) raise ArgumentError, 'An image mask requires a source image' if mask && images.empty? images += Attachment.wrap(mask, config: @config) if mask images.each do |image| raise UnsupportedAttachmentError, image.mime_type unless image.image? end end |
#wait_for_image(id) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/ruby_llm/protocols/elevenlabs/flows/images.rb', line 37 def wait_for_image(id) deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @config.request_timeout loop do body = @connection.get("#{images_url}/#{id}").body state = parse_generation_status(body) return body if state[:status] == :completed raise Error, "ElevenLabs image generation failed: #{state[:error]}" if state[:status] == :failed if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline raise Error, "ElevenLabs image generation timed out: #{id}" end sleep 1 end end |