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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2433d0b669ef8bd499507edf33ed672d011fc1c95c2de0febd4e83d2593e0b8
4
- data.tar.gz: a818a1c59220404c29c0e562c473480ac630a6fd53fadee65ab102b8955e9ec5
3
+ metadata.gz: e122212234e51321ae20de6894bb476b46c83d745ca30bedd9ced246bdcff22f
4
+ data.tar.gz: c0619618ca5e09db904545594c613b87ade415a4d1ed38ebd2c8b5857933ea02
5
5
  SHA512:
6
- metadata.gz: afa3882a1850692e63f16dbc8c379a9aa71d704096f1eb2d5d88aeefa0c9c17f2585e8e215be0ed126caa0ec6bb7d07b4c12b5b6eaa5a1cf69a054b976b0d9e8
7
- data.tar.gz: a8089658eab75b8200f51d39568dc876cdcc2d61d6581dbd1e6c211f487fa127c9300e0fcbb318f958b6b109f5fb43c2f7f6824acd2f426e4a0a9ae2a7023c63
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 | 11.61 seconds |
39
- ./spec/ruby_llm/image_generation_spec.rb[1:1:2] | passed | 17.63 seconds |
40
- ./spec/ruby_llm/image_generation_spec.rb[1:1:3] | passed | 8.77 seconds |
41
- ./spec/ruby_llm/image_generation_spec.rb[1:1:4] | passed | 0.00319 seconds |
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 |
@@ -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:, revised_prompt: nil, model_id: nil)
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
@@ -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 # All available models
9
- # RubyLLM.models.chat_models # Models that support chat
10
- # RubyLLM.models.find('claude-3') # Get info about a specific model
11
- module Models
12
- module_function
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 provider_for(model)
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 all
19
- @all ||= begin
20
- data = JSON.parse(File.read(File.expand_path('models.json', __dir__)))
21
- data.map { |model| ModelInfo.new(model.transform_keys(&:to_sym)) }
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 raise ModelNotFoundError, "Unknown model: #{model_id}"
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
- def refresh!
56
- @all = RubyLLM.providers.flat_map(&:list_models).sort_by(&:id)
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
@@ -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
- # Handle response with base64 encoded image data
41
- image_url = "data:#{image_data['mimeType'] || 'image/png'};base64,#{image_data['bytesBase64Encoded']}"
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
- url: image_url,
44
- revised_prompt: '', # Imagen doesn't return revised prompts
45
- model_id: ''
45
+ data: base64_data,
46
+ mime_type: mime_type
46
47
  )
47
48
  end
48
49
  end
@@ -26,6 +26,7 @@ module RubyLLM
26
26
 
27
27
  Image.new(
28
28
  url: image_data['url'],
29
+ mime_type: 'image/png', # DALL-E typically returns PNGs
29
30
  revised_prompt: image_data['revised_prompt'],
30
31
  model_id: data['model']
31
32
  )
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyLLM
4
- VERSION = '0.1.0.pre43'
4
+ VERSION = '0.1.0.pre45'
5
5
  end
data/lib/ruby_llm.rb CHANGED
@@ -39,7 +39,7 @@ module RubyLLM
39
39
  end
40
40
 
41
41
  def models
42
- Models
42
+ Models.instance
43
43
  end
44
44
 
45
45
  def providers
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.pre43
4
+ version: 0.1.0.pre45
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carmine Paolino