ruby_llm 1.7.1 → 1.8.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ceecb8e7cd289f58ac1f76648306f61b54482a9b6f845a2f08b3303ee746a634
4
- data.tar.gz: 3c075c03ccd1d7b841b99b58a1a4cda9289370b8dea039070cd78ede2d18a41c
3
+ metadata.gz: c8662c9b8b38e5941ea7e66882d59e8583989135285bc4b7eaaf5b83c8c2326e
4
+ data.tar.gz: 33c168dc4d68d4cffb18bb0761adc42da51288a43aee78633d30f669bffaa47f
5
5
  SHA512:
6
- metadata.gz: 16ac70cc9787c0d845b5ad4c62171cb225752f160506864b07fdb0b2c1b27adc147e9799a1f13e9d7a5169595d247e5b6bc0c1083dc523647aa13e750b1d6f9d
7
- data.tar.gz: 80543faec7119044c345f6751059e05e4cf76457ad3b288da38ea7c4e1338570fcbca1c8ad8e9dad84fb7ac5983998fd1ceba481b2e244d3542f59481a4d0e7f
6
+ metadata.gz: 6f94e7adcf5b6f50aca97718c615d8dfa681a483da841ca8214f3970ca918a2a8e384f07a494dad9db83da269068a502ab8caf14a441a2ecb86909617e06fdf9
7
+ data.tar.gz: 8342ae03bb413eb4b65b55c73629b1729b319e96e6976172fcaaa8ed19231280b5773eb8acccf4f563d63c801a78a03b20be5552189f86a4a7e435fb426c354f
data/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  Battle tested at [<picture><source media="(prefers-color-scheme: dark)" srcset="https://chatwithwork.com/logotype-dark.svg"><img src="https://chatwithwork.com/logotype.svg" alt="Chat with Work" height="30" align="absmiddle"></picture>](https://chatwithwork.com) — *Claude Code for your documents*
11
11
 
12
- [![Gem Version](https://badge.fury.io/rb/ruby_llm.svg?a=8)](https://badge.fury.io/rb/ruby_llm)
12
+ [![Gem Version](https://badge.fury.io/rb/ruby_llm.svg?a=10)](https://badge.fury.io/rb/ruby_llm)
13
13
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
14
14
  [![Gem Downloads](https://img.shields.io/gem/dt/ruby_llm)](https://rubygems.org/gems/ruby_llm)
15
15
  [![codecov](https://codecov.io/gh/crmne/ruby_llm/branch/main/graph/badge.svg?a=2)](https://codecov.io/gh/crmne/ruby_llm)
@@ -41,6 +41,7 @@ chat.ask "What's the best way to learn Ruby?"
41
41
  ```ruby
42
42
  # Analyze any file type
43
43
  chat.ask "What's in this image?", with: "ruby_conf.jpg"
44
+ chat.ask "What's happening in this video?", with: "video.mp4"
44
45
  chat.ask "Describe this meeting", with: "meeting.wav"
45
46
  chat.ask "Summarize this document", with: "contract.pdf"
46
47
  chat.ask "Explain this code", with: "app.rb"
@@ -68,6 +69,11 @@ RubyLLM.paint "a sunset over mountains in watercolor style"
68
69
  RubyLLM.embed "Ruby is elegant and expressive"
69
70
  ```
70
71
 
72
+ ```ruby
73
+ # Moderate content for safety
74
+ RubyLLM.moderate("Check if this text is safe").flagged? # => false
75
+ ```
76
+
71
77
  ```ruby
72
78
  # Let AI use your code
73
79
  class Weather < RubyLLM::Tool
@@ -100,11 +106,12 @@ response = chat.with_schema(ProductSchema).ask "Analyze this product", with: "pr
100
106
  ## Features
101
107
 
102
108
  * **Chat:** Conversational AI with `RubyLLM.chat`
103
- * **Vision:** Analyze images and screenshots
109
+ * **Vision:** Analyze images and videos
104
110
  * **Audio:** Transcribe and understand speech
105
111
  * **Documents:** Extract from PDFs, CSVs, JSON, any file type
106
112
  * **Image generation:** Create images with `RubyLLM.paint`
107
113
  * **Embeddings:** Vector search with `RubyLLM.embed`
114
+ * **Moderation:** Content safety with `RubyLLM.moderate`
108
115
  * **Tools:** Let AI call your Ruby methods
109
116
  * **Structured output:** JSON schemas that just work
110
117
  * **Streaming:** Real-time responses with blocks
@@ -132,7 +139,11 @@ end
132
139
  ## Rails
133
140
 
134
141
  ```bash
142
+ # Install database models
135
143
  rails generate ruby_llm:install
144
+
145
+ # Add chat UI (optional)
146
+ rails generate ruby_llm:chat_ui
136
147
  ```
137
148
 
138
149
  ```ruby
@@ -140,10 +151,12 @@ class Chat < ApplicationRecord
140
151
  acts_as_chat
141
152
  end
142
153
 
143
- chat = Chat.create! model_id: "claude-sonnet-4"
154
+ chat = Chat.create! model: "claude-sonnet-4"
144
155
  chat.ask "What's in this file?", with: "report.pdf"
145
156
  ```
146
157
 
158
+ Visit `http://localhost:3000/chats` for a ready-to-use chat interface!
159
+
147
160
  ## Documentation
148
161
 
149
162
  [rubyllm.com](https://rubyllm.com)
@@ -56,6 +56,7 @@ module RubyLLM
56
56
  # Message views
57
57
  template 'views/messages/_message.html.erb',
58
58
  "app/views/#{message_table_name}/_#{message_model_name.underscore}.html.erb"
59
+ template 'views/messages/_content.html.erb', "app/views/#{message_table_name}/_content.html.erb"
59
60
  template 'views/messages/_form.html.erb', "app/views/#{message_table_name}/_form.html.erb"
60
61
  template 'views/messages/create.turbo_stream.erb',
61
62
  "app/views/#{message_table_name}/create.turbo_stream.erb"
@@ -99,12 +100,23 @@ module RubyLLM
99
100
  chat_var = chat_model_name.underscore
100
101
  broadcasting_code = "broadcasts_to ->(#{msg_var}) { \"#{chat_var}_\#{#{msg_var}.#{chat_var}_id}\" }"
101
102
 
102
- inject_into_class "app/models/#{msg_var}.rb", message_model_name do
103
- "\n #{broadcasting_code}\n"
103
+ broadcast_append_chunk_method = <<-RUBY
104
+
105
+ def broadcast_append_chunk(content)
106
+ broadcast_append_to "#{chat_var}_\#{#{chat_var}_id}",
107
+ target: "#{msg_var}_\#{id}_content",
108
+ partial: "#{message_table_name}/content",
109
+ locals: { content: content }
110
+ end
111
+ RUBY
112
+
113
+ inject_into_file "app/models/#{msg_var}.rb", before: "end\n" do
114
+ " #{broadcasting_code}\n#{broadcast_append_chunk_method}"
104
115
  end
105
116
  rescue Errno::ENOENT
106
117
  say "#{message_model_name} model not found. Add broadcasting code to your model.", :yellow
107
118
  say " #{broadcasting_code}", :yellow
119
+ say broadcast_append_chunk_method, :yellow
108
120
  end
109
121
 
110
122
  def display_post_install_message
@@ -5,7 +5,7 @@ class <%= chat_model_name %>ResponseJob < ApplicationJob
5
5
  <%= chat_model_name.underscore %>.ask(content) do |chunk|
6
6
  if chunk.content && !chunk.content.blank?
7
7
  <%= message_model_name.underscore %> = <%= chat_model_name.underscore %>.<%= message_model_name.tableize %>.last
8
- <%= message_model_name.underscore %>.update!(content: <%= message_model_name.underscore %>.content + chunk.content)
8
+ <%= message_model_name.underscore %>.broadcast_append_chunk(chunk.content)
9
9
  end
10
10
  end
11
11
  end
@@ -3,7 +3,7 @@
3
3
  <div style="font-weight: bold; margin-bottom: 5px;">
4
4
  <%%= <%= message_model_name.underscore %>.role&.capitalize %>
5
5
  </div>
6
- <div style="white-space: pre-wrap;"><%%= <%= message_model_name.underscore %>.content %></div>
6
+ <div id="<%%= dom_id(<%= message_model_name.underscore %>) %>_content" style="white-space: pre-wrap;"><%%= <%= message_model_name.underscore %>.content %></div>
7
7
  <div style="font-size: 0.85em; color: #666; margin-top: 5px;">
8
8
  <%%= <%= message_model_name.underscore %>.created_at&.strftime("%I:%M %p") %>
9
9
  </div>
@@ -32,12 +32,12 @@ module RubyLLM
32
32
  migration_template 'create_chats_migration.rb.tt',
33
33
  "db/migrate/create_#{chat_table_name}.rb"
34
34
 
35
- # Then create messages table (must come before tool_calls due to foreign key)
35
+ # Then create messages table
36
36
  sleep 1 # Ensure different timestamp
37
37
  migration_template 'create_messages_migration.rb.tt',
38
38
  "db/migrate/create_#{message_table_name}.rb"
39
39
 
40
- # Then create tool_calls table (references messages)
40
+ # Then create tool_calls table
41
41
  sleep 1 # Ensure different timestamp
42
42
  migration_template 'create_tool_calls_migration.rb.tt',
43
43
  "db/migrate/create_#{tool_call_table_name}.rb"
@@ -46,6 +46,12 @@ module RubyLLM
46
46
  sleep 1 # Ensure different timestamp
47
47
  migration_template 'create_models_migration.rb.tt',
48
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"
49
55
  end
50
56
 
51
57
  def create_model_files
@@ -0,0 +1,9 @@
1
+ class AddReferencesTo<%= "#{chat_model_name.gsub('::', '').pluralize}#{tool_call_model_name.gsub('::', '').pluralize}And#{message_model_name.gsub('::', '').pluralize}" %> < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ add_reference :<%= chat_table_name %>, :<%= model_table_name.singularize %>, foreign_key: true
4
+ add_reference :<%= tool_call_table_name %>, :<%= message_table_name.singularize %>, null: false, foreign_key: true
5
+ add_reference :<%= message_table_name %>, :<%= chat_table_name.singularize %>, null: false, foreign_key: true
6
+ add_reference :<%= message_table_name %>, :<%= model_table_name.singularize %>, foreign_key: true
7
+ add_reference :<%= message_table_name %>, :<%= tool_call_table_name.singularize %>, foreign_key: true
8
+ end
9
+ end
@@ -1,7 +1,6 @@
1
1
  class Create<%= chat_model_name.gsub('::', '').pluralize %> < ActiveRecord::Migration<%= migration_version %>
2
2
  def change
3
3
  create_table :<%= chat_table_name %> do |t|
4
- t.references :<%= model_table_name.singularize %>, foreign_key: true
5
4
  t.timestamps
6
5
  end
7
6
  end
@@ -1,13 +1,10 @@
1
1
  class Create<%= message_model_name.gsub('::', '').pluralize %> < ActiveRecord::Migration<%= migration_version %>
2
2
  def change
3
3
  create_table :<%= message_table_name %> do |t|
4
- t.references :<%= chat_table_name.singularize %>, null: false, foreign_key: true
5
4
  t.string :role, null: false
6
5
  t.text :content
7
- t.references :<%= model_table_name.singularize %>, foreign_key: true
8
6
  t.integer :input_tokens
9
7
  t.integer :output_tokens
10
- t.references :<%= tool_call_table_name.singularize %>, foreign_key: true
11
8
  t.timestamps
12
9
  end
13
10
 
@@ -2,7 +2,6 @@
2
2
  class Create<%= tool_call_model_name.gsub('::', '').pluralize %> < ActiveRecord::Migration<%= migration_version %>
3
3
  def change
4
4
  create_table :<%= tool_call_table_name %> do |t|
5
- t.references :<%= message_table_name.singularize %>, null: false, foreign_key: true
6
5
  t.string :tool_call_id, null: false
7
6
  t.string :name, null: false
8
7
  t.<%= postgresql? ? 'jsonb' : 'json' %> :arguments, default: {}
@@ -76,6 +76,7 @@ module RubyLLM
76
76
 
77
77
  def type
78
78
  return :image if image?
79
+ return :video if video?
79
80
  return :audio if audio?
80
81
  return :pdf if pdf?
81
82
  return :text if text?
@@ -87,6 +88,10 @@ module RubyLLM
87
88
  RubyLLM::MimeType.image? mime_type
88
89
  end
89
90
 
91
+ def video?
92
+ RubyLLM::MimeType.video? mime_type
93
+ end
94
+
90
95
  def audio?
91
96
  RubyLLM::MimeType.audio? mime_type
92
97
  end
@@ -26,6 +26,7 @@ module RubyLLM
26
26
  # Default models
27
27
  :default_model,
28
28
  :default_embedding_model,
29
+ :default_moderation_model,
29
30
  :default_image_model,
30
31
  # Model registry
31
32
  :model_registry_class,
@@ -54,6 +55,7 @@ module RubyLLM
54
55
 
55
56
  @default_model = 'gpt-4.1-nano'
56
57
  @default_embedding_model = 'text-embedding-3-small'
58
+ @default_moderation_model = 'omni-moderation-latest'
57
59
  @default_image_model = 'gpt-image-1'
58
60
 
59
61
  @model_registry_class = 'Model'
@@ -15,6 +15,10 @@ module RubyLLM
15
15
  type.start_with?('image/')
16
16
  end
17
17
 
18
+ def video?(type)
19
+ type.start_with?('video/')
20
+ end
21
+
18
22
  def audio?(type)
19
23
  type.start_with?('audio/')
20
24
  end
@@ -56,6 +56,10 @@ module RubyLLM
56
56
  modalities.input.include?('image')
57
57
  end
58
58
 
59
+ def supports_video?
60
+ modalities.input.include?('video')
61
+ end
62
+
59
63
  def supports_functions?
60
64
  function_calling?
61
65
  end