ruby_llm 0.1.0.pre4 → 0.1.0.pre6
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/.github/workflows/test.yml +5 -2
- data/.overcommit.yml +1 -1
- data/README.md +56 -181
- data/bin/console +6 -0
- data/lib/ruby_llm/chat.rb +95 -0
- data/lib/ruby_llm/chunk.rb +6 -0
- data/lib/ruby_llm/configuration.rb +2 -4
- data/lib/ruby_llm/message.rb +26 -18
- data/lib/ruby_llm/model_capabilities/anthropic.rb +43 -48
- data/lib/ruby_llm/model_capabilities/openai.rb +82 -89
- data/lib/ruby_llm/model_info.rb +26 -17
- data/lib/ruby_llm/models.json +686 -0
- data/lib/ruby_llm/models.rb +52 -0
- data/lib/ruby_llm/provider.rb +99 -0
- data/lib/ruby_llm/providers/anthropic.rb +92 -243
- data/lib/ruby_llm/providers/openai.rb +130 -174
- data/lib/ruby_llm/tool.rb +71 -50
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +35 -37
- data/lib/tasks/models.rake +25 -0
- data/ruby_llm.gemspec +8 -6
- metadata +39 -15
- data/lib/ruby_llm/active_record/acts_as.rb +0 -115
- data/lib/ruby_llm/client.rb +0 -70
- data/lib/ruby_llm/conversation.rb +0 -19
- data/lib/ruby_llm/model_capabilities/base.rb +0 -35
- data/lib/ruby_llm/providers/base.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3f047af8fc43eadb0f4b678f175ec2484c92f954f45bff44373b577e03c1a74
|
4
|
+
data.tar.gz: 6be674b01d98fb2c18c48f51f874de29bb9d21a739b3c2275f873bf133758e47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2026bf3da2c7170a98dd5a0ee1d859a468bfa1907a709966195b65316277b2135520b3d51fc0e1e4228e986f5c98aa1ae218c32ec176f8867138cff1da4f755a
|
7
|
+
data.tar.gz: ec25bc364c2bca512facb709481be1d17d9a84cf91625beaed8389e6b9637d2546a075330e2934c47fe569864406ea9bf167330e915bf93ca0b120dc91952538
|
data/.github/workflows/test.yml
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
name: Test
|
2
2
|
|
3
|
+
|
4
|
+
|
3
5
|
on:
|
4
6
|
push:
|
5
7
|
branches: [ "main" ]
|
6
8
|
pull_request:
|
7
9
|
branches: [ "main" ]
|
10
|
+
workflow_call:
|
8
11
|
|
9
12
|
jobs:
|
10
13
|
test:
|
@@ -28,5 +31,5 @@ jobs:
|
|
28
31
|
# - name: Check code format
|
29
32
|
# run: bundle exec rubocop
|
30
33
|
|
31
|
-
- name: Run tests
|
32
|
-
|
34
|
+
# - name: Run tests
|
35
|
+
# run: bundle exec rspec
|
data/.overcommit.yml
CHANGED
data/README.md
CHANGED
@@ -1,237 +1,112 @@
|
|
1
1
|
# RubyLLM
|
2
2
|
|
3
|
-
|
3
|
+
A delightful Ruby interface to the latest large language models. Stop wrestling with multiple APIs and inconsistent interfaces. RubyLLM gives you a clean, unified way to work with models from OpenAI, Anthropic, and more.
|
4
4
|
|
5
5
|
[](https://badge.fury.io/rb/ruby_llm)
|
6
6
|
[](https://github.com/testdouble/standard)
|
7
7
|
|
8
|
-
RubyLLM provides a unified interface for interacting with various LLM providers including OpenAI, Anthropic, and more. It offers both standalone usage and seamless Rails integration.
|
9
|
-
|
10
|
-
## Features
|
11
|
-
|
12
|
-
- 🤝 Unified interface for multiple LLM providers (OpenAI, Anthropic, etc.)
|
13
|
-
- 📋 Comprehensive model listing and capabilities detection
|
14
|
-
- 🛠️ Simple and flexible tool/function calling
|
15
|
-
- 📊 Automatic token counting and tracking
|
16
|
-
- 🔄 Streaming support
|
17
|
-
- 🚂 Seamless Rails integration
|
18
|
-
|
19
8
|
## Installation
|
20
9
|
|
21
|
-
Add
|
10
|
+
Add it to your Gemfile:
|
22
11
|
|
23
12
|
```ruby
|
24
13
|
gem 'ruby_llm'
|
25
14
|
```
|
26
15
|
|
27
|
-
|
28
|
-
```bash
|
29
|
-
$ bundle install
|
30
|
-
```
|
31
|
-
|
32
|
-
Or install it directly:
|
16
|
+
Or install it yourself:
|
33
17
|
|
34
18
|
```bash
|
35
|
-
|
19
|
+
gem install ruby_llm
|
36
20
|
```
|
37
21
|
|
38
|
-
##
|
22
|
+
## Quick Start
|
39
23
|
|
40
|
-
|
24
|
+
RubyLLM makes it dead simple to start chatting with AI models:
|
41
25
|
|
42
26
|
```ruby
|
43
27
|
require 'ruby_llm'
|
44
28
|
|
29
|
+
# Configure your API keys
|
45
30
|
RubyLLM.configure do |config|
|
46
31
|
config.openai_api_key = ENV['OPENAI_API_KEY']
|
47
32
|
config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
|
48
|
-
config.default_model = 'gpt-4o-mini'
|
33
|
+
config.default_model = 'gpt-4o-mini' # OpenAI's efficient model
|
49
34
|
end
|
50
|
-
```
|
51
|
-
|
52
|
-
### Listing Available Models
|
53
|
-
|
54
|
-
```ruby
|
55
|
-
client = RubyLLM.client
|
56
|
-
|
57
|
-
# List models from all providers
|
58
|
-
all_models = client.list_models
|
59
|
-
|
60
|
-
# List models from a specific provider
|
61
|
-
openai_models = client.list_models(:openai)
|
62
|
-
anthropic_models = client.list_models(:anthropic)
|
63
|
-
|
64
|
-
# Access model information
|
65
|
-
model = openai_models.first
|
66
|
-
puts model.display_name
|
67
|
-
puts "Context window: #{model.context_window}"
|
68
|
-
puts "Maximum tokens: #{model.max_tokens}"
|
69
|
-
puts "Input price per million tokens: $#{model.input_price_per_million}"
|
70
|
-
puts "Output price per million tokens: $#{model.output_price_per_million}"
|
71
|
-
puts "Supports vision: #{model.supports_vision}"
|
72
|
-
puts "Supports function calling: #{model.supports_functions}"
|
73
|
-
puts "Supports JSON mode: #{model.supports_json_mode}"
|
74
|
-
```
|
75
|
-
|
76
|
-
### Simple Chat
|
77
|
-
|
78
|
-
```ruby
|
79
|
-
client = RubyLLM.client
|
80
|
-
|
81
|
-
response = client.chat([
|
82
|
-
{ role: :user, content: "Hello!" }
|
83
|
-
])
|
84
35
|
|
36
|
+
# Start a conversation
|
37
|
+
chat = RubyLLM.chat
|
38
|
+
response = chat.ask "What's the best way to learn Ruby?"
|
85
39
|
puts response.content
|
86
40
|
```
|
87
41
|
|
88
|
-
|
42
|
+
## Available Models
|
89
43
|
|
90
|
-
RubyLLM
|
44
|
+
RubyLLM gives you access to the latest models from multiple providers. Check what's available:
|
91
45
|
|
92
46
|
```ruby
|
93
|
-
#
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
type: "string",
|
100
|
-
description: "The mathematical expression to evaluate",
|
101
|
-
required: true
|
102
|
-
}
|
103
|
-
}
|
104
|
-
) do |args|
|
105
|
-
eval(args[:expression]).to_s
|
47
|
+
# List all available models
|
48
|
+
RubyLLM.models.all.each do |model|
|
49
|
+
puts "#{model.display_name} (#{model.provider})"
|
50
|
+
puts " Context window: #{model.context_window}"
|
51
|
+
puts " Price: $#{model.input_price_per_million}/M tokens (input)"
|
52
|
+
puts " $#{model.output_price_per_million}/M tokens (output)"
|
106
53
|
end
|
107
54
|
|
108
|
-
#
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
when 'subtract' then x - y
|
114
|
-
when 'multiply' then x * y
|
115
|
-
when 'divide' then x.to_f / y
|
116
|
-
else
|
117
|
-
raise ArgumentError, "Unknown operation: #{operation}"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
math_tool = RubyLLM::Tool.from_method(
|
123
|
-
MathUtils.instance_method(:arithmetic),
|
124
|
-
description: "Performs basic arithmetic operations",
|
125
|
-
parameter_descriptions: {
|
126
|
-
x: "First number in the operation",
|
127
|
-
y: "Second number in the operation",
|
128
|
-
operation: "Operation to perform (add, subtract, multiply, divide)"
|
129
|
-
}
|
130
|
-
)
|
131
|
-
|
132
|
-
# Use tools in conversations
|
133
|
-
response = client.chat([
|
134
|
-
{ role: :user, content: "What is 123 * 456?" }
|
135
|
-
], tools: [calculator])
|
136
|
-
|
137
|
-
puts response.content
|
55
|
+
# Get models by type
|
56
|
+
chat_models = RubyLLM.models.chat_models
|
57
|
+
embedding_models = RubyLLM.models.embedding_models
|
58
|
+
audio_models = RubyLLM.models.audio_models
|
59
|
+
image_models = RubyLLM.models.image_models
|
138
60
|
```
|
139
61
|
|
140
|
-
|
62
|
+
## Having a Conversation
|
141
63
|
|
142
|
-
|
143
|
-
client.chat([
|
144
|
-
{ role: :user, content: "Count to 10 slowly" }
|
145
|
-
], stream: true) do |chunk|
|
146
|
-
print chunk.content
|
147
|
-
end
|
148
|
-
```
|
64
|
+
Conversations are simple and natural, with automatic token counting built right in:
|
149
65
|
|
150
|
-
|
151
|
-
|
152
|
-
RubyLLM provides seamless Rails integration with Active Record models.
|
66
|
+
```ruby
|
67
|
+
chat = RubyLLM.chat model: 'claude-3-opus-20240229'
|
153
68
|
|
154
|
-
|
69
|
+
# Single messages with token tracking
|
70
|
+
response = chat.ask "What's your favorite Ruby feature?"
|
71
|
+
puts "Response used #{response.input_tokens} input tokens and #{response.output_tokens} output tokens"
|
155
72
|
|
156
|
-
|
73
|
+
# Multi-turn conversations just work
|
74
|
+
chat.ask "Can you elaborate on that?"
|
75
|
+
chat.ask "How does that compare to Python?"
|
157
76
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
config.anthropic_api_key = Rails.application.credentials.anthropic[:api_key]
|
162
|
-
config.default_model = Rails.env.production? ? 'gpt-4' : 'gpt-3.5-turbo'
|
77
|
+
# Stream responses as they come
|
78
|
+
chat.ask "Tell me a story about a Ruby programmer" do |chunk|
|
79
|
+
print chunk.content
|
163
80
|
end
|
81
|
+
|
82
|
+
# Get token usage for the whole conversation from the last message
|
83
|
+
last_message = chat.messages.last
|
84
|
+
puts "Conversation used #{last_message.input_tokens} input tokens and #{last_message.output_tokens} output tokens"
|
164
85
|
```
|
165
86
|
|
166
|
-
|
87
|
+
## Choosing the Right Model
|
167
88
|
|
168
|
-
|
169
|
-
# app/models/llm_model.rb
|
170
|
-
class LLMModel < ApplicationRecord
|
171
|
-
acts_as_llm_model
|
172
|
-
|
173
|
-
# Schema:
|
174
|
-
# t.string :provider
|
175
|
-
# t.string :name
|
176
|
-
# t.jsonb :capabilities
|
177
|
-
# t.integer :context_length
|
178
|
-
# t.timestamps
|
179
|
-
end
|
180
|
-
|
181
|
-
# app/models/conversation.rb
|
182
|
-
class Conversation < ApplicationRecord
|
183
|
-
acts_as_llm_conversation
|
184
|
-
belongs_to :user
|
89
|
+
RubyLLM gives you easy access to model capabilities:
|
185
90
|
|
186
|
-
|
187
|
-
|
188
|
-
# t.string :title
|
189
|
-
# t.string :current_model
|
190
|
-
# t.timestamps
|
191
|
-
end
|
91
|
+
```ruby
|
92
|
+
model = RubyLLM.models.find 'claude-3-opus-20240229'
|
192
93
|
|
193
|
-
#
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
# Schema:
|
198
|
-
# t.references :conversation
|
199
|
-
# t.string :role
|
200
|
-
# t.text :content
|
201
|
-
# t.jsonb :tool_calls
|
202
|
-
# t.jsonb :tool_results
|
203
|
-
# t.integer :token_count
|
204
|
-
# t.timestamps
|
205
|
-
end
|
94
|
+
model.context_window # => 200000
|
95
|
+
model.max_tokens # => 4096
|
96
|
+
model.supports_vision? # => true
|
97
|
+
model.supports_json_mode? # => true
|
206
98
|
```
|
207
99
|
|
208
|
-
|
100
|
+
## Coming Soon
|
209
101
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
redirect_to @conversation
|
215
|
-
end
|
216
|
-
|
217
|
-
def send_message
|
218
|
-
@conversation = current_user.conversations.find(params[:id])
|
219
|
-
|
220
|
-
message = @conversation.send_message(
|
221
|
-
params[:content],
|
222
|
-
model: params[:model]
|
223
|
-
)
|
224
|
-
|
225
|
-
render json: message
|
226
|
-
end
|
227
|
-
end
|
228
|
-
```
|
102
|
+
- Rails integration for seamless database and Active Record support
|
103
|
+
- Function calling / tool use capabilities
|
104
|
+
- Automatic retries and error handling
|
105
|
+
- Much more!
|
229
106
|
|
230
107
|
## Development
|
231
108
|
|
232
|
-
After checking out the repo, run `bin/setup` to install dependencies.
|
233
|
-
|
234
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
109
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt.
|
235
110
|
|
236
111
|
## Contributing
|
237
112
|
|
@@ -239,4 +114,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/crmne/
|
|
239
114
|
|
240
115
|
## License
|
241
116
|
|
242
|
-
|
117
|
+
Released under the MIT License. See LICENSE.txt for details.
|
data/bin/console
CHANGED
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
class Chat
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_reader :model, :messages, :tools
|
8
|
+
|
9
|
+
def initialize(model: nil)
|
10
|
+
model_id = model || RubyLLM.config.default_model
|
11
|
+
@model = Models.find(model_id)
|
12
|
+
@provider = Models.provider_for(model_id)
|
13
|
+
@messages = []
|
14
|
+
@tools = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def ask(message, &block)
|
18
|
+
add_message role: :user, content: message
|
19
|
+
complete(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def tool(tool)
|
23
|
+
raise Error, "Model #{@model.id} doesn't support function calling" unless @model.supports_functions
|
24
|
+
|
25
|
+
@tools << tool
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
alias with_tool tool
|
30
|
+
|
31
|
+
def tools(*tools)
|
32
|
+
tools.each { |tool| self.tool(tool) }
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
alias with_tools tools
|
37
|
+
|
38
|
+
def each(&block)
|
39
|
+
messages.each(&block)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def complete(&block)
|
45
|
+
response = @provider.complete(messages, tools: @tools, model: @model.id, &block)
|
46
|
+
|
47
|
+
if response.tool_call?
|
48
|
+
handle_tool_calls(response)
|
49
|
+
else
|
50
|
+
add_message(response)
|
51
|
+
end
|
52
|
+
|
53
|
+
response
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_tool_calls(response)
|
57
|
+
add_message(response)
|
58
|
+
|
59
|
+
response.tool_calls.each do |tool_call|
|
60
|
+
result = execute_tool(tool_call)
|
61
|
+
add_tool_result(tool_call[:id], result) if result
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get final response after tool calls
|
65
|
+
final_response = complete
|
66
|
+
add_message(final_response)
|
67
|
+
final_response
|
68
|
+
end
|
69
|
+
|
70
|
+
def execute_tool(tool_call)
|
71
|
+
tool = @tools.find { |t| t.name == tool_call[:name] }
|
72
|
+
return unless tool
|
73
|
+
|
74
|
+
args = JSON.parse(tool_call[:arguments], symbolize_names: true)
|
75
|
+
tool.call(args)
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_message(message_or_attributes)
|
79
|
+
message = message_or_attributes.is_a?(Message) ? message_or_attributes : Message.new(message_or_attributes)
|
80
|
+
messages << message
|
81
|
+
message
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_tool_result(tool_use_id, result)
|
85
|
+
add_message(
|
86
|
+
role: :user,
|
87
|
+
tool_results: {
|
88
|
+
tool_use_id: tool_use_id,
|
89
|
+
content: result.is_a?(Hash) && result[:error] ? result[:error] : result.to_s,
|
90
|
+
is_error: result.is_a?(Hash) && result[:error]
|
91
|
+
}
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -1,14 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RubyLLM
|
4
|
-
# Configuration class for RubyLLM settings
|
5
4
|
class Configuration
|
6
|
-
attr_accessor :openai_api_key, :anthropic_api_key, :
|
5
|
+
attr_accessor :openai_api_key, :anthropic_api_key, :default_model, :request_timeout
|
7
6
|
|
8
7
|
def initialize
|
9
8
|
@request_timeout = 30
|
10
|
-
@
|
11
|
-
@default_model = 'gpt-3.5-turbo'
|
9
|
+
@default_model = 'gpt-4o-mini'
|
12
10
|
end
|
13
11
|
|
14
12
|
def provider_settings
|
data/lib/ruby_llm/message.rb
CHANGED
@@ -2,18 +2,28 @@
|
|
2
2
|
|
3
3
|
module RubyLLM
|
4
4
|
class Message
|
5
|
-
|
6
|
-
|
7
|
-
attr_reader :role, :content, :tool_calls, :tool_results, :
|
8
|
-
|
9
|
-
def initialize(
|
10
|
-
@role = role.to_sym
|
11
|
-
@content = content
|
12
|
-
@tool_calls = tool_calls
|
13
|
-
@tool_results = tool_results
|
14
|
-
@
|
15
|
-
@
|
16
|
-
|
5
|
+
ROLES = %i[system user assistant tool].freeze
|
6
|
+
|
7
|
+
attr_reader :role, :content, :tool_calls, :tool_results, :input_tokens, :output_tokens, :model_id
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@role = options[:role].to_sym
|
11
|
+
@content = options[:content]
|
12
|
+
@tool_calls = options[:tool_calls]
|
13
|
+
@tool_results = options[:tool_results]
|
14
|
+
@input_tokens = options[:input_tokens]
|
15
|
+
@output_tokens = options[:output_tokens]
|
16
|
+
@model_id = options[:model_id]
|
17
|
+
|
18
|
+
ensure_valid_role
|
19
|
+
end
|
20
|
+
|
21
|
+
def tool_call?
|
22
|
+
!tool_calls.nil? && !tool_calls.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def tool_result?
|
26
|
+
!tool_results.nil? && !tool_results.empty?
|
17
27
|
end
|
18
28
|
|
19
29
|
def to_h
|
@@ -22,18 +32,16 @@ module RubyLLM
|
|
22
32
|
content: content,
|
23
33
|
tool_calls: tool_calls,
|
24
34
|
tool_results: tool_results,
|
25
|
-
|
35
|
+
input_tokens: input_tokens,
|
36
|
+
output_tokens: output_tokens,
|
26
37
|
model_id: model_id
|
27
38
|
}.compact
|
28
39
|
end
|
29
40
|
|
30
41
|
private
|
31
42
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
raise ArgumentError,
|
36
|
-
"Invalid role: #{role}. Must be one of: #{VALID_ROLES.join(', ')}"
|
43
|
+
def ensure_valid_role
|
44
|
+
raise Error, "Expected role to be one of: #{ROLES.join(', ')}" unless ROLES.include?(role)
|
37
45
|
end
|
38
46
|
end
|
39
47
|
end
|
@@ -2,71 +2,36 @@
|
|
2
2
|
|
3
3
|
module RubyLLM
|
4
4
|
module ModelCapabilities
|
5
|
-
|
5
|
+
module Anthropic
|
6
|
+
extend self
|
7
|
+
|
6
8
|
def determine_context_window(model_id)
|
7
9
|
case model_id
|
8
|
-
when /claude-3
|
9
|
-
|
10
|
-
200_000
|
11
|
-
else
|
12
|
-
100_000
|
10
|
+
when /claude-3/ then 200_000
|
11
|
+
else 100_000
|
13
12
|
end
|
14
13
|
end
|
15
14
|
|
16
15
|
def determine_max_tokens(model_id)
|
17
16
|
case model_id
|
18
|
-
when /claude-3-5
|
19
|
-
|
20
|
-
when /claude-3-opus/, /claude-3-sonnet/, /claude-3-haiku/
|
21
|
-
4_096
|
22
|
-
else
|
23
|
-
4_096
|
17
|
+
when /claude-3-5/ then 8_192
|
18
|
+
else 4_096
|
24
19
|
end
|
25
20
|
end
|
26
21
|
|
27
22
|
def get_input_price(model_id)
|
28
|
-
|
29
|
-
when /claude-3-5-sonnet/
|
30
|
-
3.0 # $3.00 per million tokens
|
31
|
-
when /claude-3-5-haiku/
|
32
|
-
0.80 # $0.80 per million tokens
|
33
|
-
when /claude-3-opus/
|
34
|
-
15.0 # $15.00 per million tokens
|
35
|
-
when /claude-3-sonnet/
|
36
|
-
3.0 # $3.00 per million tokens
|
37
|
-
when /claude-3-haiku/
|
38
|
-
0.25 # $0.25 per million tokens
|
39
|
-
else
|
40
|
-
3.0
|
41
|
-
end
|
23
|
+
PRICES.dig(model_family(model_id), :input) || default_input_price
|
42
24
|
end
|
43
25
|
|
44
26
|
def get_output_price(model_id)
|
45
|
-
|
46
|
-
when /claude-3-5-sonnet/
|
47
|
-
15.0 # $15.00 per million tokens
|
48
|
-
when /claude-3-5-haiku/
|
49
|
-
4.0 # $4.00 per million tokens
|
50
|
-
when /claude-3-opus/
|
51
|
-
75.0 # $75.00 per million tokens
|
52
|
-
when /claude-3-sonnet/
|
53
|
-
15.0 # $15.00 per million tokens
|
54
|
-
when /claude-3-haiku/
|
55
|
-
1.25 # $1.25 per million tokens
|
56
|
-
else
|
57
|
-
15.0
|
58
|
-
end
|
27
|
+
PRICES.dig(model_family(model_id), :output) || default_output_price
|
59
28
|
end
|
60
29
|
|
61
30
|
def supports_vision?(model_id)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
false
|
67
|
-
else
|
68
|
-
true
|
69
|
-
end
|
31
|
+
return false if model_id.match?(/claude-3-5-haiku/)
|
32
|
+
return false if model_id.match?(/claude-[12]/)
|
33
|
+
|
34
|
+
true
|
70
35
|
end
|
71
36
|
|
72
37
|
def supports_functions?(model_id)
|
@@ -76,6 +41,36 @@ module RubyLLM
|
|
76
41
|
def supports_json_mode?(model_id)
|
77
42
|
model_id.include?('claude-3')
|
78
43
|
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def model_family(model_id)
|
48
|
+
case model_id
|
49
|
+
when /claude-3-5-sonnet/ then :claude35_sonnet
|
50
|
+
when /claude-3-5-haiku/ then :claude35_haiku
|
51
|
+
when /claude-3-opus/ then :claude3_opus
|
52
|
+
when /claude-3-sonnet/ then :claude3_sonnet
|
53
|
+
when /claude-3-haiku/ then :claude3_haiku
|
54
|
+
else :claude2
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
PRICES = {
|
59
|
+
claude35_sonnet: { input: 3.0, output: 15.0 }, # $3.00/$15.00 per million tokens
|
60
|
+
claude35_haiku: { input: 0.80, output: 4.0 }, # $0.80/$4.00 per million tokens
|
61
|
+
claude3_opus: { input: 15.0, output: 75.0 }, # $15.00/$75.00 per million tokens
|
62
|
+
claude3_sonnet: { input: 3.0, output: 15.0 }, # $3.00/$15.00 per million tokens
|
63
|
+
claude3_haiku: { input: 0.25, output: 1.25 }, # $0.25/$1.25 per million tokens
|
64
|
+
claude2: { input: 3.0, output: 15.0 } # Default pricing for Claude 2.x models
|
65
|
+
}.freeze
|
66
|
+
|
67
|
+
def default_input_price
|
68
|
+
3.0
|
69
|
+
end
|
70
|
+
|
71
|
+
def default_output_price
|
72
|
+
15.0
|
73
|
+
end
|
79
74
|
end
|
80
75
|
end
|
81
76
|
end
|