Skip to content

Commit 5cdf01f

Browse files
committed
Make one-shot API keywords explicit
1 parent 1bc6fc0 commit 5cdf01f

18 files changed

Lines changed: 165 additions & 46 deletions

File tree

lib/ruby_llm/protocol.rb

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,28 @@ def paint(prompt, model:, size:, with: nil, mask: nil, params: {}) # rubocop:dis
7575
parse_image_response(response, model:)
7676
end
7777

78-
def speak(input, model:, voice:, format:, params: {}, **options) # rubocop:disable Metrics/ParameterLists
79-
payload = render_speech_payload(input, model:, voice:, format:, params:, **options)
78+
def speak(input, model:, voice:, format:, params: {}, instructions: nil, speed: nil) # rubocop:disable Metrics/ParameterLists
79+
payload = render_speech_payload(input, model:, voice:, format:, params:, instructions:, speed:)
8080
response = @connection.post speech_url(model:), payload
8181
parse_speech_response(response, model:, voice:, format:)
8282
end
8383

84-
def transcribe(audio_file, model:, language:, params: {}, **options)
84+
def transcribe(audio_file, model:, language:, params: {}, prompt: nil, temperature: nil, response_format: nil, # rubocop:disable Metrics/ParameterLists
85+
timestamp_granularities: nil, speaker_names: nil, speaker_references: nil, chunking_strategy: nil,
86+
response_mime_type: nil, max_output_tokens: nil, safety_settings: nil)
8587
file_part = build_audio_file_part(audio_file)
88+
options = {
89+
prompt: prompt,
90+
temperature: temperature,
91+
response_format: response_format,
92+
timestamp_granularities: timestamp_granularities,
93+
speaker_names: speaker_names,
94+
speaker_references: speaker_references,
95+
chunking_strategy: chunking_strategy,
96+
response_mime_type: response_mime_type,
97+
max_output_tokens: max_output_tokens,
98+
safety_settings: safety_settings
99+
}.compact
86100
payload = render_transcription_payload(file_part, model:, language:, params:, **options)
87101
response = @connection.post transcription_url, payload
88102
parse_transcription_response(response, model:)

lib/ruby_llm/protocols/chat_completions/speech.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ def speech_url(model:) # rubocop:disable Lint/UnusedMethodArgument
1111
'audio/speech'
1212
end
1313

14-
def render_speech_payload(input, model:, voice:, format:, params: {}, **options) # rubocop:disable Metrics/ParameterLists
14+
def render_speech_payload(input, model:, voice:, format:, params: {}, instructions: nil, speed: nil) # rubocop:disable Metrics/ParameterLists
1515
{
1616
model: model,
1717
input: input,
1818
voice: voice || 'alloy',
1919
response_format: format,
20-
instructions: options[:instructions],
21-
speed: options[:speed]
20+
instructions: instructions,
21+
speed: speed
2222
}.compact.merge(params)
2323
end
2424

lib/ruby_llm/protocols/chat_completions/transcription.rb

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,25 @@ def transcription_url
1111
'audio/transcriptions'
1212
end
1313

14-
def render_transcription_payload(file_part, model:, language:, params: {}, **options)
14+
# rubocop:disable Lint/UnusedMethodArgument, Metrics/ParameterLists
15+
def render_transcription_payload(file_part, model:, language:, params: {}, prompt: nil, temperature: nil,
16+
response_format: nil, timestamp_granularities: nil, speaker_names: nil,
17+
speaker_references: nil, chunking_strategy: nil, response_mime_type: nil,
18+
max_output_tokens: nil, safety_settings: nil)
1519
{
1620
model: model,
1721
file: file_part,
1822
language: language,
19-
chunking_strategy: (options[:chunking_strategy] || 'auto' if supports_chunking_strategy?(model, options)),
20-
response_format: response_format_for(model, options),
21-
prompt: options[:prompt],
22-
temperature: options[:temperature],
23-
timestamp_granularities: options[:timestamp_granularities],
24-
known_speaker_names: options[:speaker_names],
25-
known_speaker_references: encode_speaker_references(options[:speaker_references])
23+
chunking_strategy: resolved_chunking_strategy(model, chunking_strategy),
24+
response_format: response_format_for(model, response_format),
25+
prompt: prompt,
26+
temperature: temperature,
27+
timestamp_granularities: timestamp_granularities,
28+
known_speaker_names: speaker_names,
29+
known_speaker_references: encode_speaker_references(speaker_references)
2630
}.compact.merge(params)
2731
end
32+
# rubocop:enable Lint/UnusedMethodArgument, Metrics/ParameterLists
2833

2934
def encode_speaker_references(references)
3035
return nil unless references
@@ -34,15 +39,21 @@ def encode_speaker_references(references)
3439
end
3540
end
3641

37-
def response_format_for(model, options)
38-
return options[:response_format] if options.key?(:response_format)
42+
def resolved_chunking_strategy(model, chunking_strategy)
43+
return unless supports_chunking_strategy?(model, chunking_strategy)
44+
45+
chunking_strategy || 'auto'
46+
end
47+
48+
def response_format_for(model, response_format)
49+
return response_format if response_format
3950

