ruby_llm 0.1.0.pre36 → 0.1.0.pre37
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/docs.yml +53 -0
- data/.rspec_status +7 -35
- data/.rubocop.yml +7 -2
- data/.yardopts +12 -0
- data/Gemfile +27 -0
- data/bin/console +4 -4
- data/docs/.gitignore +7 -0
- data/docs/Gemfile +11 -0
- data/docs/_config.yml +43 -0
- data/docs/_data/navigation.yml +25 -0
- data/docs/guides/chat.md +206 -0
- data/docs/guides/embeddings.md +325 -0
- data/docs/guides/error-handling.md +301 -0
- data/docs/guides/getting-started.md +164 -0
- data/docs/guides/image-generation.md +274 -0
- data/docs/guides/index.md +45 -0
- data/docs/guides/rails.md +401 -0
- data/docs/guides/streaming.md +242 -0
- data/docs/guides/tools.md +247 -0
- data/docs/index.md +53 -0
- data/docs/installation.md +98 -0
- data/lib/ruby_llm/active_record/acts_as.rb +2 -2
- data/lib/ruby_llm/chat.rb +7 -7
- data/lib/ruby_llm/providers/anthropic/capabilities.rb +1 -2
- data/lib/ruby_llm/providers/anthropic/chat.rb +2 -3
- data/lib/ruby_llm/providers/deepseek/capabilities.rb +0 -1
- data/lib/ruby_llm/providers/gemini/capabilities.rb +1 -1
- data/lib/ruby_llm/providers/openai/capabilities.rb +7 -12
- data/lib/ruby_llm/providers/openai/embeddings.rb +1 -1
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/tasks/models.rake +2 -2
- data/ruby_llm.gemspec +10 -32
- metadata +22 -296
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8befc508f1a0bdbaf7b113f3a2f8584f78fbe756ac07b22344af9ea90bc47f31
|
4
|
+
data.tar.gz: 389cb1518cacfa6448f30891d45e573536c768aa8092f8d1fbac156ff4c2d4c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67493fd05b3c9f0765b8d7bd72d295756e615ad6ab8b133181c8a472d28a64ce83e8aaedf48f556de8e9ddc1d39c59fdd4e7cdf4f0521eff9b9d34726a6b6bcd
|
7
|
+
data.tar.gz: e4569279dc890b62881c3d8da2cd03370fd8a87f6c20f112fe0bbce2d61aec0acba726d9d89252b724f4f4a2cc97ce383f229bddc8ea9d6c204fbcc66e71f6de
|
@@ -0,0 +1,53 @@
|
|
1
|
+
name: Deploy docs
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [main]
|
6
|
+
paths:
|
7
|
+
- 'docs/**'
|
8
|
+
- '.github/workflows/docs.yml'
|
9
|
+
workflow_dispatch:
|
10
|
+
|
11
|
+
permissions:
|
12
|
+
contents: read
|
13
|
+
pages: write
|
14
|
+
id-token: write
|
15
|
+
|
16
|
+
concurrency:
|
17
|
+
group: "pages"
|
18
|
+
cancel-in-progress: false
|
19
|
+
|
20
|
+
jobs:
|
21
|
+
build:
|
22
|
+
runs-on: ubuntu-latest
|
23
|
+
steps:
|
24
|
+
- name: Checkout
|
25
|
+
uses: actions/checkout@v4
|
26
|
+
- name: Setup Ruby
|
27
|
+
uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
ruby-version: '3.3'
|
30
|
+
bundler-cache: true
|
31
|
+
working-directory: docs
|
32
|
+
- name: Setup Pages
|
33
|
+
uses: actions/configure-pages@v4
|
34
|
+
- name: Build with Jekyll
|
35
|
+
working-directory: docs
|
36
|
+
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
|
37
|
+
env:
|
38
|
+
JEKYLL_ENV: production
|
39
|
+
- name: Upload artifact
|
40
|
+
uses: actions/upload-pages-artifact@v3
|
41
|
+
with:
|
42
|
+
path: docs/_site
|
43
|
+
|
44
|
+
deploy:
|
45
|
+
environment:
|
46
|
+
name: github-pages
|
47
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
48
|
+
runs-on: ubuntu-latest
|
49
|
+
needs: build
|
50
|
+
steps:
|
51
|
+
- name: Deploy to GitHub Pages
|
52
|
+
id: deployment
|
53
|
+
uses: actions/deploy-pages@v4
|
data/.rspec_status
CHANGED
@@ -1,35 +1,7 @@
|
|
1
|
-
example_id
|
2
|
-
|
3
|
-
./spec/
|
4
|
-
./spec/
|
5
|
-
./spec/
|
6
|
-
./spec/
|
7
|
-
./spec/
|
8
|
-
./spec/integration/chat_spec.rb[1:1:3:2] | passed | 2.84 seconds |
|
9
|
-
./spec/integration/content_spec.rb[1:1:1] | passed | 3.51 seconds |
|
10
|
-
./spec/integration/content_spec.rb[1:1:2] | passed | 1.11 seconds |
|
11
|
-
./spec/integration/content_spec.rb[1:1:3] | passed | 1.77 seconds |
|
12
|
-
./spec/integration/content_spec.rb[1:2:1] | passed | 1.68 seconds |
|
13
|
-
./spec/integration/content_spec.rb[1:2:2] | passed | 2.01 seconds |
|
14
|
-
./spec/integration/embeddings_spec.rb[1:1:1:1] | passed | 0.28694 seconds |
|
15
|
-
./spec/integration/embeddings_spec.rb[1:1:1:2] | passed | 0.32456 seconds |
|
16
|
-
./spec/integration/embeddings_spec.rb[1:1:2:1] | passed | 0.85006 seconds |
|
17
|
-
./spec/integration/embeddings_spec.rb[1:1:2:2] | passed | 0.82832 seconds |
|
18
|
-
./spec/integration/error_handling_spec.rb[1:1] | passed | 0.19746 seconds |
|
19
|
-
./spec/integration/image_generation_spec.rb[1:1:1] | passed | 10.73 seconds |
|
20
|
-
./spec/integration/image_generation_spec.rb[1:1:2] | passed | 16.95 seconds |
|
21
|
-
./spec/integration/image_generation_spec.rb[1:1:3] | passed | 0.00024 seconds |
|
22
|
-
./spec/integration/rails_spec.rb[1:1] | passed | 3.39 seconds |
|
23
|
-
./spec/integration/rails_spec.rb[1:2] | passed | 1.74 seconds |
|
24
|
-
./spec/integration/streaming_spec.rb[1:1:1:1] | passed | 0.56418 seconds |
|
25
|
-
./spec/integration/streaming_spec.rb[1:1:1:2] | passed | 6.33 seconds |
|
26
|
-
./spec/integration/streaming_spec.rb[1:1:2:1] | passed | 0.51911 seconds |
|
27
|
-
./spec/integration/streaming_spec.rb[1:1:2:2] | passed | 2.31 seconds |
|
28
|
-
./spec/integration/streaming_spec.rb[1:1:3:1] | passed | 0.78299 seconds |
|
29
|
-
./spec/integration/streaming_spec.rb[1:1:3:2] | passed | 3.82 seconds |
|
30
|
-
./spec/integration/tools_spec.rb[1:1:1:1] | passed | 3.89 seconds |
|
31
|
-
./spec/integration/tools_spec.rb[1:1:1:2] | passed | 7.78 seconds |
|
32
|
-
./spec/integration/tools_spec.rb[1:1:2:1] | passed | 1.25 seconds |
|
33
|
-
./spec/integration/tools_spec.rb[1:1:2:2] | passed | 2.1 seconds |
|
34
|
-
./spec/integration/tools_spec.rb[1:1:3:1] | passed | 1.59 seconds |
|
35
|
-
./spec/integration/tools_spec.rb[1:1:3:2] | passed | 3.05 seconds |
|
1
|
+
example_id | status | run_time |
|
2
|
+
------------------------------------------- | ------ | ------------ |
|
3
|
+
./spec/ruby_llm/chat_content_spec.rb[1:1:1] | passed | 3.59 seconds |
|
4
|
+
./spec/ruby_llm/chat_content_spec.rb[1:1:2] | passed | 1.51 seconds |
|
5
|
+
./spec/ruby_llm/chat_content_spec.rb[1:1:3] | passed | 2.29 seconds |
|
6
|
+
./spec/ruby_llm/chat_content_spec.rb[1:2:1] | passed | 2.06 seconds |
|
7
|
+
./spec/ruby_llm/chat_content_spec.rb[1:2:2] | passed | 2.04 seconds |
|
data/.rubocop.yml
CHANGED
data/.yardopts
ADDED
data/Gemfile
CHANGED
@@ -3,3 +3,30 @@
|
|
3
3
|
source 'https://rubygems.org'
|
4
4
|
|
5
5
|
gemspec
|
6
|
+
|
7
|
+
group :development do
|
8
|
+
# Rails integration dependencies
|
9
|
+
gem 'activerecord', '>= 6.0', '< 9.0'
|
10
|
+
gem 'activesupport', '>= 6.0', '< 9.0'
|
11
|
+
|
12
|
+
# Development dependencies
|
13
|
+
gem 'bundler', '>= 2.0'
|
14
|
+
gem 'codecov'
|
15
|
+
gem 'dotenv'
|
16
|
+
gem 'irb'
|
17
|
+
gem 'nokogiri'
|
18
|
+
gem 'overcommit', '>= 0.66'
|
19
|
+
gem 'pry', '>= 0.14'
|
20
|
+
gem 'rake', '>= 13.0'
|
21
|
+
gem 'rdoc'
|
22
|
+
gem 'reline'
|
23
|
+
gem 'rspec', '~> 3.12'
|
24
|
+
gem 'rubocop', '>= 1.0'
|
25
|
+
gem 'rubocop-rake', '>= 0.6'
|
26
|
+
gem 'rubocop-rspec'
|
27
|
+
gem 'simplecov', '>= 0.21'
|
28
|
+
gem 'simplecov-cobertura'
|
29
|
+
gem 'sqlite3'
|
30
|
+
gem 'webmock', '~> 3.18'
|
31
|
+
gem 'yard', '>= 0.9'
|
32
|
+
end
|
data/bin/console
CHANGED
@@ -8,10 +8,10 @@ require 'dotenv/load'
|
|
8
8
|
require 'irb'
|
9
9
|
|
10
10
|
RubyLLM.configure do |config|
|
11
|
-
config.openai_api_key = ENV
|
12
|
-
config.anthropic_api_key = ENV
|
13
|
-
config.gemini_api_key = ENV
|
14
|
-
config.deepseek_api_key = ENV
|
11
|
+
config.openai_api_key = ENV.fetch('OPENAI_API_KEY', nil)
|
12
|
+
config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY', nil)
|
13
|
+
config.gemini_api_key = ENV.fetch('GEMINI_API_KEY', nil)
|
14
|
+
config.deepseek_api_key = ENV.fetch('DEEPSEEK_API_KEY', nil)
|
15
15
|
end
|
16
16
|
|
17
17
|
IRB.start(__FILE__)
|
data/docs/.gitignore
ADDED
data/docs/Gemfile
ADDED
data/docs/_config.yml
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
title: RubyLLM
|
2
|
+
description: A delightful Ruby way to work with AI
|
3
|
+
url: https://crmne.github.io/ruby_llm
|
4
|
+
baseurl: /ruby_llm
|
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 © 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
|
@@ -0,0 +1,25 @@
|
|
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
ADDED
@@ -0,0 +1,206 @@
|
|
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
|