ruby_llm 1.8.1 → 1.8.2
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 +4 -4
- data/lib/generators/ruby_llm/chat_ui/chat_ui_generator.rb +117 -69
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/chats_controller.rb.tt +12 -12
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/messages_controller.rb.tt +7 -7
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/models_controller.rb.tt +4 -4
- data/lib/generators/ruby_llm/chat_ui/templates/jobs/chat_response_job.rb.tt +6 -6
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +4 -4
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_form.html.erb.tt +5 -5
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/index.html.erb.tt +5 -5
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/new.html.erb.tt +4 -4
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/show.html.erb.tt +8 -8
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_form.html.erb.tt +5 -5
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_message.html.erb.tt +9 -6
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_tool_calls.html.erb.tt +7 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +5 -5
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/_model.html.erb.tt +9 -9
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/index.html.erb.tt +4 -6
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/show.html.erb.tt +11 -11
- data/lib/generators/ruby_llm/generator_helpers.rb +131 -87
- data/lib/generators/ruby_llm/install/install_generator.rb +75 -79
- data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +1 -1
- data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +88 -85
- data/lib/ruby_llm/active_record/acts_as.rb +11 -2
- data/lib/ruby_llm/connection.rb +1 -1
- data/lib/ruby_llm/version.rb +1 -1
- metadata +2 -1
@@ -1,16 +1,16 @@
|
|
1
|
-
<tr id="<%%= dom_id <%= model_model_name.underscore %> %>">
|
2
|
-
<td><%%= <%= model_model_name.underscore %>.provider %></td>
|
3
|
-
<td><%%= <%= model_model_name.underscore %>.name %></td>
|
4
|
-
<td><%%= number_with_delimiter(<%= model_model_name.underscore %>.context_window) if <%= model_model_name.underscore %>.context_window %></td>
|
1
|
+
<tr id="<%%= dom_id <%= model_model_name.demodulize.underscore %> %>">
|
2
|
+
<td><%%= <%= model_model_name.demodulize.underscore %>.provider %></td>
|
3
|
+
<td><%%= <%= model_model_name.demodulize.underscore %>.name %></td>
|
4
|
+
<td><%%= number_with_delimiter(<%= model_model_name.demodulize.underscore %>.context_window) if <%= model_model_name.demodulize.underscore %>.context_window %></td>
|
5
5
|
<td>
|
6
|
-
<%% if <%= model_model_name.underscore %>.pricing && <%= model_model_name.underscore %>.pricing['text_tokens'] && <%= model_model_name.underscore %>.pricing['text_tokens']['standard'] %>
|
7
|
-
<%% input = <%= model_model_name.underscore %>.pricing['text_tokens']['standard']['input_per_million'] %>
|
8
|
-
<%% output = <%= model_model_name.underscore %>.pricing['text_tokens']['standard']['output_per_million'] %>
|
6
|
+
<%% if <%= model_model_name.demodulize.underscore %>.pricing && <%= model_model_name.demodulize.underscore %>.pricing['text_tokens'] && <%= model_model_name.demodulize.underscore %>.pricing['text_tokens']['standard'] %>
|
7
|
+
<%% input = <%= model_model_name.demodulize.underscore %>.pricing['text_tokens']['standard']['input_per_million'] %>
|
8
|
+
<%% output = <%= model_model_name.demodulize.underscore %>.pricing['text_tokens']['standard']['output_per_million'] %>
|
9
9
|
<%% if input && output %>
|
10
10
|
$<%%= "%.2f" % input %> / $<%%= "%.2f" % output %>
|
11
11
|
<%% end %>
|
12
12
|
<%% end %>
|
13
13
|
</td>
|
14
|
-
<td><%%= link_to "Show", <%= model_model_name.underscore %> %></td>
|
15
|
-
<td><%%= link_to "Start <%=
|
14
|
+
<td><%%= link_to "Show", <%= model_model_name.demodulize.underscore %> %></td>
|
15
|
+
<td><%%= link_to "Start <%= chat_table_name.singularize.humanize.downcase %>", new_<%= chat_variable_name %>_path(model: <%= model_model_name.demodulize.underscore %>.model_id) %></td>
|
16
16
|
</tr>
|
@@ -5,10 +5,10 @@
|
|
5
5
|
<h1><%= model_model_name.pluralize %></h1>
|
6
6
|
|
7
7
|
<p>
|
8
|
-
<%%= button_to "Refresh <%= model_model_name.pluralize %>", refresh_<%=
|
8
|
+
<%%= button_to "Refresh <%= model_model_name.pluralize %>", refresh_<%= model_table_name %>_path, method: :post %>
|
9
9
|
</p>
|
10
10
|
|
11
|
-
<div id="<%=
|
11
|
+
<div id="<%= model_table_name %>">
|
12
12
|
<table>
|
13
13
|
<thead>
|
14
14
|
<tr>
|
@@ -20,11 +20,9 @@
|
|
20
20
|
</tr>
|
21
21
|
</thead>
|
22
22
|
<tbody>
|
23
|
-
|
24
|
-
<%%= render <%= model_model_name.underscore %> %>
|
25
|
-
<%% end %>
|
23
|
+
<%%= render @<%= model_variable_name.pluralize %> %>
|
26
24
|
</tbody>
|
27
25
|
</table>
|
28
26
|
</div>
|
29
27
|
|
30
|
-
<%%= link_to "Back to <%=
|
28
|
+
<%%= link_to "Back to <%= chat_table_name.humanize.downcase %>", <%= chat_table_name %>_path %>
|
@@ -1,18 +1,18 @@
|
|
1
|
-
<%% content_for :title,
|
1
|
+
<%% content_for :title, @<%= model_variable_name %>.name %>
|
2
2
|
|
3
|
-
<h1><%%=
|
3
|
+
<h1><%%= @<%= model_variable_name %>.name %></h1>
|
4
4
|
|
5
|
-
<p><strong>ID:</strong> <%%=
|
6
|
-
<p><strong>Provider:</strong> <%%=
|
7
|
-
<p><strong>Context Window:</strong> <%%= number_with_delimiter(
|
8
|
-
<p><strong>Max Output:</strong> <%%= number_with_delimiter(
|
5
|
+
<p><strong>ID:</strong> <%%= @<%= model_variable_name %>.model_id %></p>
|
6
|
+
<p><strong>Provider:</strong> <%%= @<%= model_variable_name %>.provider %></p>
|
7
|
+
<p><strong>Context Window:</strong> <%%= number_with_delimiter(@<%= model_variable_name %>.context_window) %> tokens</p>
|
8
|
+
<p><strong>Max Output:</strong> <%%= number_with_delimiter(@<%= model_variable_name %>.max_output_tokens) %> tokens</p>
|
9
9
|
|
10
|
-
<%% if
|
11
|
-
<p><strong>Capabilities:</strong> <%%=
|
10
|
+
<%% if @<%= model_variable_name %>.capabilities.any? %>
|
11
|
+
<p><strong>Capabilities:</strong> <%%= @<%= model_variable_name %>.capabilities.join(", ") %></p>
|
12
12
|
<%% end %>
|
13
13
|
|
14
14
|
<p>
|
15
|
-
<%%= link_to "Start chat with this model",
|
16
|
-
<%%= link_to "All models",
|
17
|
-
<%%= link_to "Back to chats",
|
15
|
+
<%%= link_to "Start chat with this model", new_<%= chat_variable_name %>_path(model: @<%= model_variable_name %>.model_id) %> |
|
16
|
+
<%%= link_to "All models", <%= model_table_name %>_path %> |
|
17
|
+
<%%= link_to "Back to chats", <%= chat_table_name %>_path %>
|
18
18
|
</p>
|
@@ -1,129 +1,173 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RubyLLM
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
4
|
+
module Generators
|
5
|
+
# Shared helpers for RubyLLM generators
|
6
|
+
module GeneratorHelpers
|
7
|
+
def parse_model_mappings
|
8
|
+
@model_names = {
|
9
|
+
chat: 'Chat',
|
10
|
+
message: 'Message',
|
11
|
+
tool_call: 'ToolCall',
|
12
|
+
model: 'Model'
|
13
|
+
}
|
14
|
+
|
15
|
+
model_mappings.each do |mapping|
|
16
|
+
if mapping.include?(':')
|
17
|
+
key, value = mapping.split(':', 2)
|
18
|
+
@model_names[key.to_sym] = value.classify
|
19
|
+
end
|
18
20
|
end
|
21
|
+
|
22
|
+
@model_names
|
19
23
|
end
|
20
24
|
|
21
|
-
|
22
|
-
|
25
|
+
%i[chat message tool_call model].each do |type|
|
26
|
+
define_method("#{type}_model_name") do
|
27
|
+
@model_names ||= parse_model_mappings
|
28
|
+
@model_names[type]
|
29
|
+
end
|
23
30
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
define_method("#{type}_table_name") do
|
32
|
+
table_name_for(send("#{type}_model_name"))
|
33
|
+
end
|
34
|
+
|
35
|
+
define_method("#{type}_variable_name") do
|
36
|
+
variable_name_for(send("#{type}_model_name"))
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method("#{type}_controller_class_name") do
|
40
|
+
controller_class_name_for(send("#{type}_model_name"))
|
41
|
+
end
|
42
|
+
|
43
|
+
define_method("#{type}_job_class_name") do
|
44
|
+
"#{variable_name_for(send("#{type}_model_name")).camelize}ResponseJob"
|
45
|
+
end
|
29
46
|
|
30
|
-
|
31
|
-
|
47
|
+
define_method("#{type}_partial") do
|
48
|
+
partial_path_for(send("#{type}_model_name"))
|
49
|
+
end
|
32
50
|
end
|
33
|
-
end
|
34
51
|
|
35
|
-
|
36
|
-
|
52
|
+
def acts_as_chat_declaration
|
53
|
+
params = []
|
37
54
|
|
38
|
-
|
39
|
-
|
55
|
+
add_association_params(params, :messages, message_table_name, message_model_name, plural: true)
|
56
|
+
add_association_params(params, :model, model_table_name, model_model_name)
|
40
57
|
|
41
|
-
|
42
|
-
|
58
|
+
"acts_as_chat#{" #{params.join(', ')}" if params.any?}"
|
59
|
+
end
|
43
60
|
|
44
|
-
|
45
|
-
|
61
|
+
def acts_as_message_declaration
|
62
|
+
params = []
|
46
63
|
|
47
|
-
|
48
|
-
|
49
|
-
|
64
|
+
add_association_params(params, :chat, chat_table_name, chat_model_name)
|
65
|
+
add_association_params(params, :tool_calls, tool_call_table_name, tool_call_model_name, plural: true)
|
66
|
+
add_association_params(params, :model, model_table_name, model_model_name)
|
50
67
|
|
51
|
-
|
52
|
-
|
68
|
+
"acts_as_message#{" #{params.join(', ')}" if params.any?}"
|
69
|
+
end
|
53
70
|
|
54
|
-
|
55
|
-
|
71
|
+
def acts_as_model_declaration
|
72
|
+
params = []
|
56
73
|
|
57
|
-
|
74
|
+
add_association_params(params, :chats, chat_table_name, chat_model_name, plural: true)
|
58
75
|
|
59
|
-
|
60
|
-
|
76
|
+
"acts_as_model#{" #{params.join(', ')}" if params.any?}"
|
77
|
+
end
|
61
78
|
|
62
|
-
|
63
|
-
|
79
|
+
def acts_as_tool_call_declaration
|
80
|
+
params = []
|
64
81
|
|
65
|
-
|
82
|
+
add_association_params(params, :message, message_table_name, message_model_name)
|
66
83
|
|
67
|
-
|
68
|
-
|
84
|
+
"acts_as_tool_call#{" #{params.join(', ')}" if params.any?}"
|
85
|
+
end
|
69
86
|
|
70
|
-
|
71
|
-
|
87
|
+
def create_namespace_modules
|
88
|
+
namespaces = []
|
72
89
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
90
|
+
[chat_model_name, message_model_name, tool_call_model_name, model_model_name].each do |model_name|
|
91
|
+
if model_name.include?('::')
|
92
|
+
namespace = model_name.split('::').first
|
93
|
+
namespaces << namespace unless namespaces.include?(namespace)
|
94
|
+
end
|
77
95
|
end
|
78
|
-
end
|
79
96
|
|
80
|
-
|
81
|
-
|
82
|
-
|
97
|
+
namespaces.each do |namespace|
|
98
|
+
module_path = "app/models/#{namespace.underscore}.rb"
|
99
|
+
next if File.exist?(Rails.root.join(module_path))
|
83
100
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
101
|
+
create_file module_path do
|
102
|
+
<<~RUBY
|
103
|
+
module #{namespace}
|
104
|
+
def self.table_name_prefix
|
105
|
+
"#{namespace.underscore}_"
|
106
|
+
end
|
89
107
|
end
|
90
|
-
|
91
|
-
|
108
|
+
RUBY
|
109
|
+
end
|
92
110
|
end
|
93
111
|
end
|
94
|
-
end
|
95
112
|
|
96
|
-
|
97
|
-
|
98
|
-
|
113
|
+
def migration_version
|
114
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
115
|
+
end
|
99
116
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
117
|
+
def postgresql?
|
118
|
+
::ActiveRecord::Base.connection.adapter_name.downcase.include?('postgresql')
|
119
|
+
rescue StandardError
|
120
|
+
false
|
121
|
+
end
|
105
122
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
123
|
+
def table_exists?(table_name)
|
124
|
+
::ActiveRecord::Base.connection.table_exists?(table_name)
|
125
|
+
rescue StandardError
|
126
|
+
false
|
127
|
+
end
|
111
128
|
|
112
|
-
|
129
|
+
private
|
113
130
|
|
114
|
-
|
115
|
-
|
131
|
+
def add_association_params(params, default_assoc, table_name, model_name, plural: false)
|
132
|
+
assoc = plural ? table_name.to_sym : table_name.singularize.to_sym
|
116
133
|
|
117
|
-
|
134
|
+
return if assoc == default_assoc
|
118
135
|
|
119
|
-
|
120
|
-
|
121
|
-
|
136
|
+
params << "#{default_assoc}: :#{assoc}"
|
137
|
+
params << "#{default_assoc.to_s.singularize}_class: '#{model_name}'" if model_name != assoc.to_s.classify
|
138
|
+
end
|
122
139
|
|
123
|
-
def table_name_for(model_name)
|
124
140
|
# Convert namespaced model names to proper table names
|
125
141
|
# e.g., "Assistant::Chat" -> "assistant_chats" (not "assistant/chats")
|
126
|
-
model_name
|
142
|
+
def table_name_for(model_name)
|
143
|
+
model_name.underscore.pluralize.tr('/', '_')
|
144
|
+
end
|
145
|
+
|
146
|
+
# Convert model name to instance variable name
|
147
|
+
# e.g., "LLM::Chat" -> "llm_chat" (not "llm/chat")
|
148
|
+
def variable_name_for(model_name)
|
149
|
+
model_name.underscore.tr('/', '_')
|
150
|
+
end
|
151
|
+
|
152
|
+
# Convert model name to controller class name
|
153
|
+
# For namespaced models, use Rails convention: "Llm::Chat" -> "Llm::ChatsController"
|
154
|
+
# For regular models: "Chat" -> "ChatsController"
|
155
|
+
def controller_class_name_for(model_name)
|
156
|
+
if model_name.include?('::')
|
157
|
+
parts = model_name.split('::')
|
158
|
+
namespace = parts[0..-2].join('::')
|
159
|
+
resource = parts.last.pluralize
|
160
|
+
"#{namespace}::#{resource}Controller"
|
161
|
+
else
|
162
|
+
"#{model_name.pluralize}Controller"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Convert model name to partial path
|
167
|
+
# e.g., "LLM::Message" -> "llm/message" (not "llm_message")
|
168
|
+
def partial_path_for(model_name)
|
169
|
+
"#{model_name.underscore.pluralize}/#{model_name.demodulize.underscore}"
|
170
|
+
end
|
127
171
|
end
|
128
172
|
end
|
129
173
|
end
|
@@ -5,106 +5,102 @@ require 'rails/generators/active_record'
|
|
5
5
|
require_relative '../generator_helpers'
|
6
6
|
|
7
7
|
module RubyLLM
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
module Generators
|
9
|
+
# Generator for RubyLLM Rails models and migrations
|
10
|
+
class InstallGenerator < Rails::Generators::Base
|
11
|
+
include Rails::Generators::Migration
|
12
|
+
include RubyLLM::Generators::GeneratorHelpers
|
12
13
|
|
13
|
-
|
14
|
+
namespace 'ruby_llm:install'
|
14
15
|
|
15
|
-
|
16
|
+
source_root File.expand_path('templates', __dir__)
|
16
17
|
|
17
|
-
|
18
|
+
argument :model_mappings, type: :array, default: [], banner: 'chat:ChatName message:MessageName ...'
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
class_option :skip_active_storage, type: :boolean, default: false,
|
21
|
+
desc: 'Skip ActiveStorage installation and attachment setup'
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
desc 'Creates models and migrations for RubyLLM Rails integration\n' \
|
24
|
+
'Usage: rails g ruby_llm:install [chat:ChatName] [message:MessageName] ...'
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
def self.next_migration_number(dirname)
|
27
|
+
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
migration_template 'create_chats_migration.rb.tt',
|
33
|
-
"db/migrate/create_#{chat_table_name}.rb"
|
34
|
-
|
35
|
-
# Then create messages table
|
36
|
-
sleep 1 # Ensure different timestamp
|
37
|
-
migration_template 'create_messages_migration.rb.tt',
|
38
|
-
"db/migrate/create_#{message_table_name}.rb"
|
39
|
-
|
40
|
-
# Then create tool_calls table
|
41
|
-
sleep 1 # Ensure different timestamp
|
42
|
-
migration_template 'create_tool_calls_migration.rb.tt',
|
43
|
-
"db/migrate/create_#{tool_call_table_name}.rb"
|
44
|
-
|
45
|
-
# Create models table
|
46
|
-
sleep 1 # Ensure different timestamp
|
47
|
-
migration_template 'create_models_migration.rb.tt',
|
48
|
-
"db/migrate/create_#{model_table_name}.rb"
|
49
|
-
|
50
|
-
# Add references to chats, tool_calls and messages.
|
51
|
-
sleep 1 # Ensure different timestamp
|
52
|
-
migration_template 'add_references_to_chats_tool_calls_and_messages_migration.rb.tt',
|
53
|
-
'db/migrate/add_references_to_' \
|
54
|
-
"#{chat_table_name}_#{tool_call_table_name}_and_#{message_table_name}.rb"
|
55
|
-
end
|
30
|
+
def create_migration_files
|
31
|
+
migration_template 'create_chats_migration.rb.tt',
|
32
|
+
"db/migrate/create_#{chat_table_name}.rb"
|
56
33
|
|
57
|
-
|
58
|
-
|
34
|
+
sleep 1 # Ensure different timestamp
|
35
|
+
migration_template 'create_messages_migration.rb.tt',
|
36
|
+
"db/migrate/create_#{message_table_name}.rb"
|
59
37
|
|
60
|
-
|
61
|
-
|
62
|
-
|
38
|
+
sleep 1 # Ensure different timestamp
|
39
|
+
migration_template 'create_tool_calls_migration.rb.tt',
|
40
|
+
"db/migrate/create_#{tool_call_table_name}.rb"
|
63
41
|
|
64
|
-
|
65
|
-
|
42
|
+
sleep 1 # Ensure different timestamp
|
43
|
+
migration_template 'create_models_migration.rb.tt',
|
44
|
+
"db/migrate/create_#{model_table_name}.rb"
|
66
45
|
|
67
|
-
|
68
|
-
|
69
|
-
|
46
|
+
sleep 1 # Ensure different timestamp
|
47
|
+
migration_template 'add_references_to_chats_tool_calls_and_messages_migration.rb.tt',
|
48
|
+
'db/migrate/add_references_to_' \
|
49
|
+
"#{chat_table_name}_#{tool_call_table_name}_and_#{message_table_name}.rb"
|
50
|
+
end
|
70
51
|
|
71
|
-
|
72
|
-
|
52
|
+
def create_model_files
|
53
|
+
create_namespace_modules
|
73
54
|
|
74
|
-
|
75
|
-
|
76
|
-
|
55
|
+
template 'chat_model.rb.tt', "app/models/#{chat_model_name.underscore}.rb"
|
56
|
+
template 'message_model.rb.tt', "app/models/#{message_model_name.underscore}.rb"
|
57
|
+
template 'tool_call_model.rb.tt', "app/models/#{tool_call_model_name.underscore}.rb"
|
58
|
+
|
59
|
+
template 'model_model.rb.tt', "app/models/#{model_model_name.underscore}.rb"
|
60
|
+
end
|
77
61
|
|
78
|
-
|
79
|
-
|
62
|
+
def create_initializer
|
63
|
+
template 'initializer.rb.tt', 'config/initializers/ruby_llm.rb'
|
64
|
+
end
|
80
65
|
|
81
|
-
|
66
|
+
def install_active_storage
|
67
|
+
return if options[:skip_active_storage]
|
82
68
|
|
83
|
-
|
84
|
-
|
85
|
-
|
69
|
+
say ' Installing ActiveStorage for file attachments...', :cyan
|
70
|
+
rails_command 'active_storage:install'
|
71
|
+
end
|
86
72
|
|
87
|
-
|
73
|
+
def show_install_info
|
74
|
+
say "\n ✅ RubyLLM installed!", :green
|
88
75
|
|
89
|
-
|
90
|
-
say ' Models automatically load from the database'
|
91
|
-
say ' Pass model names as strings - RubyLLM handles the rest!'
|
92
|
-
say " Specify provider when needed: Chat.create!(model: 'gemini-2.5-flash', provider: 'vertexai')"
|
76
|
+
say ' ✅ ActiveStorage configured for file attachments support', :green unless options[:skip_active_storage]
|
93
77
|
|
94
|
-
|
95
|
-
say
|
96
|
-
say '
|
97
|
-
say ' To enable later:'
|
98
|
-
say ' 1. Run: rails active_storage:install && rails db:migrate'
|
99
|
-
say " 2. Add to your #{message_model_name} model: has_many_attached :attachments"
|
100
|
-
end
|
78
|
+
say "\n Next steps:", :yellow
|
79
|
+
say ' 1. Run: rails db:migrate'
|
80
|
+
say ' 2. Set your API keys in config/initializers/ruby_llm.rb'
|
101
81
|
|
102
|
-
|
82
|
+
say " 3. Start chatting: #{chat_model_name}.create!(model: 'gpt-4.1-nano').ask('Hello!')"
|
103
83
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
84
|
+
say "\n 🚀 Model registry is database-backed!", :cyan
|
85
|
+
say ' Models automatically load from the database'
|
86
|
+
say ' Pass model names as strings - RubyLLM handles the rest!'
|
87
|
+
say " Specify provider when needed: Chat.create!(model: 'gemini-2.5-flash', provider: 'vertexai')"
|
88
|
+
|
89
|
+
if options[:skip_active_storage]
|
90
|
+
say "\n 📎 Note: ActiveStorage was skipped", :yellow
|
91
|
+
say ' File attachments won\'t work without ActiveStorage.'
|
92
|
+
say ' To enable later:'
|
93
|
+
say ' 1. Run: rails active_storage:install && rails db:migrate'
|
94
|
+
say " 2. Add to your #{message_model_name} model: has_many_attached :attachments"
|
95
|
+
end
|
96
|
+
|
97
|
+
say "\n 📚 Documentation: https://rubyllm.com", :cyan
|
98
|
+
|
99
|
+
say "\n ❤️ Love RubyLLM?", :magenta
|
100
|
+
say ' • ⭐ Star on GitHub: https://github.com/crmne/ruby_llm'
|
101
|
+
say ' • 🐦 Follow for updates: https://x.com/paolino'
|
102
|
+
say "\n"
|
103
|
+
end
|
108
104
|
end
|
109
105
|
end
|
110
106
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
RubyLLM.configure do |config|
|
2
|
-
config.openai_api_key = Rails.application.credentials.dig(:openai_api_key)
|
2
|
+
config.openai_api_key = ENV['OPENAI_API_KEY'] || Rails.application.credentials.dig(:openai_api_key)
|
3
3
|
# config.default_model = "gpt-4.1-nano"
|
4
4
|
|
5
5
|
# Use the new association-based acts_as API (recommended)
|