4051
'diarized_json' if model.include?('diarize')
4152
end
4253

43-
def supports_chunking_strategy?(model, options)
54+
def supports_chunking_strategy?(model, chunking_strategy)
4455
return false if model.start_with?('whisper')
45-
return true if options.key?(:chunking_strategy)
56+
return true if chunking_strategy
4657

4758
model.include?('diarize')
4859
end

lib/ruby_llm/protocols/gemini/files.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ module Protocols
55
class Gemini
66
# Gemini Files API.
77
class Files < UploadedFile::Protocol
8-
def upload(file, filename: nil, display_name: nil, **)
8+
# rubocop:disable Lint/UnusedMethodArgument, Metrics/ParameterLists
9+
def upload(file, filename: nil, display_name: nil, purpose: nil, expires_after: nil, expiry: nil,
10+
visibility: nil, uri: nil, content_type: nil)
911
attachment = file_attachment(file, filename:)
1012
upload_url = start_resumable_upload(attachment, display_name: display_name || attachment.filename)
1113
response = upload_file_bytes(upload_url, attachment)
1214
parse_file_response(response.body.fetch('file'))
1315
end
16+
# rubocop:enable Lint/UnusedMethodArgument, Metrics/ParameterLists
1417

1518
def download(file_id)
1619
file = find(file_id)

lib/ruby_llm/protocols/gemini/speech.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def speech_url(model:)
1111
"models/#{model}:generateContent"
1212
end
1313

14-
def render_speech_payload(input, model:, voice:, format:, params: {}, **options) # rubocop:disable Lint/UnusedMethodArgument,Metrics/ParameterLists
14+
def render_speech_payload(input, model:, voice:, format:, params: {}, instructions: nil, speed: nil) # rubocop:disable Lint/UnusedMethodArgument,Metrics/ParameterLists
1515
RubyLLM.logger.debug { "Ignoring speech format #{format}. Gemini returns PCM audio." } if format
1616

1717
payload = {

lib/ruby_llm/protocols/gemini/transcription.rb

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,28 @@ class Gemini
77
module Transcription
88
DEFAULT_PROMPT = 'Transcribe the provided audio and respond with only the transcript text.'
99

10-
def transcribe(audio_file, model:, language:, params: {}, **options)
10+
# rubocop:disable Lint/UnusedMethodArgument, Metrics/ParameterLists
11+
def transcribe(audio_file, model:, language:, params: {}, prompt: nil, temperature: nil,
12+
response_format: nil, timestamp_granularities: nil, speaker_names: nil,
13+
speaker_references: nil, chunking_strategy: nil, response_mime_type: 'text/plain',
14+
max_output_tokens: nil, safety_settings: nil)
1115
attachment = Attachment.new(audio_file)
12-
payload = render_transcription_payload(attachment, language:, params:, **options)
16+
payload = render_transcription_payload(attachment, language:, params:, prompt:, temperature:,
17+
response_mime_type:, max_output_tokens:, safety_settings:)
1318
response = @connection.post(transcription_url(model), payload)
1419
parse_transcription_response(response, model:)
1520
end
21+
# rubocop:enable Lint/UnusedMethodArgument, Metrics/ParameterLists
1622

1723
private
1824

1925
def transcription_url(model)
2026
"models/#{model}:generateContent"
2127
end
2228

23-
def render_transcription_payload(attachment, language:, params: {}, **options)
24-
prompt = build_prompt(options[:prompt], language)
29+
def render_transcription_payload(attachment, language:, params: {}, prompt: nil, temperature: nil, # rubocop:disable Metrics/ParameterLists
30+
response_mime_type: 'text/plain', max_output_tokens: nil, safety_settings: nil)
31+
prompt = build_prompt(prompt, language)
2532
audio_part = format_audio_part(attachment)
2633

2734
raise UnsupportedAttachmentError, attachment.mime_type unless attachment.audio?
@@ -38,20 +45,19 @@ def render_transcription_payload(attachment, language:, params: {}, **options)
3845
]
3946
}
4047

41-
generation_config = build_generation_config(options)
48+
generation_config = build_generation_config(response_mime_type:, temperature:, max_output_tokens:)
4249
payload[:generationConfig] = generation_config unless generation_config.empty?
43-
payload[:safetySettings] = options[:safety_settings] if options[:safety_settings]
50+
payload[:safetySettings] = safety_settings if safety_settings
4451

4552
Utils.deep_merge(payload, params)
4653
end
4754

48-
def build_generation_config(options)
55+
def build_generation_config(response_mime_type:, temperature:, max_output_tokens:)
4956
config = {}
50-
response_mime_type = options.fetch(:response_mime_type, 'text/plain')
5157

5258
config[:responseMimeType] = response_mime_type if response_mime_type
53-
config[:temperature] = options[:temperature] if options.key?(:temperature)
54-
config[:maxOutputTokens] = options[:max_output_tokens] if options[:max_output_tokens]
59+
config[:temperature] = temperature if temperature
60+
config[:maxOutputTokens] = max_output_tokens if max_output_tokens
5561

