ruby_llm 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +7 -5
- data/lib/generators/ruby_llm/generator_helpers.rb +8 -0
- data/lib/generators/ruby_llm/tool/templates/tool.rb.tt +1 -1
- data/lib/ruby_llm/active_record/acts_as.rb +3 -0
- data/lib/ruby_llm/active_record/acts_as_legacy.rb +52 -25
- data/lib/ruby_llm/active_record/chat_methods.rb +47 -23
- data/lib/ruby_llm/active_record/message_methods.rb +19 -14
- data/lib/ruby_llm/active_record/model_methods.rb +7 -9
- data/lib/ruby_llm/active_record/payload_helpers.rb +29 -0
- data/lib/ruby_llm/active_record/tool_call_methods.rb +5 -15
- data/lib/ruby_llm/agent.rb +3 -2
- data/lib/ruby_llm/aliases.json +53 -14
- data/lib/ruby_llm/attachment.rb +11 -27
- data/lib/ruby_llm/chat.rb +62 -21
- data/lib/ruby_llm/cost.rb +224 -0
- data/lib/ruby_llm/image.rb +37 -4
- data/lib/ruby_llm/message.rb +20 -0
- data/lib/ruby_llm/model/info.rb +17 -0
- data/lib/ruby_llm/model/pricing_category.rb +13 -2
- data/lib/ruby_llm/models.json +26511 -24930
- data/lib/ruby_llm/models.rb +2 -1
- data/lib/ruby_llm/models_schema.json +3 -0
- data/lib/ruby_llm/provider.rb +10 -3
- data/lib/ruby_llm/providers/anthropic/capabilities.rb +1 -133
- data/lib/ruby_llm/providers/anthropic/models.rb +2 -8
- data/lib/ruby_llm/providers/anthropic/tools.rb +4 -1
- data/lib/ruby_llm/providers/bedrock/chat.rb +24 -13
- data/lib/ruby_llm/providers/bedrock/streaming.rb +4 -1
- data/lib/ruby_llm/providers/deepseek/capabilities.rb +1 -119
- data/lib/ruby_llm/providers/gemini/capabilities.rb +45 -215
- data/lib/ruby_llm/providers/gemini/chat.rb +8 -1
- data/lib/ruby_llm/providers/gemini/images.rb +2 -2
- data/lib/ruby_llm/providers/gemini/models.rb +2 -4
- data/lib/ruby_llm/providers/gemini/streaming.rb +4 -1
- data/lib/ruby_llm/providers/gemini/tools.rb +3 -1
- data/lib/ruby_llm/providers/mistral/capabilities.rb +6 -1
- data/lib/ruby_llm/providers/mistral/chat.rb +55 -4
- data/lib/ruby_llm/providers/openai/capabilities.rb +157 -195
- data/lib/ruby_llm/providers/openai/chat.rb +45 -6
- data/lib/ruby_llm/providers/openai/images.rb +58 -6
- data/lib/ruby_llm/providers/openai/models.rb +2 -4
- data/lib/ruby_llm/providers/openai/streaming.rb +5 -6
- data/lib/ruby_llm/providers/openrouter/chat.rb +30 -6
- data/lib/ruby_llm/providers/openrouter/images.rb +2 -2
- data/lib/ruby_llm/providers/openrouter/models.rb +1 -1
- data/lib/ruby_llm/providers/openrouter/streaming.rb +5 -6
- data/lib/ruby_llm/providers/perplexity/capabilities.rb +34 -99
- data/lib/ruby_llm/providers/perplexity/models.rb +12 -14
- data/lib/ruby_llm/railtie.rb +6 -0
- data/lib/ruby_llm/tokens.rb +8 -0
- data/lib/ruby_llm/tool.rb +24 -7
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +2 -4
- data/lib/tasks/models.rake +13 -12
- metadata +21 -5
data/lib/ruby_llm/models.rb
CHANGED
|
@@ -356,7 +356,8 @@ module RubyLLM
|
|
|
356
356
|
text_standard = {
|
|
357
357
|
input_per_million: cost[:input],
|
|
358
358
|
output_per_million: cost[:output],
|
|
359
|
-
|
|
359
|
+
cache_read_input_per_million: cost[:cache_read],
|
|
360
|
+
cache_write_input_per_million: cost[:cache_write],
|
|
360
361
|
reasoning_output_per_million: cost[:reasoning]
|
|
361
362
|
}.compact
|
|
362
363
|
|
|
@@ -87,7 +87,10 @@
|
|
|
87
87
|
"type": "object",
|
|
88
88
|
"properties": {
|
|
89
89
|
"input_per_million": {"type": "number", "minimum": 0},
|
|
90
|
+
"cache_read_input_per_million": {"type": "number", "minimum": 0},
|
|
91
|
+
"cache_write_input_per_million": {"type": "number", "minimum": 0},
|
|
90
92
|
"cached_input_per_million": {"type": "number", "minimum": 0},
|
|
93
|
+
"cache_creation_input_per_million": {"type": "number", "minimum": 0},
|
|
91
94
|
"output_per_million": {"type": "number", "minimum": 0},
|
|
92
95
|
"reasoning_output_per_million": {"type": "number", "minimum": 0}
|
|
93
96
|
}
|
data/lib/ruby_llm/provider.rb
CHANGED
|
@@ -81,9 +81,10 @@ module RubyLLM
|
|
|
81
81
|
parse_moderation_response(response, model:)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
def paint(prompt, model:, size:)
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
def paint(prompt, model:, size:, with: nil, mask: nil, params: {}) # rubocop:disable Metrics/ParameterLists
|
|
85
|
+
validate_paint_inputs!(with:, mask:)
|
|
86
|
+
payload = render_image_payload(prompt, model:, size:, with:, mask:, params:)
|
|
87
|
+
response = @connection.post images_url(with:, mask:), payload
|
|
87
88
|
parse_image_response(response, model:)
|
|
88
89
|
end
|
|
89
90
|
|
|
@@ -225,6 +226,12 @@ module RubyLLM
|
|
|
225
226
|
|
|
226
227
|
private
|
|
227
228
|
|
|
229
|
+
def validate_paint_inputs!(with:, mask:)
|
|
230
|
+
return if with.nil? && mask.nil?
|
|
231
|
+
|
|
232
|
+
raise UnsupportedAttachmentError, "#{name} does not support image references in paint"
|
|
233
|
+
end
|
|
234
|
+
|
|
228
235
|
def build_audio_file_part(file_path)
|
|
229
236
|
expanded_path = File.expand_path(file_path)
|
|
230
237
|
mime_type = Marcel::MimeType.for(Pathname.new(expanded_path))
|
|
@@ -3,37 +3,10 @@
|
|
|
3
3
|
module RubyLLM
|
|
4
4
|
module Providers
|
|
5
5
|
class Anthropic
|
|
6
|
-
#
|
|
6
|
+
# Provider-level capability checks used outside the model registry.
|
|
7
7
|
module Capabilities
|
|
8
8
|
module_function
|
|
9
9
|
|
|
10
|
-
def determine_context_window(_model_id)
|
|
11
|
-
200_000
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def determine_max_tokens(model_id)
|
|
15
|
-
case model_id
|
|
16
|
-
when /claude-3-7-sonnet/, /claude-3-5/ then 8_192
|
|
17
|
-
else 4_096
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def get_input_price(model_id)
|
|
22
|
-
PRICES.dig(model_family(model_id), :input) || default_input_price
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def get_output_price(model_id)
|
|
26
|
-
PRICES.dig(model_family(model_id), :output) || default_output_price
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def supports_vision?(model_id)
|
|
30
|
-
!model_id.match?(/claude-[12]/)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def supports_functions?(model_id)
|
|
34
|
-
!model_id.match?(/claude-[12]/)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
10
|
def supports_tool_choice?(_model_id)
|
|
38
11
|
true
|
|
39
12
|
end
|
|
@@ -41,111 +14,6 @@ module RubyLLM
|
|
|
41
14
|
def supports_tool_parallel_control?(_model_id)
|
|
42
15
|
true
|
|
43
16
|
end
|
|
44
|
-
|
|
45
|
-
def supports_json_mode?(model_id)
|
|
46
|
-
!model_id.match?(/claude-[12]/)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def supports_structured_output?(model_id)
|
|
50
|
-
match = model_id.match(/claude-(?:sonnet|opus|haiku)-(\d+)-(\d+)/)
|
|
51
|
-
return false unless match
|
|
52
|
-
|
|
53
|
-
major = match[1].to_i
|
|
54
|
-
minor = match[2].to_i
|
|
55
|
-
major > 4 || (major == 4 && minor >= 5)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def supports_extended_thinking?(model_id)
|
|
59
|
-
model_id.match?(/claude-3-7-sonnet/)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def model_family(model_id)
|
|
63
|
-
case model_id
|
|
64
|
-
when /claude-3-7-sonnet/ then 'claude-3-7-sonnet'
|
|
65
|
-
when /claude-3-5-sonnet/ then 'claude-3-5-sonnet'
|
|
66
|
-
when /claude-3-5-haiku/ then 'claude-3-5-haiku'
|
|
67
|
-
when /claude-3-opus/ then 'claude-3-opus'
|
|
68
|
-
when /claude-3-sonnet/ then 'claude-3-sonnet'
|
|
69
|
-
when /claude-3-haiku/ then 'claude-3-haiku'
|
|
70
|
-
else 'claude-2'
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def model_type(_)
|
|
75
|
-
'chat'
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
PRICES = {
|
|
79
|
-
'claude-3-7-sonnet': { input: 3.0, output: 15.0 },
|
|
80
|
-
'claude-3-5-sonnet': { input: 3.0, output: 15.0 },
|
|
81
|
-
'claude-3-5-haiku': { input: 0.80, output: 4.0 },
|
|
82
|
-
'claude-3-opus': { input: 15.0, output: 75.0 },
|
|
83
|
-
'claude-3-haiku': { input: 0.25, output: 1.25 },
|
|
84
|
-
'claude-2': { input: 3.0, output: 15.0 }
|
|
85
|
-
}.freeze
|
|
86
|
-
|
|
87
|
-
def default_input_price
|
|
88
|
-
3.0
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def default_output_price
|
|
92
|
-
15.0
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def modalities_for(model_id)
|
|
96
|
-
modalities = {
|
|
97
|
-
input: ['text'],
|
|
98
|
-
output: ['text']
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
unless model_id.match?(/claude-[12]/)
|
|
102
|
-
modalities[:input] << 'image'
|
|
103
|
-
modalities[:input] << 'pdf'
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
modalities
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def capabilities_for(model_id)
|
|
110
|
-
capabilities = ['streaming']
|
|
111
|
-
|
|
112
|
-
unless model_id.match?(/claude-[12]/)
|
|
113
|
-
capabilities << 'function_calling'
|
|
114
|
-
capabilities << 'batch'
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
capabilities << 'structured_output' if supports_structured_output?(model_id)
|
|
118
|
-
capabilities << 'reasoning' if model_id.match?(/claude-3-7-sonnet|claude-(?:sonnet|opus|haiku)-4/)
|
|
119
|
-
capabilities << 'citations' if model_id.match?(/claude-3\.5|claude-3-7/)
|
|
120
|
-
capabilities
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def pricing_for(model_id)
|
|
124
|
-
family = model_family(model_id)
|
|
125
|
-
prices = PRICES.fetch(family.to_sym, { input: default_input_price, output: default_output_price })
|
|
126
|
-
|
|
127
|
-
standard_pricing = {
|
|
128
|
-
input_per_million: prices[:input],
|
|
129
|
-
output_per_million: prices[:output]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
batch_pricing = {
|
|
133
|
-
input_per_million: prices[:input] * 0.5,
|
|
134
|
-
output_per_million: prices[:output] * 0.5
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if model_id.match?(/claude-3-7/)
|
|
138
|
-
standard_pricing[:reasoning_output_per_million] = prices[:output] * 2.5
|
|
139
|
-
batch_pricing[:reasoning_output_per_million] = prices[:output] * 1.25
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
{
|
|
143
|
-
text_tokens: {
|
|
144
|
-
standard: standard_pricing,
|
|
145
|
-
batch: batch_pricing
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
end
|
|
149
17
|
end
|
|
150
18
|
end
|
|
151
19
|
end
|
|
@@ -11,21 +11,15 @@ module RubyLLM
|
|
|
11
11
|
'v1/models'
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def parse_list_models_response(response, slug,
|
|
14
|
+
def parse_list_models_response(response, slug, _capabilities)
|
|
15
15
|
Array(response.body['data']).map do |model_data|
|
|
16
16
|
model_id = model_data['id']
|
|
17
17
|
|
|
18
18
|
Model::Info.new(
|
|
19
19
|
id: model_id,
|
|
20
|
-
name: model_data['display_name'],
|
|
20
|
+
name: model_data['display_name'] || model_id,
|
|
21
21
|
provider: slug,
|
|
22
|
-
family: capabilities.model_family(model_id),
|
|
23
22
|
created_at: Time.parse(model_data['created_at']),
|
|
24
|
-
context_window: capabilities.determine_context_window(model_id),
|
|
25
|
-
max_output_tokens: capabilities.determine_max_tokens(model_id),
|
|
26
|
-
modalities: capabilities.modalities_for(model_id),
|
|
27
|
-
capabilities: capabilities.capabilities_for(model_id),
|
|
28
|
-
pricing: capabilities.pricing_for(model_id),
|
|
29
23
|
metadata: {}
|
|
30
24
|
)
|
|
31
25
|
end
|
|
@@ -45,10 +45,13 @@ module RubyLLM
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def format_tool_result_block(msg)
|
|
48
|
+
content = msg.content
|
|
49
|
+
content = '(no output)' if content.nil? || (content.respond_to?(:empty?) && content.empty?)
|
|
50
|
+
|
|
48
51
|
{
|
|
49
52
|
type: 'tool_result',
|
|
50
53
|
tool_use_id: msg.tool_call_id,
|
|
51
|
-
content: Media.format_content(
|
|
54
|
+
content: Media.format_content(content)
|
|
52
55
|
}
|
|
53
56
|
end
|
|
54
57
|
|
|
@@ -56,7 +56,7 @@ module RubyLLM
|
|
|
56
56
|
content: parse_text_content(content_blocks),
|
|
57
57
|
thinking: Thinking.build(text: thinking_text, signature: thinking_signature),
|
|
58
58
|
tool_calls: parse_tool_calls(content_blocks),
|
|
59
|
-
input_tokens: usage
|
|
59
|
+
input_tokens: input_tokens(usage),
|
|
60
60
|
output_tokens: usage['outputTokens'],
|
|
61
61
|
cached_tokens: usage['cacheReadInputTokens'],
|
|
62
62
|
cache_creation_tokens: usage['cacheWriteInputTokens'],
|
|
@@ -66,6 +66,13 @@ module RubyLLM
|
|
|
66
66
|
)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
def input_tokens(usage)
|
|
70
|
+
input_tokens = usage['inputTokens']
|
|
71
|
+
return unless input_tokens
|
|
72
|
+
|
|
73
|
+
[input_tokens.to_i - usage['cacheReadInputTokens'].to_i - usage['cacheWriteInputTokens'].to_i, 0].max
|
|
74
|
+
end
|
|
75
|
+
|
|
69
76
|
def render_messages(messages)
|
|
70
77
|
rendered = []
|
|
71
78
|
tool_result_blocks = []
|
|
@@ -154,19 +161,23 @@ module RubyLLM
|
|
|
154
161
|
|
|
155
162
|
def render_tool_result_content(content)
|
|
156
163
|
return render_raw_tool_result_content(content.value) if content.is_a?(RubyLLM::Content::Raw)
|
|
164
|
+
return [{ json: content }] if content.is_a?(Hash) || content.is_a?(Array)
|
|
165
|
+
return render_content_tool_result_content(content) if content.is_a?(RubyLLM::Content)
|
|
157
166
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
[text_tool_result_block(content)]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def render_content_tool_result_content(content)
|
|
171
|
+
blocks = []
|
|
172
|
+
blocks << text_tool_result_block(content.text) unless content.text.to_s.empty?
|
|
173
|
+
content.attachments.each { |attachment| blocks << text_tool_result_block(attachment.for_llm) }
|
|
174
|
+
blocks.empty? ? [text_tool_result_block(nil)] : blocks
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def text_tool_result_block(text)
|
|
178
|
+
text = text.to_s
|
|
179
|
+
text = '(no output)' if text.empty?
|
|
180
|
+
{ text: text }
|
|
170
181
|
end
|
|
171
182
|
|
|
172
183
|
def render_raw_tool_result_content(raw_value)
|
|
@@ -158,7 +158,10 @@ module RubyLLM
|
|
|
158
158
|
end
|
|
159
159
|
|
|
160
160
|
def extract_input_tokens(metadata_usage, usage, message_usage)
|
|
161
|
-
metadata_usage['inputTokens']
|
|
161
|
+
bedrock_usage = metadata_usage['inputTokens'] ? metadata_usage : usage
|
|
162
|
+
return Bedrock::Chat.input_tokens(bedrock_usage) if bedrock_usage['inputTokens']
|
|
163
|
+
|
|
164
|
+
message_usage['input_tokens']
|
|
162
165
|
end
|
|
163
166
|
|
|
164
167
|
def extract_output_tokens(metadata_usage, usage)
|
|
@@ -3,44 +3,10 @@
|
|
|
3
3
|
module RubyLLM
|
|
4
4
|
module Providers
|
|
5
5
|
class DeepSeek
|
|
6
|
-
#
|
|
6
|
+
# Provider-level capability checks used outside the model registry.
|
|
7
7
|
module Capabilities
|
|
8
8
|
module_function
|
|
9
9
|
|
|
10
|
-
def context_window_for(model_id)
|
|
11
|
-
case model_id
|
|
12
|
-
when /deepseek-(?:chat|reasoner)/ then 64_000
|
|
13
|
-
else 32_768
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def max_tokens_for(model_id)
|
|
18
|
-
case model_id
|
|
19
|
-
when /deepseek-(?:chat|reasoner)/ then 8_192
|
|
20
|
-
else 4_096
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def input_price_for(model_id)
|
|
25
|
-
PRICES.dig(model_family(model_id), :input_miss) || default_input_price
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def output_price_for(model_id)
|
|
29
|
-
PRICES.dig(model_family(model_id), :output) || default_output_price
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def cache_hit_price_for(model_id)
|
|
33
|
-
PRICES.dig(model_family(model_id), :input_hit) || default_cache_hit_price
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def supports_vision?(_model_id)
|
|
37
|
-
false
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def supports_functions?(model_id)
|
|
41
|
-
model_id.match?(/deepseek-chat/)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
10
|
def supports_tool_choice?(_model_id)
|
|
45
11
|
true
|
|
46
12
|
end
|
|
@@ -48,90 +14,6 @@ module RubyLLM
|
|
|
48
14
|
def supports_tool_parallel_control?(_model_id)
|
|
49
15
|
false
|
|
50
16
|
end
|
|
51
|
-
|
|
52
|
-
def supports_json_mode?(_model_id)
|
|
53
|
-
false
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def format_display_name(model_id)
|
|
57
|
-
case model_id
|
|
58
|
-
when 'deepseek-chat' then 'DeepSeek V3'
|
|
59
|
-
when 'deepseek-reasoner' then 'DeepSeek R1'
|
|
60
|
-
else
|
|
61
|
-
model_id.split('-')
|
|
62
|
-
.map(&:capitalize)
|
|
63
|
-
.join(' ')
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def model_type(_model_id)
|
|
68
|
-
'chat'
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def model_family(model_id)
|
|
72
|
-
case model_id
|
|
73
|
-
when /deepseek-reasoner/ then :reasoner
|
|
74
|
-
else :chat
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
PRICES = {
|
|
79
|
-
chat: {
|
|
80
|
-
input_hit: 0.07,
|
|
81
|
-
input_miss: 0.27,
|
|
82
|
-
output: 1.10
|
|
83
|
-
},
|
|
84
|
-
reasoner: {
|
|
85
|
-
input_hit: 0.14,
|
|
86
|
-
input_miss: 0.55,
|
|
87
|
-
output: 2.19
|
|
88
|
-
}
|
|
89
|
-
}.freeze
|
|
90
|
-
|
|
91
|
-
def default_input_price
|
|
92
|
-
0.27
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def default_output_price
|
|
96
|
-
1.10
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def default_cache_hit_price
|
|
100
|
-
0.07
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def modalities_for(_model_id)
|
|
104
|
-
{
|
|
105
|
-
input: ['text'],
|
|
106
|
-
output: ['text']
|
|
107
|
-
}
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def capabilities_for(model_id)
|
|
111
|
-
capabilities = ['streaming']
|
|
112
|
-
|
|
113
|
-
capabilities << 'function_calling' if model_id.match?(/deepseek-chat/)
|
|
114
|
-
|
|
115
|
-
capabilities
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def pricing_for(model_id)
|
|
119
|
-
family = model_family(model_id)
|
|
120
|
-
prices = PRICES.fetch(family, { input_miss: default_input_price, output: default_output_price })
|
|
121
|
-
|
|
122
|
-
standard_pricing = {
|
|
123
|
-
input_per_million: prices[:input_miss],
|
|
124
|
-
output_per_million: prices[:output]
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
standard_pricing[:cached_input_per_million] = prices[:input_hit] if prices[:input_hit]
|
|
128
|
-
|
|
129
|
-
{
|
|
130
|
-
text_tokens: {
|
|
131
|
-
standard: standard_pricing
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
end
|
|
135
17
|
end
|
|
136
18
|
end
|
|
137
19
|
end
|