ruby_llm 0.1.0.pre43 → 0.1.0.pre45
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/.rspec_status +13 -4
- data/lib/ruby_llm/image.rb +26 -3
- data/lib/ruby_llm/models.rb +67 -22
- data/lib/ruby_llm/provider.rb +10 -0
- data/lib/ruby_llm/providers/gemini/images.rb +6 -5
- data/lib/ruby_llm/providers/openai/images.rb +1 -0
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e122212234e51321ae20de6894bb476b46c83d745ca30bedd9ced246bdcff22f
|
4
|
+
data.tar.gz: c0619618ca5e09db904545594c613b87ade415a4d1ed38ebd2c8b5857933ea02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e14f4c2ce93c2d6a4f8ba3909b78a2cad5fb336066b28999ace00135f6abb7a1c3a56389e5a01b41583c86a1b3521ff4296266be9eba831e06b591f558756045
|
7
|
+
data.tar.gz: 6b68676a11c6168cccb7237fd3e90624fbe624402b731ffd87925f3805bffec849a9358c807890dea142f83035a511964b097defbe52a9ef33c679f6cf9195a3
|
data/.rspec_status
CHANGED
@@ -35,7 +35,16 @@ example_id | status | run_time |
|
|
35
35
|
./spec/ruby_llm/embeddings_spec.rb[1:1:2:1] | passed | 0.65614 seconds |
|
36
36
|
./spec/ruby_llm/embeddings_spec.rb[1:1:2:2] | passed | 2.16 seconds |
|
37
37
|
./spec/ruby_llm/error_handling_spec.rb[1:1] | passed | 0.29366 seconds |
|
38
|
-
./spec/ruby_llm/image_generation_spec.rb[1:1:1] | passed |
|
39
|
-
./spec/ruby_llm/image_generation_spec.rb[1:1:2] | passed |
|
40
|
-
./spec/ruby_llm/image_generation_spec.rb[1:1:3] | passed |
|
41
|
-
./spec/ruby_llm/image_generation_spec.rb[1:1:4] | passed | 0.
|
38
|
+
./spec/ruby_llm/image_generation_spec.rb[1:1:1] | passed | 24.16 seconds |
|
39
|
+
./spec/ruby_llm/image_generation_spec.rb[1:1:2] | passed | 14.81 seconds |
|
40
|
+
./spec/ruby_llm/image_generation_spec.rb[1:1:3] | passed | 9.17 seconds |
|
41
|
+
./spec/ruby_llm/image_generation_spec.rb[1:1:4] | passed | 0.00083 seconds |
|
42
|
+
./spec/ruby_llm/models_spec.rb[1:1:1] | passed | 0.00337 seconds |
|
43
|
+
./spec/ruby_llm/models_spec.rb[1:2:1] | passed | 0.00435 seconds |
|
44
|
+
./spec/ruby_llm/models_spec.rb[1:2:2] | passed | 0.00491 seconds |
|
45
|
+
./spec/ruby_llm/models_spec.rb[1:2:3] | passed | 0.00028 seconds |
|
46
|
+
./spec/ruby_llm/models_spec.rb[1:3:1] | passed | 0.00007 seconds |
|
47
|
+
./spec/ruby_llm/models_spec.rb[1:3:2] | passed | 0.00036 seconds |
|
48
|
+
./spec/ruby_llm/models_spec.rb[1:3:3] | passed | 0.00252 seconds |
|
49
|
+
./spec/ruby_llm/models_spec.rb[1:4:1] | passed | 0.0016 seconds |
|
50
|
+
./spec/ruby_llm/models_spec.rb[1:4:2] | passed | 0.00156 seconds |
|
data/lib/ruby_llm/image.rb
CHANGED
@@ -3,16 +3,39 @@
|
|
3
3
|
module RubyLLM
|
4
4
|
# Represents a generated image from an AI model.
|
5
5
|
# Provides an interface to image generation capabilities
|
6
|
-
# from providers like DALL-E.
|
6
|
+
# from providers like DALL-E and Gemini's Imagen.
|
7
7
|
class Image
|
8
|
-
attr_reader :url, :revised_prompt, :model_id
|
8
|
+
attr_reader :url, :data, :mime_type, :revised_prompt, :model_id
|
9
9
|
|
10
|
-
def initialize(url
|
10
|
+
def initialize(url: nil, data: nil, mime_type: nil, revised_prompt: nil, model_id: nil)
|
11
11
|
@url = url
|
12
|
+
@data = data
|
13
|
+
@mime_type = mime_type
|
12
14
|
@revised_prompt = revised_prompt
|
13
15
|
@model_id = model_id
|
14
16
|
end
|
15
17
|
|
18
|
+
def base64?
|
19
|
+
!@data.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the raw binary image data regardless of source
|
23
|
+
def to_blob
|
24
|
+
if base64?
|
25
|
+
Base64.decode64(@data)
|
26
|
+
else
|
27
|
+
# Use Faraday instead of URI.open for better security
|
28
|
+
response = Faraday.get(@url)
|
29
|
+
response.body
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Saves the image to a file path
|
34
|
+
def save(path)
|
35
|
+
File.binwrite(File.expand_path(path), to_blob)
|
36
|
+
path
|
37
|
+
end
|
38
|
+
|
16
39
|
def self.paint(prompt, model: nil, size: '1024x1024')
|
17
40
|
model_id = model || RubyLLM.config.default_image_model
|
18
41
|
Models.find(model_id) # Validate model exists
|
data/lib/ruby_llm/models.rb
CHANGED
@@ -5,55 +5,100 @@ module RubyLLM
|
|
5
5
|
# to discover and work with models from different providers.
|
6
6
|
#
|
7
7
|
# Example:
|
8
|
-
# RubyLLM.models.all
|
9
|
-
# RubyLLM.models.chat_models
|
10
|
-
# RubyLLM.models.
|
11
|
-
|
12
|
-
|
8
|
+
# RubyLLM.models.all # All available models
|
9
|
+
# RubyLLM.models.chat_models # Models that support chat
|
10
|
+
# RubyLLM.models.by_provider('openai').chat_models # OpenAI chat models
|
11
|
+
# RubyLLM.models.find('claude-3') # Get info about a specific model
|
12
|
+
class Models
|
13
|
+
include Enumerable
|
13
14
|
|
14
|
-
def
|
15
|
+
def self.instance
|
16
|
+
@instance ||= new
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.provider_for(model)
|
15
20
|
Provider.for(model)
|
16
21
|
end
|
17
22
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
23
|
+
def self.refresh!
|
24
|
+
models = RubyLLM.providers.flat_map(&:list_models).sort_by(&:id)
|
25
|
+
# Write to models.json
|
26
|
+
File.write(File.expand_path('models.json', __dir__), JSON.pretty_generate(models.map(&:to_h)))
|
27
|
+
@instance = new(models)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Delegate class methods to the singleton instance
|
31
|
+
class << self
|
32
|
+
def method_missing(method, ...)
|
33
|
+
if instance.respond_to?(method)
|
34
|
+
instance.send(method, ...)
|
35
|
+
else
|
36
|
+
super
|
37
|
+
end
|
22
38
|
end
|
39
|
+
|
40
|
+
def respond_to_missing?(method, include_private = false)
|
41
|
+
instance.respond_to?(method, include_private) || super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Initialize with optional pre-filtered models
|
46
|
+
def initialize(models = nil)
|
47
|
+
@models = models || load_models
|
48
|
+
end
|
49
|
+
|
50
|
+
# Load models from the JSON file
|
51
|
+
def load_models
|
52
|
+
data = JSON.parse(File.read(File.expand_path('models.json', __dir__)))
|
53
|
+
data.map { |model| ModelInfo.new(model.transform_keys(&:to_sym)) }
|
23
54
|
rescue Errno::ENOENT
|
24
55
|
[] # Return empty array if file doesn't exist yet
|
25
56
|
end
|
26
57
|
|
58
|
+
# Return all models in the collection
|
59
|
+
def all
|
60
|
+
@models
|
61
|
+
end
|
62
|
+
|
63
|
+
# Allow enumeration over all models
|
64
|
+
def each(&)
|
65
|
+
all.each(&)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Find a specific model by ID
|
27
69
|
def find(model_id)
|
28
|
-
all.find { |m| m.id == model_id } or
|
70
|
+
all.find { |m| m.id == model_id } or
|
71
|
+
raise ModelNotFoundError, "Unknown model: #{model_id}"
|
29
72
|
end
|
30
73
|
|
74
|
+
# Filter to only chat models
|
31
75
|
def chat_models
|
32
|
-
all.select { |m| m.type == 'chat' }
|
76
|
+
self.class.new(all.select { |m| m.type == 'chat' })
|
33
77
|
end
|
34
78
|
|
79
|
+
# Filter to only embedding models
|
35
80
|
def embedding_models
|
36
|
-
all.select { |m| m.type == 'embedding' }
|
81
|
+
self.class.new(all.select { |m| m.type == 'embedding' })
|
37
82
|
end
|
38
83
|
|
84
|
+
# Filter to only audio models
|
39
85
|
def audio_models
|
40
|
-
all.select { |m| m.type == 'audio' }
|
86
|
+
self.class.new(all.select { |m| m.type == 'audio' })
|
41
87
|
end
|
42
88
|
|
89
|
+
# Filter to only image models
|
43
90
|
def image_models
|
44
|
-
all.select { |m| m.type == 'image' }
|
91
|
+
self.class.new(all.select { |m| m.type == 'image' })
|
45
92
|
end
|
46
93
|
|
94
|
+
# Filter models by family
|
47
95
|
def by_family(family)
|
48
|
-
all.select { |m| m.family == family }
|
49
|
-
end
|
50
|
-
|
51
|
-
def default_model
|
52
|
-
'gpt-4o-mini'
|
96
|
+
self.class.new(all.select { |m| m.family == family.to_s })
|
53
97
|
end
|
54
98
|
|
55
|
-
|
56
|
-
|
99
|
+
# Filter models by provider
|
100
|
+
def by_provider(provider)
|
101
|
+
self.class.new(all.select { |m| m.provider == provider.to_s })
|
57
102
|
end
|
58
103
|
end
|
59
104
|
end
|
data/lib/ruby_llm/provider.rb
CHANGED
@@ -158,6 +158,16 @@ module RubyLLM
|
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
161
|
+
def parse_data_uri(uri)
|
162
|
+
if uri&.start_with?('data:')
|
163
|
+
match = uri.match(/\Adata:([^;]+);base64,(.+)\z/)
|
164
|
+
return { mime_type: match[1], data: match[2] } if match
|
165
|
+
end
|
166
|
+
|
167
|
+
# If it's not a data URI, return nil
|
168
|
+
nil
|
169
|
+
end
|
170
|
+
|
161
171
|
class << self
|
162
172
|
def extended(base)
|
163
173
|
base.extend(Methods)
|
@@ -37,12 +37,13 @@ module RubyLLM
|
|
37
37
|
raise Error, 'Unexpected response format from Gemini image generation API'
|
38
38
|
end
|
39
39
|
|
40
|
-
#
|
41
|
-
|
40
|
+
# Extract mime type and base64 data
|
41
|
+
mime_type = image_data['mimeType'] || 'image/png'
|
42
|
+
base64_data = image_data['bytesBase64Encoded']
|
43
|
+
|
42
44
|
Image.new(
|
43
|
-
|
44
|
-
|
45
|
-
model_id: ''
|
45
|
+
data: base64_data,
|
46
|
+
mime_type: mime_type
|
46
47
|
)
|
47
48
|
end
|
48
49
|
end
|
data/lib/ruby_llm/version.rb
CHANGED
data/lib/ruby_llm.rb
CHANGED