ruby_llm 1.6.3 → 1.7.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 +6 -3
- data/lib/generators/ruby_llm/chat_ui/chat_ui_generator.rb +115 -0
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/chats_controller.rb.tt +39 -0
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/messages_controller.rb.tt +24 -0
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/models_controller.rb.tt +14 -0
- data/lib/generators/ruby_llm/chat_ui/templates/jobs/chat_response_job.rb.tt +12 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +16 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_form.html.erb.tt +29 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/index.html.erb.tt +16 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/new.html.erb.tt +11 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/show.html.erb.tt +23 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_form.html.erb.tt +21 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_message.html.erb.tt +10 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +9 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/_model.html.erb.tt +16 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/index.html.erb.tt +30 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/show.html.erb.tt +18 -0
- data/lib/generators/ruby_llm/install/templates/chat_model.rb.tt +2 -2
- data/lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt +4 -4
- data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +8 -7
- data/lib/generators/ruby_llm/install/templates/create_models_migration.rb.tt +43 -0
- data/lib/generators/ruby_llm/install/templates/create_tool_calls_migration.rb.tt +6 -5
- data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +10 -4
- data/lib/generators/ruby_llm/install/templates/message_model.rb.tt +4 -3
- data/lib/generators/ruby_llm/install/templates/model_model.rb.tt +3 -0
- data/lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt +2 -2
- data/lib/generators/ruby_llm/install_generator.rb +129 -33
- data/lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt +137 -0
- data/lib/generators/ruby_llm/upgrade_to_v1_7_generator.rb +160 -0
- data/lib/ruby_llm/active_record/acts_as.rb +112 -319
- data/lib/ruby_llm/active_record/acts_as_legacy.rb +398 -0
- data/lib/ruby_llm/active_record/chat_methods.rb +336 -0
- data/lib/ruby_llm/active_record/message_methods.rb +72 -0
- data/lib/ruby_llm/active_record/model_methods.rb +84 -0
- data/lib/ruby_llm/aliases.json +58 -13
- data/lib/ruby_llm/attachment.rb +20 -0
- data/lib/ruby_llm/chat.rb +8 -7
- data/lib/ruby_llm/configuration.rb +9 -0
- data/lib/ruby_llm/connection.rb +4 -4
- data/lib/ruby_llm/model/info.rb +12 -0
- data/lib/ruby_llm/models.json +3579 -2029
- data/lib/ruby_llm/models.rb +51 -22
- data/lib/ruby_llm/provider.rb +3 -3
- data/lib/ruby_llm/providers/anthropic/chat.rb +2 -2
- data/lib/ruby_llm/providers/anthropic/media.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/tools.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/chat.rb +2 -2
- data/lib/ruby_llm/providers/bedrock/models.rb +19 -1
- data/lib/ruby_llm/providers/gemini/chat.rb +53 -25
- data/lib/ruby_llm/providers/gemini/media.rb +1 -1
- data/lib/ruby_llm/providers/gpustack/chat.rb +11 -0
- data/lib/ruby_llm/providers/gpustack/media.rb +45 -0
- data/lib/ruby_llm/providers/gpustack/models.rb +44 -8
- data/lib/ruby_llm/providers/gpustack.rb +1 -0
- data/lib/ruby_llm/providers/ollama/media.rb +2 -6
- data/lib/ruby_llm/providers/ollama/models.rb +36 -0
- data/lib/ruby_llm/providers/ollama.rb +1 -0
- data/lib/ruby_llm/providers/openai/chat.rb +1 -1
- data/lib/ruby_llm/providers/openai/media.rb +4 -4
- data/lib/ruby_llm/providers/openai/tools.rb +11 -6
- data/lib/ruby_llm/providers/openai.rb +2 -2
- data/lib/ruby_llm/providers/vertexai/chat.rb +14 -0
- data/lib/ruby_llm/providers/vertexai/embeddings.rb +32 -0
- data/lib/ruby_llm/providers/vertexai/models.rb +130 -0
- data/lib/ruby_llm/providers/vertexai/streaming.rb +14 -0
- data/lib/ruby_llm/providers/vertexai.rb +55 -0
- data/lib/ruby_llm/railtie.rb +20 -3
- data/lib/ruby_llm/streaming.rb +1 -1
- data/lib/ruby_llm/utils.rb +5 -9
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +4 -3
- data/lib/tasks/models.rake +525 -0
- data/lib/tasks/release.rake +37 -2
- data/lib/tasks/ruby_llm.rake +15 -0
- data/lib/tasks/vcr.rake +2 -2
- metadata +37 -5
- data/lib/generators/ruby_llm/install/templates/INSTALL_INFO.md.tt +0 -108
- data/lib/tasks/aliases.rake +0 -205
- data/lib/tasks/models_docs.rake +0 -214
- data/lib/tasks/models_update.rake +0 -108
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
class VertexAI
|
6
|
+
# Chat methods for the Vertex AI implementation
|
7
|
+
module Chat
|
8
|
+
def completion_url
|
9
|
+
"projects/#{@config.vertexai_project_id}/locations/#{@config.vertexai_location}/publishers/google/models/#{@model}:generateContent" # rubocop:disable Layout/LineLength
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
class VertexAI
|
6
|
+
# Embeddings methods for the Vertex AI implementation
|
7
|
+
module Embeddings
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def embedding_url(model:)
|
11
|
+
"projects/#{@config.vertexai_project_id}/locations/#{@config.vertexai_location}/publishers/google/models/#{model}:predict" # rubocop:disable Layout/LineLength
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_embedding_payload(text, model:, dimensions:) # rubocop:disable Lint/UnusedMethodArgument
|
15
|
+
{
|
16
|
+
instances: [text].flatten.map { |t| { content: t.to_s } }
|
17
|
+
}.tap do |payload|
|
18
|
+
payload[:parameters] = { outputDimensionality: dimensions } if dimensions
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_embedding_response(response, model:, text:)
|
23
|
+
predictions = response.body['predictions']
|
24
|
+
vectors = predictions&.map { |p| p.dig('embeddings', 'values') }
|
25
|
+
vectors = vectors.first if vectors&.length == 1 && !text.is_a?(Array)
|
26
|
+
|
27
|
+
Embedding.new(vectors:, model:, input_tokens: 0)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
class VertexAI
|
6
|
+
# Models methods for the Vertex AI integration
|
7
|
+
module Models
|
8
|
+
# Gemini and other Google models that aren't returned by the API
|
9
|
+
KNOWN_GOOGLE_MODELS = %w[
|
10
|
+
gemini-2.5-flash-lite
|
11
|
+
gemini-2.5-pro
|
12
|
+
gemini-2.5-flash
|
13
|
+
gemini-2.0-flash-lite-001
|
14
|
+
gemini-2.0-flash-001
|
15
|
+
gemini-2.0-flash
|
16
|
+
gemini-2.0-flash-exp
|
17
|
+
gemini-1.5-pro-002
|
18
|
+
gemini-1.5-pro
|
19
|
+
gemini-1.5-flash-002
|
20
|
+
gemini-1.5-flash
|
21
|
+
gemini-1.5-flash-8b
|
22
|
+
gemini-pro
|
23
|
+
gemini-pro-vision
|
24
|
+
gemini-exp-1206
|
25
|
+
gemini-exp-1121
|
26
|
+
gemini-embedding-001
|
27
|
+
text-embedding-005
|
28
|
+
text-embedding-004
|
29
|
+
text-multilingual-embedding-002
|
30
|
+
].freeze
|
31
|
+
|
32
|
+
def list_models
|
33
|
+
all_models = []
|
34
|
+
page_token = nil
|
35
|
+
|
36
|
+
all_models.concat(build_known_models)
|
37
|
+
|
38
|
+
loop do
|
39
|
+
response = @connection.get('publishers/google/models') do |req|
|
40
|
+
req.headers['x-goog-user-project'] = @config.vertexai_project_id
|
41
|
+
req.params = { pageSize: 100 }
|
42
|
+
req.params[:pageToken] = page_token if page_token
|
43
|
+
end
|
44
|
+
|
45
|
+
publisher_models = response.body['publisherModels'] || []
|
46
|
+
publisher_models.each do |model_data|
|
47
|
+
next if model_data['launchStage'] == 'DEPRECATED'
|
48
|
+
|
49
|
+
model_id = extract_model_id_from_path(model_data['name'])
|
50
|
+
all_models << build_model_from_api_data(model_data, model_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
page_token = response.body['nextPageToken']
|
54
|
+
break unless page_token
|
55
|
+
end
|
56
|
+
|
57
|
+
all_models
|
58
|
+
rescue StandardError => e
|
59
|
+
RubyLLM.logger.debug "Error fetching Vertex AI models: #{e.message}"
|
60
|
+
build_known_models
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def build_known_models
|
66
|
+
KNOWN_GOOGLE_MODELS.map do |model_id|
|
67
|
+
Model::Info.new(
|
68
|
+
id: model_id,
|
69
|
+
name: model_id,
|
70
|
+
provider: slug,
|
71
|
+
family: determine_model_family(model_id),
|
72
|
+
created_at: nil,
|
73
|
+
context_window: nil,
|
74
|
+
max_output_tokens: nil,
|
75
|
+
modalities: nil,
|
76
|
+
capabilities: %w[streaming function_calling],
|
77
|
+
pricing: nil,
|
78
|
+
metadata: {
|
79
|
+
source: 'known_models'
|
80
|
+
}
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_model_from_api_data(model_data, model_id)
|
86
|
+
Model::Info.new(
|
87
|
+
id: model_id,
|
88
|
+
name: model_id,
|
89
|
+
provider: slug,
|
90
|
+
family: determine_model_family(model_id),
|
91
|
+
created_at: nil,
|
92
|
+
context_window: nil,
|
93
|
+
max_output_tokens: nil,
|
94
|
+
modalities: nil,
|
95
|
+
capabilities: extract_capabilities(model_data),
|
96
|
+
pricing: nil,
|
97
|
+
metadata: {
|
98
|
+
version_id: model_data['versionId'],
|
99
|
+
open_source_category: model_data['openSourceCategory'],
|
100
|
+
launch_stage: model_data['launchStage'],
|
101
|
+
supported_actions: model_data['supportedActions'],
|
102
|
+
publisher_model_template: model_data['publisherModelTemplate']
|
103
|
+
}
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
def extract_model_id_from_path(path)
|
108
|
+
path.split('/').last
|
109
|
+
end
|
110
|
+
|
111
|
+
def determine_model_family(model_id)
|
112
|
+
case model_id
|
113
|
+
when /^gemini-2\.\d+/ then 'gemini-2'
|
114
|
+
when /^gemini-1\.\d+/ then 'gemini-1.5'
|
115
|
+
when /^text-embedding/ then 'text-embedding'
|
116
|
+
when /bison/ then 'palm'
|
117
|
+
else 'gemini'
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def extract_capabilities(model_data)
|
122
|
+
capabilities = ['streaming']
|
123
|
+
model_name = model_data['name']
|
124
|
+
capabilities << 'function_calling' if model_name.include?('gemini')
|
125
|
+
capabilities.uniq
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
class VertexAI
|
6
|
+
# Streaming methods for the Vertex AI implementation
|
7
|
+
module Streaming
|
8
|
+
def stream_url
|
9
|
+
"projects/#{@config.vertexai_project_id}/locations/#{@config.vertexai_location}/publishers/google/models/#{@model}:streamGenerateContent?alt=sse" # rubocop:disable Layout/LineLength
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
# Google Vertex AI implementation
|
6
|
+
class VertexAI < Gemini
|
7
|
+
include VertexAI::Chat
|
8
|
+
include VertexAI::Streaming
|
9
|
+
include VertexAI::Embeddings
|
10
|
+
include VertexAI::Models
|
11
|
+
|
12
|
+
def initialize(config)
|
13
|
+
super
|
14
|
+
@authorizer = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def api_base
|
18
|
+
"https://#{@config.vertexai_location}-aiplatform.googleapis.com/v1beta1"
|
19
|
+
end
|
20
|
+
|
21
|
+
def headers
|
22
|
+
{
|
23
|
+
'Authorization' => "Bearer #{access_token}"
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
def configuration_requirements
|
29
|
+
%i[vertexai_project_id vertexai_location]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def access_token
|
36
|
+
return 'test-token' if defined?(VCR) && !VCR.current_cassette.recording?
|
37
|
+
|
38
|
+
initialize_authorizer unless @authorizer
|
39
|
+
@authorizer.fetch_access_token!['access_token']
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize_authorizer
|
43
|
+
require 'googleauth'
|
44
|
+
@authorizer = ::Google::Auth.get_application_default(
|
45
|
+
scope: [
|
46
|
+
'https://www.googleapis.com/auth/cloud-platform',
|
47
|
+
'https://www.googleapis.com/auth/generative-language.retriever'
|
48
|
+
]
|
49
|
+
)
|
50
|
+
rescue LoadError
|
51
|
+
raise Error, 'The googleauth gem is required for Vertex AI. Please add it to your Gemfile: gem "googleauth"'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/ruby_llm/railtie.rb
CHANGED
@@ -3,14 +3,31 @@
|
|
3
3
|
module RubyLLM
|
4
4
|
# Rails integration for RubyLLM
|
5
5
|
class Railtie < Rails::Railtie
|
6
|
+
initializer 'ruby_llm.inflections' do
|
7
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
8
|
+
inflect.acronym 'LLM'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
6
12
|
initializer 'ruby_llm.active_record' do
|
7
13
|
ActiveSupport.on_load :active_record do
|
8
|
-
|
14
|
+
if RubyLLM.config.use_new_acts_as
|
15
|
+
require 'ruby_llm/active_record/acts_as'
|
16
|
+
::ActiveRecord::Base.include RubyLLM::ActiveRecord::ActsAs
|
17
|
+
else
|
18
|
+
require 'ruby_llm/active_record/acts_as_legacy'
|
19
|
+
::ActiveRecord::Base.include RubyLLM::ActiveRecord::ActsAsLegacy
|
20
|
+
|
21
|
+
Rails.logger.warn(
|
22
|
+
"\n!!! RubyLLM's legacy acts_as API is deprecated and will be removed in RubyLLM 2.0.0. " \
|
23
|
+
"Please consult the migration guide at https://rubyllm.com/upgrading-to-1-7/\n"
|
24
|
+
)
|
25
|
+
end
|
9
26
|
end
|
10
27
|
end
|
11
28
|
|
12
|
-
|
13
|
-
|
29
|
+
rake_tasks do
|
30
|
+
load 'tasks/ruby_llm.rake'
|
14
31
|
end
|
15
32
|
end
|
16
33
|
end
|
data/lib/ruby_llm/streaming.rb
CHANGED
data/lib/ruby_llm/utils.rb
CHANGED
@@ -5,10 +5,6 @@ module RubyLLM
|
|
5
5
|
module Utils
|
6
6
|
module_function
|
7
7
|
|
8
|
-
def format_text_file_for_llm(text_file)
|
9
|
-
"<file name='#{text_file.filename}' mime_type='#{text_file.mime_type}'>#{text_file.content}</file>"
|
10
|
-
end
|
11
|
-
|
12
8
|
def hash_get(hash, key)
|
13
9
|
hash[key.to_sym] || hash[key.to_s]
|
14
10
|
end
|
@@ -36,12 +32,12 @@ module RubyLLM
|
|
36
32
|
value.is_a?(Date) ? value : Date.parse(value.to_s)
|
37
33
|
end
|
38
34
|
|
39
|
-
def deep_merge(
|
40
|
-
|
41
|
-
if
|
42
|
-
deep_merge(
|
35
|
+
def deep_merge(original, overrides)
|
36
|
+
original.merge(overrides) do |_key, original_value, overrides_value|
|
37
|
+
if original_value.is_a?(Hash) && overrides_value.is_a?(Hash)
|
38
|
+
deep_merge(original_value, overrides_value)
|
43
39
|
else
|
44
|
-
|
40
|
+
overrides_value
|
45
41
|
end
|
46
42
|
end
|
47
43
|
end
|
data/lib/ruby_llm/version.rb
CHANGED
data/lib/ruby_llm.rb
CHANGED
@@ -21,11 +21,11 @@ loader.inflector.inflect(
|
|
21
21
|
'openrouter' => 'OpenRouter',
|
22
22
|
'gpustack' => 'GPUStack',
|
23
23
|
'mistral' => 'Mistral',
|
24
|
-
'
|
24
|
+
'vertexai' => 'VertexAI',
|
25
|
+
'pdf' => 'PDF',
|
26
|
+
'UI' => 'UI'
|
25
27
|
)
|
26
28
|
loader.ignore("#{__dir__}/tasks")
|
27
|
-
loader.ignore("#{__dir__}/ruby_llm/railtie")
|
28
|
-
loader.ignore("#{__dir__}/ruby_llm/active_record")
|
29
29
|
loader.ignore("#{__dir__}/generators")
|
30
30
|
loader.setup
|
31
31
|
|
@@ -88,6 +88,7 @@ RubyLLM::Provider.register :ollama, RubyLLM::Providers::Ollama
|
|
88
88
|
RubyLLM::Provider.register :openai, RubyLLM::Providers::OpenAI
|
89
89
|
RubyLLM::Provider.register :openrouter, RubyLLM::Providers::OpenRouter
|
90
90
|
RubyLLM::Provider.register :perplexity, RubyLLM::Providers::Perplexity
|
91
|
+
RubyLLM::Provider.register :vertexai, RubyLLM::Providers::VertexAI
|
91
92
|
|
92
93
|
if defined?(Rails::Railtie)
|
93
94
|
require 'ruby_llm/railtie'
|