ruby_llm 0.1.0.pre38 → 0.1.0.pre39

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: efcf5aa8692558d9214d82dbb6c053727b1b6c5e810fcd7cd224e9a909ae38ff
4
- data.tar.gz: 4910f4d7dade64d20696f5af971e968ce31abf0d98eae14fa7c874efe6ac03ce
3
+ metadata.gz: 0c887462ad2c35c5e831991b8b6cd78095c3f286861fd4913afddd5887833f3b
4
+ data.tar.gz: 382a2dd05532510ed5ac8ae5deb7a81febb831e3bbd8a11376eba0ad266451c3
5
5
  SHA512:
6
- metadata.gz: 31679bff69003430d7f662dfa822a640ea6863087bf9e2260b0555f7341c41d3368a2e07d7c515c78255f5b1b400a05b08c631a80ee4ed7871fd0ceedb330ca2
7
- data.tar.gz: 306fbf3cc3f35688b03b73995abe962152ddcde8d438093f4b4879d8c0b271187e4c7c26b10b8393f80556b955e1c631a8b30fdd693605712353cd7d6aa5e9cb
6
+ metadata.gz: b8c372a54f0bb94ecf6b22ead70f34a324974f4f61ad4610ba15ffee64ed8ec226fac24a74b73667bc07ea73a14fb5ee5d813759ab60f86c54c7d00cfc3905aa
7
+ data.tar.gz: 868fadbdaf583aa911a98cce36b6b61208a2065d92f32c31f1a2ea0908a37aa91f2047d2ea7aa77911093a7fcbb4ae10ace87f7ddafa2d39856e67a54d5bf846
@@ -3,6 +3,12 @@ name: CI
3
3
  on:
4
4
  push:
5
5
  branches: [ "main" ]
6
+ paths:
7
+ - 'lib/**'
8
+ - 'spec/**'
9
+ - 'Gemfile'
10
+ - 'Rakefile'
11
+ - 'ruby_llm.gemspec'
6
12
  pull_request:
7
13
  branches: [ "main" ]
8
14
  workflow_call:
data/README.md CHANGED
@@ -20,6 +20,8 @@ A delightful Ruby way to work with AI. Chat in text, analyze and generate images
20
20
  <a href="https://codecov.io/gh/crmne/ruby_llm"><img src="https://codecov.io/gh/crmne/ruby_llm/branch/main/graph/badge.svg" alt="codecov" /></a>
21
21
  </p>
22
22
 
23
+ 🤺 Battle tested at [💬 Chat with Work](https://chatwithwork.com)
24
+
23
25
  ## Features
24
26
 
25
27
  - 💬 **Beautiful Chat Interface** - Converse with AI models as easily as `RubyLLM.chat.ask "teach me Ruby"`
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyLLM
4
- VERSION = '0.1.0.pre38'
4
+ VERSION = '0.1.0.pre39'
5
5
  end
data/ruby_llm.gemspec CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
  # Specify which files should be added to the gem when it is released.
29
29
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
30
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
31
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
31
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|docs)/}) }
32
32
  end
33
33
  spec.bindir = 'exe'
34
34
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_llm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre38
4
+ version: 0.1.0.pre39
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carmine Paolino
@@ -111,21 +111,6 @@ files:
111
111
  - Rakefile
112
112
  - bin/console
113
113
  - bin/setup
114
- - docs/.gitignore
115
- - docs/Gemfile
116
- - docs/_config.yml
117
- - docs/_data/navigation.yml
118
- - docs/guides/chat.md
119
- - docs/guides/embeddings.md
120
- - docs/guides/error-handling.md
121
- - docs/guides/getting-started.md
122
- - docs/guides/image-generation.md
123
- - docs/guides/index.md
124
- - docs/guides/rails.md
125
- - docs/guides/streaming.md
126
- - docs/guides/tools.md
127
- - docs/index.md
128
- - docs/installation.md
129
114
  - lib/ruby_llm.rb
130
115
  - lib/ruby_llm/active_record/acts_as.rb
131
116
  - lib/ruby_llm/chat.rb