5662
config
5763
end

lib/ruby_llm/protocols/openai/files.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ class Files < UploadedFile::Protocol
99

1010
private
1111

12-
def render_upload_payload(attachment, purpose: nil, expires_after: nil, **)
12+
# rubocop:disable Lint/UnusedMethodArgument, Metrics/ParameterLists
13+
def render_upload_payload(attachment, purpose: nil, expires_after: nil, expiry: nil, visibility: nil,
14+
display_name: nil, uri: nil, content_type: nil)
1315
unless purpose
1416
raise ArgumentError, "#{@provider.name} file uploads require purpose: " \
1517
"#{UPLOAD_PURPOSES.join(', ')}"
1618
end
1719

1820
multipart_payload(attachment, purpose:, expires_after:)
1921
end
22+
# rubocop:enable Lint/UnusedMethodArgument, Metrics/ParameterLists
2023

2124
def parse_file_response(data)
2225
uploaded_file(

lib/ruby_llm/provider.rb

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,35 @@ def paint(prompt, model:, size:, with: nil, mask: nil, params: {}) # rubocop:dis
148148
default_protocol.new(self).paint(prompt, model:, size:, with:, mask:, params:)
149149
end
150150

151-
def speak(input, model:, voice:, format:, params: {}, **options) # rubocop:disable Metrics/ParameterLists
152-
default_protocol.new(self).speak(input, model:, voice:, format:, params:, **options)
151+
def speak(input, model:, voice:, format:, params: {}, instructions: nil, speed: nil) # rubocop:disable Metrics/ParameterLists
152+
default_protocol.new(self).speak(input, model:, voice:, format:, params:, instructions:, speed:)
153153
end
154154

155-
def transcribe(audio_file, model:, language:, params: {}, **options)
155+
def transcribe(audio_file, model:, language:, params: {}, prompt: nil, temperature: nil, response_format: nil, # rubocop:disable Metrics/ParameterLists
156+
timestamp_granularities: nil, speaker_names: nil, speaker_references: nil, chunking_strategy: nil,
157+
response_mime_type: nil, max_output_tokens: nil, safety_settings: nil)
158+
options = {
159+
prompt: prompt,
160+
temperature: temperature,
161+
response_format: response_format,
162+
timestamp_granularities: timestamp_granularities,
163+
speaker_names: speaker_names,
164+
speaker_references: speaker_references,
165+
chunking_strategy: chunking_strategy,
166+
response_mime_type: response_mime_type,
167+
max_output_tokens: max_output_tokens,
168+
safety_settings: safety_settings
169+
}.compact
170+
156171
default_protocol.new(self).transcribe(audio_file, model:, language:, params:, **options)
157172
end
158173

159-
def upload_file(file, **options)
174+
def upload_file(file, filename: nil, purpose: nil, expires_after: nil, expiry: nil, visibility: nil, # rubocop:disable Metrics/ParameterLists
175+
display_name: nil, uri: nil, content_type: nil)
160176
ensure_files_supported!
177+
options = { filename:, purpose:, expires_after:, expiry:, visibility:, display_name:, uri:, content_type: }
178+
.compact
179+
161180
file_protocol.new(self).upload(file, **options)
162181
end
163182

lib/ruby_llm/providers/bedrock/files.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ module Providers
55
class Bedrock
66
# S3-backed file storage for Bedrock batch input and output.
77
class Files < UploadedFile::Protocol
8-
def upload(file, uri: nil, filename: nil, content_type: nil, **)
8+
# rubocop:disable Lint/UnusedMethodArgument, Metrics/ParameterLists
9+
def upload(file, uri: nil, filename: nil, content_type: nil, purpose: nil, expires_after: nil, expiry: nil,
10+
visibility: nil, display_name: nil)
911
attachment = file_attachment(file, filename:)
1012
target_uri = uri || storage_uri_for(attachment)
1113
bucket, key = parse_s3_uri(target_uri)
@@ -24,6 +26,7 @@ def upload(file, uri: nil, filename: nil, content_type: nil, **)
2426
mime_type: content_type || file_content_type(attachment)
2527
)
2628
end
29+
# rubocop:enable Lint/UnusedMethodArgument, Metrics/ParameterLists
2730

2831
def find(file_id)
2932
bucket, key = parse_s3_uri(file_id)

lib/ruby_llm/providers/mistral/files.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ def download_file_url(file_id)
1111
"#{file_info_url(file_id)}/download"
1212
end
1313

14-
def render_upload_payload(attachment, purpose: nil, expiry: nil, visibility: nil, **)
14+
# rubocop:disable Lint/UnusedMethodArgument, Metrics/ParameterLists
15+
def render_upload_payload(attachment, purpose: nil, expiry: nil, visibility: nil, expires_after: nil,
16+
display_name: nil, uri: nil, content_type: nil)
1517
multipart_payload(attachment, purpose:, expiry:, visibility:)
1618
end
19+
# rubocop:enable Lint/UnusedMethodArgument, Metrics/ParameterLists
1720

1821
def parse_file_response(data)
1922
uploaded_file(

0 commit comments

Comments
 (0)