ruby_llm 0.1.0.pre31 → 0.1.0.pre33
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/cicd.yml +1 -1
- data/.rspec_status +38 -27
- data/README.md +52 -3
- data/lib/ruby_llm/configuration.rb +2 -0
- data/lib/ruby_llm/content.rb +4 -2
- data/lib/ruby_llm/image.rb +24 -0
- data/lib/ruby_llm/provider.rb +21 -5
- data/lib/ruby_llm/providers/openai/chat.rb +1 -1
- data/lib/ruby_llm/providers/openai/images.rb +38 -0
- data/lib/ruby_llm/providers/openai/media.rb +52 -0
- data/lib/ruby_llm/providers/openai.rb +4 -0
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +4 -0
- data/ruby_llm.gemspec +5 -5
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e36a864dcd3852d03d467684aafcc811273f0f44dbd1925484440808c6c8895b
|
4
|
+
data.tar.gz: 5ed1b436a1b91f7fac06ab76d43fd0c7dfee925cc1af280a10bb40e448dabf0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6dd5a24c4a374a5fd291c7f47363dd282abcc850361464e67859f82ad88f51f49f0d4fda89299cf3871df838896acb111170a3615963c215a2aedb6b4154d0bd
|
7
|
+
data.tar.gz: 07f0931ca91abe8c42b7ca52910f4ac31f34ec4e049a321a7a4d59808cd190813aab1534312bb279d609a94f2ee6fbb2164faa6330a82a80ff520697741a7088
|
data/.github/workflows/cicd.yml
CHANGED
data/.rspec_status
CHANGED
@@ -1,27 +1,38 @@
|
|
1
|
-
example_id
|
2
|
-
|
3
|
-
./spec/integration/chat_spec.rb[1:1:1:1]
|
4
|
-
./spec/integration/chat_spec.rb[1:1:1:2]
|
5
|
-
./spec/integration/chat_spec.rb[1:1:2:1]
|
6
|
-
./spec/integration/chat_spec.rb[1:1:2:2]
|
7
|
-
./spec/integration/chat_spec.rb[1:1:3:1]
|
8
|
-
./spec/integration/chat_spec.rb[1:1:3:2]
|
9
|
-
./spec/integration/
|
10
|
-
./spec/integration/
|
11
|
-
./spec/integration/
|
12
|
-
./spec/integration/
|
13
|
-
./spec/integration/
|
14
|
-
./spec/integration/
|
15
|
-
./spec/integration/
|
16
|
-
./spec/integration/
|
17
|
-
./spec/integration/
|
18
|
-
./spec/integration/
|
19
|
-
./spec/integration/
|
20
|
-
./spec/integration/
|
21
|
-
./spec/integration/
|
22
|
-
./spec/integration/
|
23
|
-
./spec/integration/
|
24
|
-
./spec/integration/
|
25
|
-
./spec/integration/
|
26
|
-
./spec/integration/
|
27
|
-
./spec/integration/
|
1
|
+
example_id | status | run_time |
|
2
|
+
-------------------------------------------------- | ------ | --------------- |
|
3
|
+
./spec/integration/chat_spec.rb[1:1:1:1] | passed | 0.5826 seconds |
|
4
|
+
./spec/integration/chat_spec.rb[1:1:1:2] | passed | 3.43 seconds |
|
5
|
+
./spec/integration/chat_spec.rb[1:1:2:1] | passed | 0.49383 seconds |
|
6
|
+
./spec/integration/chat_spec.rb[1:1:2:2] | passed | 1.36 seconds |
|
7
|
+
./spec/integration/chat_spec.rb[1:1:3:1] | passed | 0.74049 seconds |
|
8
|
+
./spec/integration/chat_spec.rb[1:1:3:2] | passed | 4.11 seconds |
|
9
|
+
./spec/integration/content_spec.rb[1:1:1] | passed | 3.87 seconds |
|
10
|
+
./spec/integration/content_spec.rb[1:1:2] | passed | 1.23 seconds |
|
11
|
+
./spec/integration/content_spec.rb[1:1:3] | passed | 2.07 seconds |
|
12
|
+
./spec/integration/content_spec.rb[1:2:1] | passed | 2.05 seconds |
|
13
|
+
./spec/integration/content_spec.rb[1:2:2] | passed | 2.88 seconds |
|
14
|
+
./spec/integration/embeddings_spec.rb[1:1:1:1] | passed | 0.30185 seconds |
|
15
|
+
./spec/integration/embeddings_spec.rb[1:1:1:2] | passed | 0.30812 seconds |
|
16
|
+
./spec/integration/embeddings_spec.rb[1:1:2:1] | passed | 13.05 seconds |
|
17
|
+
./spec/integration/embeddings_spec.rb[1:1:2:2] | passed | 0.78135 seconds |
|
18
|
+
./spec/integration/error_handling_spec.rb[1:1] | passed | 0.21297 seconds |
|
19
|
+
./spec/integration/image_generation_spec.rb[1:1:1] | passed | 12.44 seconds |
|
20
|
+
./spec/integration/image_generation_spec.rb[1:1:2] | passed | 17.66 seconds |
|
21
|
+
./spec/integration/image_generation_spec.rb[1:1:3] | passed | 0.00324 seconds |
|
22
|
+
./spec/integration/image_generation_spec.rb[1:1:4] | failed | 0.15682 seconds |
|
23
|
+
./spec/integration/image_generation_spec.rb[1:1:5] | passed | 18.69 seconds |
|
24
|
+
./spec/integration/image_generation_spec.rb[1:1:6] | passed | 0.00032 seconds |
|
25
|
+
./spec/integration/rails_spec.rb[1:1] | passed | 4.05 seconds |
|
26
|
+
./spec/integration/rails_spec.rb[1:2] | passed | 1.82 seconds |
|
27
|
+
./spec/integration/streaming_spec.rb[1:1:1:1] | passed | 0.58445 seconds |
|
28
|
+
./spec/integration/streaming_spec.rb[1:1:1:2] | passed | 6.04 seconds |
|
29
|
+
./spec/integration/streaming_spec.rb[1:1:2:1] | passed | 0.47171 seconds |
|
30
|
+
./spec/integration/streaming_spec.rb[1:1:2:2] | passed | 2.39 seconds |
|
31
|
+
./spec/integration/streaming_spec.rb[1:1:3:1] | passed | 0.72016 seconds |
|
32
|
+
./spec/integration/streaming_spec.rb[1:1:3:2] | passed | 3.59 seconds |
|
33
|
+
./spec/integration/tools_spec.rb[1:1:1:1] | passed | 3.1 seconds |
|
34
|
+
./spec/integration/tools_spec.rb[1:1:1:2] | passed | 7.04 seconds |
|
35
|
+
./spec/integration/tools_spec.rb[1:1:2:1] | passed | 1.42 seconds |
|
36
|
+
./spec/integration/tools_spec.rb[1:1:2:2] | passed | 2.24 seconds |
|
37
|
+
./spec/integration/tools_spec.rb[1:1:3:1] | passed | 2.16 seconds |
|
38
|
+
./spec/integration/tools_spec.rb[1:1:3:2] | passed | 5.26 seconds |
|
data/README.md
CHANGED
@@ -1,20 +1,33 @@
|
|
1
1
|
# RubyLLM
|
2
2
|
|
3
|
-
A delightful Ruby way to work with AI
|
3
|
+
A delightful Ruby way to work with AI. Chat in text, analyze and generate images, understand audio, and use tools through a unified interface to OpenAI, Anthropic, Google, and DeepSeek. Built for developer happiness with automatic token counting, proper streaming, and Rails integration. No wrapping your head around multiple APIs - just clean Ruby code that works.
|
4
4
|
|
5
5
|
<p align="center">
|
6
6
|
<img src="https://upload.wikimedia.org/wikipedia/commons/4/4d/OpenAI_Logo.svg" alt="OpenAI" height="40" width="120">
|
7
7
|
|
8
8
|
<img src="https://upload.wikimedia.org/wikipedia/commons/7/78/Anthropic_logo.svg" alt="Anthropic" height="40" width="120">
|
9
9
|
|
10
|
-
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8a/Google_Gemini_logo.svg" alt="Google" height="40" width="120">
|
10
|
+
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8a/Google_Gemini_logo.svg" alt="Google" height="40" width="120">
|
11
11
|
|
12
|
-
<img src="https://upload.wikimedia.org/wikipedia/commons/e/ec/DeepSeek_logo.svg" alt="DeepSeek" height="40" width="120"
|
12
|
+
<img src="https://upload.wikimedia.org/wikipedia/commons/e/ec/DeepSeek_logo.svg" alt="DeepSeek" height="40" width="120">
|
13
13
|
</p>
|
14
14
|
|
15
15
|
[](https://badge.fury.io/rb/ruby_llm)
|
16
16
|
[](https://github.com/testdouble/standard)
|
17
17
|
|
18
|
+
## Features
|
19
|
+
|
20
|
+
- 💬 **Beautiful Chat Interface** - Converse with AI models as easily as `RubyLLM.chat.ask "teach me Ruby"`
|
21
|
+
- 🎵 **Audio Analysis** - Get audio transcription and understanding with `chat.ask "what's said here?", with: { audio: "clip.wav" }`
|
22
|
+
- 👁️ **Vision Understanding** - Let AIs analyze images with a simple `chat.ask "what's in this?", with: { image: "photo.jpg" }`
|
23
|
+
- 🌊 **Streaming** - Real-time responses with proper Ruby streaming with `chat.ask "hello" do |chunk| puts chunk.content end`
|
24
|
+
- 🚂 **Rails Integration** - Persist chats and messages with ActiveRecord with `acts_as_{chat|message|tool_call}`
|
25
|
+
- 🛠️ **Tool Support** - Give AIs access to your Ruby code with `chat.with_tool(Calculator).ask "what's 2+2?"`
|
26
|
+
- 🎨 **Paint with AI** - Create images as easily as `RubyLLM.paint "a sunset over mountains"`
|
27
|
+
- 📊 **Embeddings** - Generate vector embeddings for your text with `RubyLLM.embed "hello"`
|
28
|
+
- 🔄 **Multi-Provider Support** - Works with OpenAI, Anthropic, Google, and DeepSeek
|
29
|
+
- 🎯 **Token Tracking** - Automatic usage tracking across providers
|
30
|
+
|
18
31
|
## Installation
|
19
32
|
|
20
33
|
Add it to your Gemfile:
|
@@ -87,11 +100,47 @@ chat.ask "Tell me a story about a Ruby programmer" do |chunk|
|
|
87
100
|
print chunk.content
|
88
101
|
end
|
89
102
|
|
103
|
+
# Ask about images
|
104
|
+
chat.ask "What do you see in this image?", with: { image: "ruby_logo.png" }
|
105
|
+
|
106
|
+
# Get analysis of audio content
|
107
|
+
chat.ask "What's being said in this recording?", with: { audio: "meeting.wav" }
|
108
|
+
|
109
|
+
# Combine multiple pieces of content
|
110
|
+
chat.ask "Compare these diagrams", with: { image: ["diagram1.png", "diagram2.png"] }
|
111
|
+
|
90
112
|
# Check token usage
|
91
113
|
last_message = chat.messages.last
|
92
114
|
puts "Conversation used #{last_message.input_tokens} input tokens and #{last_message.output_tokens} output tokens"
|
93
115
|
```
|
94
116
|
|
117
|
+
You can provide content as local files or URLs - RubyLLM handles the rest. Vision and audio capabilities are available with compatible models (Claude 3, GPT-4V, Gemini Pro Vision). The API stays clean and consistent whether you're working with text, images, or audio.
|
118
|
+
|
119
|
+
## Image Generation
|
120
|
+
|
121
|
+
Want to create AI-generated images? RubyLLM makes it super simple:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
# Paint a picture!
|
125
|
+
image = RubyLLM.paint "a starry night over San Francisco in Van Gogh's style"
|
126
|
+
image.url # => "https://..."
|
127
|
+
image.revised_prompt # Shows how DALL-E interpreted your prompt
|
128
|
+
|
129
|
+
# Choose size and model
|
130
|
+
image = RubyLLM.paint(
|
131
|
+
"a cyberpunk cityscape at sunset",
|
132
|
+
model: "dall-e-3",
|
133
|
+
size: "1792x1024"
|
134
|
+
)
|
135
|
+
|
136
|
+
# Set your default model
|
137
|
+
RubyLLM.configure do |config|
|
138
|
+
config.default_image_model = "dall-e-3"
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
RubyLLM automatically handles all the complexities of the DALL-E API, token/credit management, and error handling, so you can focus on being creative.
|
143
|
+
|
95
144
|
## Text Embeddings
|
96
145
|
|
97
146
|
Need vector embeddings for your text? RubyLLM makes it simple:
|
@@ -16,6 +16,7 @@ module RubyLLM
|
|
16
16
|
:deepseek_api_key,
|
17
17
|
:default_model,
|
18
18
|
:default_embedding_model,
|
19
|
+
:default_image_model,
|
19
20
|
:request_timeout,
|
20
21
|
:max_retries
|
21
22
|
|
@@ -24,6 +25,7 @@ module RubyLLM
|
|
24
25
|
@max_retries = 3
|
25
26
|
@default_model = 'gpt-4o-mini'
|
26
27
|
@default_embedding_model = 'text-embedding-3-small'
|
28
|
+
@default_image_model = 'dall-e-3'
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
data/lib/ruby_llm/content.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RubyLLM
|
4
|
-
# Represents the content received from
|
4
|
+
# Represents the content sent to or received from an LLM.
|
5
|
+
# Stores data in a standard internal format, letting providers
|
6
|
+
# handle their own formatting needs.
|
5
7
|
class Content
|
6
8
|
def initialize(text = nil, attachments = {})
|
7
9
|
@parts = []
|
@@ -33,7 +35,7 @@ module RubyLLM
|
|
33
35
|
def attach_image(source) # rubocop:disable Metrics/MethodLength
|
34
36
|
source = File.expand_path(source) unless source.start_with?('http')
|
35
37
|
|
36
|
-
return { type: '
|
38
|
+
return { type: 'image', source: { url: source } } if source.start_with?('http')
|
37
39
|
|
38
40
|
data = Base64.strict_encode64(File.read(source))
|
39
41
|
mime_type = mime_type_for(source)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
# Represents a generated image from an AI model.
|
5
|
+
# Provides an interface to image generation capabilities
|
6
|
+
# from providers like DALL-E.
|
7
|
+
class Image
|
8
|
+
attr_reader :url, :revised_prompt, :model_id
|
9
|
+
|
10
|
+
def initialize(url:, revised_prompt: nil, model_id: nil)
|
11
|
+
@url = url
|
12
|
+
@revised_prompt = revised_prompt
|
13
|
+
@model_id = model_id
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.paint(prompt, model: nil, size: '1024x1024')
|
17
|
+
model_id = model || RubyLLM.config.default_image_model
|
18
|
+
Models.find(model_id) # Validate model exists
|
19
|
+
|
20
|
+
provider = Provider.for(model_id)
|
21
|
+
provider.paint(prompt, model: model_id, size: size)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/ruby_llm/provider.rb
CHANGED
@@ -7,7 +7,7 @@ module RubyLLM
|
|
7
7
|
module Provider
|
8
8
|
# Common functionality for all LLM providers. Implements the core provider
|
9
9
|
# interface so specific providers only need to implement a few key methods.
|
10
|
-
module Methods
|
10
|
+
module Methods # rubocop:disable Metrics/ModuleLength
|
11
11
|
def complete(messages, tools:, temperature:, model:, &block)
|
12
12
|
payload = render_payload messages, tools: tools, temperature: temperature, model: model, stream: block_given?
|
13
13
|
|
@@ -32,6 +32,13 @@ module RubyLLM
|
|
32
32
|
parse_embedding_response response
|
33
33
|
end
|
34
34
|
|
35
|
+
def paint(prompt, model:, size:)
|
36
|
+
payload = render_image_payload(prompt, model:, size:)
|
37
|
+
|
38
|
+
response = post(images_url, payload)
|
39
|
+
parse_image_response(response)
|
40
|
+
end
|
41
|
+
|
35
42
|
private
|
36
43
|
|
37
44
|
def sync_response(payload)
|
@@ -59,11 +66,21 @@ module RubyLLM
|
|
59
66
|
end
|
60
67
|
end
|
61
68
|
|
62
|
-
def connection # rubocop:disable Metrics/MethodLength
|
63
|
-
@connection ||= Faraday.new(api_base) do |f|
|
69
|
+
def connection # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
70
|
+
@connection ||= Faraday.new(api_base) do |f| # rubocop:disable Metrics/BlockLength
|
64
71
|
f.options.timeout = RubyLLM.config.request_timeout
|
65
72
|
|
66
|
-
|
73
|
+
f.response :logger,
|
74
|
+
RubyLLM.logger,
|
75
|
+
bodies: true,
|
76
|
+
response: true,
|
77
|
+
errors: true,
|
78
|
+
headers: false,
|
79
|
+
log_level: :debug do |logger|
|
80
|
+
logger.filter(%r{"[A-Za-z0-9+/=]{100,}"}, 'data":"[BASE64 DATA]"')
|
81
|
+
logger.filter(/[-\d.e,\s]{100,}/, '[EMBEDDINGS ARRAY]')
|
82
|
+
end
|
83
|
+
|
67
84
|
f.request :retry, {
|
68
85
|
max: RubyLLM.config.max_retries,
|
69
86
|
interval: 0.05,
|
@@ -86,7 +103,6 @@ module RubyLLM
|
|
86
103
|
f.response :json
|
87
104
|
f.adapter Faraday.default_adapter
|
88
105
|
f.use :llm_errors, provider: self
|
89
|
-
f.response :logger, RubyLLM.logger, { headers: false, bodies: true, errors: true, log_level: :debug }
|
90
106
|
end
|
91
107
|
end
|
92
108
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
module OpenAI
|
6
|
+
# Image generation methods for the OpenAI API integration
|
7
|
+
module Images
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def images_url
|
11
|
+
'images/generations'
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_image_payload(prompt, model:, size:)
|
15
|
+
{
|
16
|
+
model: model,
|
17
|
+
prompt: prompt,
|
18
|
+
n: 1,
|
19
|
+
size: size
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def parse_image_response(response)
|
26
|
+
data = response.body
|
27
|
+
image_data = data['data'].first
|
28
|
+
|
29
|
+
Image.new(
|
30
|
+
url: image_data['url'],
|
31
|
+
revised_prompt: image_data['revised_prompt'],
|
32
|
+
model_id: data['model']
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
module OpenAI
|
6
|
+
# Handles formatting of media content (images, audio) for OpenAI APIs
|
7
|
+
module Media
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def format_content(content) # rubocop:disable Metrics/MethodLength
|
11
|
+
return content unless content.is_a?(Array)
|
12
|
+
|
13
|
+
content.map do |part|
|
14
|
+
case part[:type]
|
15
|
+
when 'image'
|
16
|
+
format_image(part)
|
17
|
+
when 'input_audio'
|
18
|
+
format_audio(part)
|
19
|
+
else
|
20
|
+
part
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def format_image(part)
|
26
|
+
{
|
27
|
+
type: 'image_url',
|
28
|
+
image_url: {
|
29
|
+
url: format_data_url(part[:source]),
|
30
|
+
detail: 'auto'
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def format_audio(part)
|
36
|
+
{
|
37
|
+
type: 'input_audio',
|
38
|
+
input_audio: part[:input_audio]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def format_data_url(source)
|
43
|
+
if source[:type] == 'base64'
|
44
|
+
"data:#{source[:media_type]};base64,#{source[:data]}"
|
45
|
+
else
|
46
|
+
source[:url]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -12,6 +12,8 @@ module RubyLLM
|
|
12
12
|
extend OpenAI::Models
|
13
13
|
extend OpenAI::Streaming
|
14
14
|
extend OpenAI::Tools
|
15
|
+
extend OpenAI::Images
|
16
|
+
extend OpenAI::Media
|
15
17
|
|
16
18
|
def self.extended(base)
|
17
19
|
base.extend(Provider)
|
@@ -20,6 +22,8 @@ module RubyLLM
|
|
20
22
|
base.extend(OpenAI::Models)
|
21
23
|
base.extend(OpenAI::Streaming)
|
22
24
|
base.extend(OpenAI::Tools)
|
25
|
+
base.extend(OpenAI::Images)
|
26
|
+
base.extend(OpenAI::Media)
|
23
27
|
end
|
24
28
|
|
25
29
|
module_function
|
data/lib/ruby_llm/version.rb
CHANGED
data/lib/ruby_llm.rb
CHANGED
data/ruby_llm.gemspec
CHANGED
@@ -8,11 +8,11 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ['Carmine Paolino']
|
9
9
|
spec.email = ['carmine@paolino.me']
|
10
10
|
|
11
|
-
spec.summary = '
|
12
|
-
spec.description = 'A delightful Ruby way to work with AI
|
13
|
-
'
|
14
|
-
'
|
15
|
-
' - just clean Ruby code that works.'
|
11
|
+
spec.summary = 'Beautiful Ruby interface to modern AI'
|
12
|
+
spec.description = 'A delightful Ruby way to work with AI. Chat in text, analyze and generate images, understand' \
|
13
|
+
' audio, and use tools through a unified interface to OpenAI, Anthropic, Google, and DeepSeek.' \
|
14
|
+
' Built for developer happiness with automatic token counting, proper streaming, and Rails' \
|
15
|
+
' integration. No wrapping your head around multiple APIs - just clean Ruby code that works.'
|
16
16
|
spec.homepage = 'https://github.com/crmne/ruby_llm'
|
17
17
|
spec.license = 'MIT'
|
18
18
|
spec.required_ruby_version = Gem::Requirement.new('>= 3.1.0')
|
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.
|
4
|
+
version: 0.1.0.pre33
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carmine Paolino
|
@@ -350,10 +350,11 @@ dependencies:
|
|
350
350
|
- - ">="
|
351
351
|
- !ruby/object:Gem::Version
|
352
352
|
version: '0.9'
|
353
|
-
description: A delightful Ruby way to work with AI
|
354
|
-
|
355
|
-
|
356
|
-
|
353
|
+
description: A delightful Ruby way to work with AI. Chat in text, analyze and generate
|
354
|
+
images, understand audio, and use tools through a unified interface to OpenAI, Anthropic,
|
355
|
+
Google, and DeepSeek. Built for developer happiness with automatic token counting,
|
356
|
+
proper streaming, and Rails integration. No wrapping your head around multiple APIs
|
357
|
+
- just clean Ruby code that works.
|
357
358
|
email:
|
358
359
|
- carmine@paolino.me
|
359
360
|
executables: []
|
@@ -380,6 +381,7 @@ files:
|
|
380
381
|
- lib/ruby_llm/content.rb
|
381
382
|
- lib/ruby_llm/embedding.rb
|
382
383
|
- lib/ruby_llm/error.rb
|
384
|
+
- lib/ruby_llm/image.rb
|
383
385
|
- lib/ruby_llm/message.rb
|
384
386
|
- lib/ruby_llm/model_info.rb
|
385
387
|
- lib/ruby_llm/models.json
|
@@ -401,6 +403,8 @@ files:
|
|
401
403
|
- lib/ruby_llm/providers/openai/capabilities.rb
|
402
404
|
- lib/ruby_llm/providers/openai/chat.rb
|
403
405
|
- lib/ruby_llm/providers/openai/embeddings.rb
|
406
|
+
- lib/ruby_llm/providers/openai/images.rb
|
407
|
+
- lib/ruby_llm/providers/openai/media.rb
|
404
408
|
- lib/ruby_llm/providers/openai/models.rb
|
405
409
|
- lib/ruby_llm/providers/openai/streaming.rb
|
406
410
|
- lib/ruby_llm/providers/openai/tools.rb
|
@@ -438,5 +442,5 @@ requirements: []
|
|
438
442
|
rubygems_version: 3.5.22
|
439
443
|
signing_key:
|
440
444
|
specification_version: 4
|
441
|
-
summary:
|
445
|
+
summary: Beautiful Ruby interface to modern AI
|
442
446
|
test_files: []
|