data/docs/.gitignore DELETED
@@ -1,7 +0,0 @@
1
- _site/
2
- .sass-cache/
3
- .jekyll-cache/
4
- .jekyll-metadata
5
- # Ignore folders generated by Bundler
6
- .bundle/
7
- vendor/
data/docs/Gemfile DELETED
@@ -1,11 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'jekyll', '~> 4.3'
4
- gem 'just-the-docs', '~> 0.7.0'
5
- gem 'webrick', '~> 1.8'
6
-
7
- # GitHub Pages plugins
8
- group :jekyll_plugins do
9
- gem 'jekyll-remote-theme'
10
- gem 'jekyll-seo-tag'
11
- end
data/docs/_config.yml DELETED
@@ -1,43 +0,0 @@
1
- title: RubyLLM
2
- description: A delightful Ruby way to work with AI
3
- url: https://rubyllm.com
4
- baseurl: /
5
- remote_theme: just-the-docs/just-the-docs
6
-
7
- # Enable search
8
- search_enabled: true
9
- search:
10
- heading_level: 2
11
- previews: 3
12
- preview_words_before: 5
13
- preview_words_after: 10
14
- tokenizer_separator: /[\s/]+/
15
- rel_url: true
16
- button: false
17
-
18
- # Navigation structure
19
- nav_external_links:
20
- - title: RubyLLM on GitHub
21
- url: https://github.com/crmne/ruby_llm
22
- hide_icon: false
23
-
24
- # Footer content
25
- footer_content: "Copyright &copy; 2025 <a href='https://paolino.me'>Carmine Paolino</a>. Distributed under an <a href=\"https://github.com/crmne/ruby_llm/tree/main/LICENSE\">MIT license.</a>"
26
-
27
- # Enable copy button on code blocks
28
- enable_copy_code_button: true
29
-
30
- # Make Anchor links show on hover
31
- heading_anchors: true
32
-
33
- # Color scheme
34
- color_scheme: light
35
-
36
- # Google Analytics
37
- ga_tracking:
38
- ga_tracking_anonymize_ip: true
39
-
40
- # Custom plugins (GitHub Pages allows these)
41
- plugins:
42
- - jekyll-remote-theme
43
- - jekyll-seo-tag
@@ -1,25 +0,0 @@
1
- - title: Home
2
- url: /
3
- - title: Installation
4
- url: /installation
5
- - title: Guides
6
- url: /guides/
7
- subfolderitems:
8
- - title: Getting Started
9
- url: /guides/getting-started
10
- - title: Chat
11
- url: /guides/chat
12
- - title: Tools
13
- url: /guides/tools
14
- - title: Streaming
15
- url: /guides/streaming
16
- - title: Rails Integration
17
- url: /guides/rails
18
- - title: Image Generation
19
- url: /guides/image-generation
20
- - title: Embeddings
21
- url: /guides/embeddings
22
- - title: Error Handling
23
- url: /guides/error-handling
24
- - title: GitHub
25
- url: https://github.com/crmne/ruby_llm
data/docs/guides/chat.md DELETED
@@ -1,206 +0,0 @@
1
- ---
2
- layout: default
3
- title: Chat
4
- parent: Guides
5
- nav_order: 2
6
- permalink: /guides/chat
7
- ---
8
-
9
- # Chatting with AI Models
10
-
11
- RubyLLM's chat interface provides a natural way to interact with various AI models. This guide covers everything from basic chatting to advanced features like multimodal inputs and streaming responses.
12
-
13
- ## Basic Chat
14
-
15
- Creating a chat and asking questions is straightforward:
16
-
17
- ```ruby
18
- # Create a chat with the default model
19
- chat = RubyLLM.chat
20
-
21
- # Ask a question
22
- response = chat.ask "What's the best way to learn Ruby?"
23
-
24
- # The response is a Message object
25
- puts response.content
26
- puts "Role: #{response.role}"
27
- puts "Model: #{response.model_id}"
28
- puts "Tokens: #{response.input_tokens} input, #{response.output_tokens} output"
29
- ```
30
-
31
- ## Choosing Models
32
-
33
- You can specify which model to use when creating a chat:
34
-
35
- ```ruby
36
- # Create a chat with a specific model
37
- chat = RubyLLM.chat(model: 'gpt-4o-mini')
38
-
39
- # Use Claude instead
40
- claude_chat = RubyLLM.chat(model: 'claude-3-5-sonnet-20241022')
41
-
42
- # Or change the model for an existing chat
43
- chat.with_model('gemini-2.0-flash')
44
- ```
45
-
46
- ## Multi-turn Conversations
47
-
48
- Chats maintain conversation history automatically:
49
-
50
- ```ruby
51
- chat = RubyLLM.chat
52
-
53
- # Start a conversation
54
- chat.ask "What's your favorite programming language?"
55
-
56
- # Follow up
57
- chat.ask "Why do you like that language?"
58
-
59
- # Continue the conversation
60
- chat.ask "What are its weaknesses?"
61
-
62
- # Access the conversation history
63
- chat.messages.each do |message|
64
- puts "#{message.role}: #{message.content[0..50]}..."
65
- end
66
- ```
67
-
68
- ## Working with Images
69
-
70
- Vision-capable models can understand images:
71
-
72
- ```ruby
73
- chat = RubyLLM.chat
74
-
75
- # Ask about an image (local file)
76
- chat.ask "What's in this image?", with: { image: "path/to/image.jpg" }
77
-
78
- # Or use an image URL
79
- chat.ask "Describe this picture", with: { image: "https://example.com/image.jpg" }
80
-
81
- # Include multiple images
82
- chat.ask "Compare these two charts", with: {
83
- image: ["chart1.png", "chart2.png"]
84
- }
85
-
86
- # Combine text and image
87
- chat.ask "Is this the Ruby logo?", with: { image: "logo.png" }
88
- ```
89
-
90
- ## Working with Audio
91
-
92
- Models with audio capabilities can process spoken content:
93
-
94
- ```ruby
95
- chat = RubyLLM.chat(model: 'gpt-4o-audio-preview')
96
-
97
- # Analyze audio content
98
- chat.ask "What's being said in this recording?", with: {
99
- audio: "meeting.wav"
100
- }
101
-
102
- # Ask follow-up questions about the audio
103
- chat.ask "Summarize the key points mentioned"
104
- ```
105
-
106
- ## Streaming Responses
107
-
108
- For a more interactive experience, you can stream responses as they're generated:
109
-
110
- ```ruby
111
- chat = RubyLLM.chat
112
-
113
- # Stream the response with a block
114
- chat.ask "Tell me a story about a Ruby programmer" do |chunk|
115
- # Each chunk is a partial response
116
- print chunk.content
117
- $stdout.flush # Ensure output is displayed immediately
118
- end
119
-
120
- # Useful for long responses or real-time displays
121
- chat.ask "Write a detailed essay about programming paradigms" do |chunk|
122
- add_to_ui(chunk.content) # Your method to update UI
123
- end
124
- ```
125
-
126
- ## Temperature Control
127
-
128
- Control the creativity and randomness of AI responses:
129
-
130
- ```ruby
131
- # Higher temperature (more creative)
132
- creative_chat = RubyLLM.chat.with_temperature(0.9)
133
- creative_chat.ask "Write a poem about Ruby programming"
134
-
135
- # Lower temperature (more deterministic)
136
- precise_chat = RubyLLM.chat.with_temperature(0.1)
137
- precise_chat.ask "Explain how Ruby's garbage collector works"
138
- ```
139
-
140
- ## Access Token Usage
141
-
142
- RubyLLM automatically tracks token usage for billing and quota management:
143
-
144
- ```ruby
145
- chat = RubyLLM.chat
146
- response = chat.ask "Explain quantum computing"
147
-
148
- # Check token usage
149
- puts "Input tokens: #{response.input_tokens}"
150
- puts "Output tokens: #{response.output_tokens}"
151
- puts "Total tokens: #{response.input_tokens + response.output_tokens}"
152
-
153
- # Estimate cost (varies by model)
154
- model = RubyLLM.models.find(response.model_id)
155
- input_cost = response.input_tokens * model.input_price_per_million / 1_000_000
156
- output_cost = response.output_tokens * model.output_price_per_million / 1_000_000
157
- puts "Estimated cost: $#{(input_cost + output_cost).round(6)}"
158
- ```
159
-
160
- ## Registering Event Handlers
161
-
162
- You can register callbacks for chat events:
163
-
164
- ```ruby
165
- chat = RubyLLM.chat
166
-
167
- # Called when a new assistant message starts
168
- chat.on_new_message do
169
- puts "Assistant is typing..."
170
- end
171
-
172
- # Called when a message is complete
173
- chat.on_end_message do |message|
174
- puts "Response complete!"
175
- puts "Used #{message.input_tokens + message.output_tokens} tokens"
176
- end
177
-
178
- # These callbacks work with both streaming and non-streaming responses
179
- chat.ask "Tell me about Ruby's history"
180
- ```
181
-
182
- ## Multiple Parallel Chats
183
-
184
- You can maintain multiple separate chat instances:
185
-
186
- ```ruby
187
- # Create multiple chat instances
188
- ruby_chat = RubyLLM.chat
189
- python_chat = RubyLLM.chat
190
-
191
- # Each has its own conversation history
192
- ruby_chat.ask "What's great about Ruby?"
193
- python_chat.ask "What's great about Python?"
194
-
195
- # Continue separate conversations
196
- ruby_chat.ask "How does Ruby handle metaprogramming?"
197
- python_chat.ask "How does Python handle decorators?"
198
- ```
199
-
200
- ## Next Steps
201
-
202
- Now that you understand chat basics, you might want to explore:
203
-
204
- - [Using Tools]({% link guides/tools.md %}) to let AI use your Ruby code
205
- - [Streaming Responses]({% link guides/streaming.md %}) for real-time interactions
206
- - [Rails Integration]({% link guides/rails.md %}) to persist conversations in your apps
@@ -1,325 +0,0 @@
1
- ---
2
- layout: default
3
- title: Embeddings
4
- parent: Guides
5
- nav_order: 7
6
- permalink: /guides/embeddings
7
- ---
8
-
9
- # Embeddings
10
-
11
- Text embeddings are numerical representations of text that capture semantic meaning. RubyLLM makes it easy to generate embeddings for a variety of applications, including semantic search, clustering, and recommendation systems.
12
-
13
- ## Basic Embedding Generation
14
-
15
- The simplest way to create an embedding is with the global `embed` method:
16
-
17
- ```ruby
18
- # Create an embedding for a single text
19
- embedding = RubyLLM.embed("Ruby is a programmer's best friend")
20
-
21
- # The vector representation
22
- vector = embedding.vectors
23
- puts "Vector dimension: #{vector.length}" # => 1536 for text-embedding-3-small
24
- ```
25
-
26
- ## Embedding Multiple Texts
27
-
28
- You can efficiently embed multiple texts at once:
29
-
30
- ```ruby
31
- # Create embeddings for multiple texts
32
- texts = ["Ruby", "Python", "JavaScript"]
33
- embeddings = RubyLLM.embed(texts)
34
-
35
- # Each text gets its own vector
36
- puts "Number of vectors: #{embeddings.vectors.length}" # => 3
37
- puts "First vector dimensions: #{embeddings.vectors.first.length}"
38
- ```
39
-
40
- ## Choosing Models
41
-
42
- By default, RubyLLM uses OpenAI's `text-embedding-3-small`, but you can specify a different model:
43
-
44
- ```ruby
45
- # Use a specific model
46
- embedding = RubyLLM.embed(
47
- "This is a test sentence",
48
- model: "text-embedding-3-large"
49
- )
50
-
51
- # Or use a Google model
52
- google_embedding = RubyLLM.embed(
53
- "This is a test sentence",
54
- model: "text-embedding-004"
55
- )
56
- ```
57
-
58
- You can configure the default embedding model globally:
59
-
60
- ```ruby
61
- RubyLLM.configure do |config|
62
- config.default_embedding_model = "text-embedding-3-large"
63
- end
64
- ```
65
-
66
- ## Using Embedding Results
67
-
68
- ### Vector Properties
69
-
70
- The embedding result contains useful information:
71
-
72
- ```ruby
73
- embedding = RubyLLM.embed("Example text")
74
-
75
- # The vector representation
76
- puts embedding.vectors.class # => Array
77
- puts embedding.vectors.first.class # => Float
78
-
79
- # The model used
80
- puts embedding.model # => "text-embedding-3-small"
81
-
82
- # Token usage
83
- puts embedding.input_tokens # => 3
84
- ```
85
-
86
- ### Calculating Similarity
87
-
88
- Embeddings are commonly used to calculate similarity between texts:
89
-
90
- ```ruby
91
- require 'matrix'
92
-
93
- # Create embeddings for two texts
94
- embedding1 = RubyLLM.embed("I love Ruby programming")
95
- embedding2 = RubyLLM.embed("Ruby is my favorite language")
96
-
97
- # Convert to Vector objects
98
- vector1 = Vector.elements(embedding1.vectors)
99
- vector2 = Vector.elements(embedding2.vectors)
100
-
101
- # Calculate cosine similarity
102
- similarity = vector1.inner_product(vector2) / (vector1.norm * vector2.norm)
103
- puts "Similarity: #{similarity}" # Higher values (closer to 1) mean more similar
104
- ```
105
-
106
- ### Simple Semantic Search
107
-
108
- ```ruby
109
- # Create a simple search index
110
- class SearchIndex
111
- def initialize(texts, model: nil)
112
- @texts = texts
113
- @embeddings = RubyLLM.embed(texts, model: model).vectors
114
- end
115
-
116
- def search(query, top_k: 3)
117
- query_embedding = RubyLLM.embed(query).vectors
118
- query_vector = Vector.elements(query_embedding)
119
-
120
- # Calculate similarities
121
- similarities = @embeddings.map.with_index do |embedding, idx|
122
- vector = Vector.elements(embedding)
123
- similarity = query_vector.inner_product(vector) / (query_vector.norm * vector.norm)
124
- [idx, similarity]
125
- end
126
-
127
- # Return top results
128
- similarities.sort_by { |_, similarity| -similarity }
129
- .take(top_k)
130
- .map { |idx, similarity| { text: @texts[idx], similarity: similarity } }
131
- end
132
- end
133
-
134
- # Create an index
135
- documents = [
136
- "Ruby is a dynamic, interpreted language",
137
- "Python is known for its readability",
138
- "JavaScript runs in the browser",
139
- "Ruby on Rails is a web framework",
140
- "Django is a Python web framework"
141
- ]
142
-
143
- index = SearchIndex.new(documents)
144
-
145
- # Search for similar documents
146
- results = index.search("web development frameworks")
147
- results.each do |result|
148
- puts "#{result[:text]} (Similarity: #{result[:similarity].round(4)})"
149
- end
150
- ```
151
-
152
- ## Error Handling
153
-
154
- Handle errors that may occur during embedding generation:
155
-
156
- ```ruby
157
- begin
158
- embedding = RubyLLM.embed("Example text")
159
- rescue RubyLLM::UnauthorizedError
160
- puts "Please check your API key"
161
- rescue RubyLLM::BadRequestError => e
162
- puts "Invalid request: #{e.message}"
163
- rescue RubyLLM::Error => e
164
- puts "Error generating embedding: #{e.message}"
165
- end
166
- ```
167
-
168
- ## Performance Considerations
169
-
170
- When working with embeddings, keep these best practices in mind:
171
-
172
- 1. **Batch processing** - Embedding multiple texts at once is more efficient than making separate calls
173
- 2. **Caching** - Store embeddings in your database rather than regenerating them
174
- 3. **Dimensionality** - Different models produce embeddings with different dimensions
175
- 4. **Normalization** - Consider normalizing vectors to improve similarity calculations
176
-
177
- ## Working with Large Datasets
178
-
179
- For larger datasets, process embeddings in batches:
180
-
181
- ```ruby
182
- def embed_in_batches(texts, batch_size: 100, model: nil)
183
- all_embeddings = []
184
-
185
- texts.each_slice(batch_size) do |batch|
186
- batch_embeddings = RubyLLM.embed(batch, model: model).vectors
187
- all_embeddings.concat(batch_embeddings)
188
-
189
- # Optional: add a small delay to avoid rate limiting
190
- sleep(0.1)
191
- end
192
-
193
- all_embeddings
194
- end
195
-
196
- # Usage
197
- documents = File.readlines("documents.txt", chomp: true)
198
- embeddings = embed_in_batches(documents)
199
- ```
200
-
201
- ## Rails Integration
202
-
203
- In a Rails application, you might integrate embeddings like this:
204
-
205
- ```ruby
206
- class Document < ApplicationRecord
207
- serialize :embedding, Array
208
-
209
- before_save :generate_embedding, if: -> { content_changed? }
210
-
211
- def self.search(query, limit: 10)
212
- # Generate query embedding
213
- query_embedding = RubyLLM.embed(query).vectors
214
-
215
- # Convert to SQL for similarity search
216
- where.not(embedding: nil)
217
- .select("*, (embedding <=> ?) AS similarity", query_embedding)
218
- .order("similarity DESC")
219
- .limit(limit)
220
- end
221
-
222
- private
223
-
224
- def generate_embedding
225
- return if content.blank?
226
-
227
- self.embedding = RubyLLM.embed(content).vectors
228
- rescue RubyLLM::Error => e
229
- errors.add(:base, "Failed to generate embedding: #{e.message}")
230
- throw :abort
231
- end
232
- end
233
- ```
234
-
235
- Note: The above example assumes you're using PostgreSQL with the `pgvector` extension for vector similarity search.
236
-
237
- ## Example Use Cases
238
-
239
- ### Document Classification
240
-
241
- ```ruby
242
- # Train a simple classifier
243
- class SimpleClassifier
244
- def initialize
245
- @categories = {}
246
- end
247
-
248
- def train(text, category)
249
- @categories[category] ||= []
250
- @categories[category] << RubyLLM.embed(text).vectors
251
- end
252
-
253
- def classify(text)
254
- # Get embedding for the query text
255
- query_embedding = RubyLLM.embed(text).vectors
256
- query_vector = Vector.elements(query_embedding)
257
-
258
- # Find the closest category
259
- best_similarity = -1
260
- best_category = nil
261
-
262
- @categories.each do |category, embeddings|
263
- # Calculate average similarity to this category
264
- similarity = embeddings.map do |embedding|
265
- vector = Vector.elements(embedding)
266
- query_vector.inner_product(vector) / (query_vector.norm * vector.norm)
267
- end.sum / embeddings.size
268
-
269
- if similarity > best_similarity
270
- best_similarity = similarity
271
- best_category = category
272
- end
273
- end
274
-
275
- { category: best_category, confidence: best_similarity }
276
- end
277
- end
278
-
279
- # Usage
280
- classifier = SimpleClassifier.new
281
-
282
- # Train with examples
283
- classifier.train("How do I install Ruby?", :installation)
284
- classifier.train("Setting up Ruby environment", :installation)
285
- classifier.train("What are blocks in Ruby?", :language_features)
286
- classifier.train("Understanding Ruby modules", :language_features)
287
-
288
- # Classify new queries
289
- puts classifier.classify("How to install Ruby on Ubuntu?")
290
- # => {:category=>:installation, :confidence=>0.92}
291
- ```
292
-
293
- ### Content Recommendation
294
-
295
- ```ruby
296
- def recommend_similar_content(content_id, library, count: 3)
297
- # Get the target content
298
- target = library.find(content_id)
299
- target_embedding = RubyLLM.embed(target.description).vectors
300
- target_vector = Vector.elements(target_embedding)
301
-
302
- # Compare with all other content
303
- similarities = library.reject { |item| item.id == content_id }.map do |item|
304
- next if item.embedding.nil?
305
-
306
- item_vector = Vector.elements(item.embedding)
307
- similarity = target_vector.inner_product(item_vector) / (target_vector.norm * item_vector.norm)
308
-
309
- [item, similarity]
310
- end.compact
311
-
312
- # Return top matches
313
- similarities.sort_by { |_, similarity| -similarity }
314
- .take(count)
315
- .map { |item, similarity| { item: item, similarity: similarity } }
316
- end
317
- ```
318
-
319
- ## Next Steps
320
-
321
- Now that you understand embeddings, you might want to explore:
322
-
323
- - [Chat]({% link guides/chat.md %}) for interactive AI conversations
324
- - [Tools]({% link guides/tools.md %}) to extend AI capabilities
325
- - [Error Handling]({% link guides/error-handling.md %}) for robust applications