imago 0.1.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7ab8cd4f924113a9ba92f0f6918b137c0132ebda6fe9d8d2006a62e158d1f987
4
+ data.tar.gz: 78f6726394dac041f2d82d1e068012767c94a616267801ac4cf597540e070884
5
+ SHA512:
6
+ metadata.gz: d9b288487b3d77b17b70fe5289a9b63744e454f2bf01358304b846e0eb6cef28326287ac319887a1e539ea7f15a16ad22fc19f6579da47118d0fa6685b8d51e0
7
+ data.tar.gz: 2f3d13bd6d3bce751755c6a41e333139413cc28a1f31e6fde0c09c7671a592a9d87d731336200733112ad15d4886376708c48f25decf1008126866615d6f8bfa
data/.rubocop.yml ADDED
@@ -0,0 +1,48 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 3.0
6
+ NewCops: enable
7
+ SuggestExtensions: false
8
+ Exclude:
9
+ - 'vendor/**/*'
10
+ - 'tmp/**/*'
11
+
12
+ Capybara:
13
+ Enabled: false
14
+
15
+ Capybara/RSpec:
16
+ Enabled: false
17
+
18
+ Capybara/RSpec/PredicateMatcher:
19
+ Enabled: false
20
+
21
+ FactoryBot:
22
+ Enabled: false
23
+
24
+ RSpecRails:
25
+ Enabled: false
26
+
27
+ Style/Documentation:
28
+ Enabled: false
29
+
30
+ Metrics/BlockLength:
31
+ Exclude:
32
+ - 'spec/**/*'
33
+ - '*.gemspec'
34
+
35
+ RSpec/ExampleLength:
36
+ Max: 15
37
+
38
+ RSpec/MultipleExpectations:
39
+ Max: 5
40
+
41
+ RSpec/NestedGroups:
42
+ Max: 4
43
+
44
+ Layout/LineLength:
45
+ Max: 120
46
+
47
+ RSpec/MessageSpies:
48
+ EnforcedStyle: receive
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-4.0.0
data/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # Imago
2
+
3
+ A unified Ruby interface for multiple image generation AI providers. Generate images using OpenAI (DALL-E), Google Gemini (Imagen), and xAI (Grok) through a single, consistent API.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'imago'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ gem install imago
23
+ ```
24
+
25
+ ## Configuration
26
+
27
+ Set API keys via environment variables:
28
+
29
+ ```bash
30
+ export OPENAI_API_KEY="your-openai-key"
31
+ export GEMINI_API_KEY="your-gemini-key"
32
+ export XAI_API_KEY="your-xai-key"
33
+ ```
34
+
35
+ Or pass them directly when creating a client.
36
+
37
+ ## Usage
38
+
39
+ ### Basic Usage
40
+
41
+ ```ruby
42
+ require 'imago'
43
+
44
+ # Create a client for OpenAI
45
+ client = Imago.new(provider: :openai)
46
+
47
+ # Generate an image
48
+ result = client.generate("A serene mountain landscape at sunset")
49
+ puts result[:images].first[:url]
50
+ ```
51
+
52
+ ### Specifying a Model
53
+
54
+ ```ruby
55
+ # Use a specific model
56
+ client = Imago.new(provider: :openai, model: 'dall-e-2')
57
+
58
+ result = client.generate("A cat wearing a hat")
59
+ ```
60
+
61
+ ### Passing API Key Directly
62
+
63
+ ```ruby
64
+ client = Imago.new(
65
+ provider: :openai,
66
+ api_key: 'sk-your-api-key'
67
+ )
68
+ ```
69
+
70
+ ### Provider-Specific Options
71
+
72
+ Each provider supports different options:
73
+
74
+ #### OpenAI (DALL-E)
75
+
76
+ ```ruby
77
+ client = Imago.new(provider: :openai)
78
+
79
+ result = client.generate("A futuristic city", {
80
+ size: '1024x1024', # '256x256', '512x512', '1024x1024', '1792x1024', '1024x1792'
81
+ quality: 'hd', # 'standard' or 'hd'
82
+ n: 1, # Number of images (1-10)
83
+ response_format: 'url' # 'url' or 'b64_json'
84
+ })
85
+
86
+ # Access the generated image
87
+ result[:images].each do |image|
88
+ puts image[:url]
89
+ puts image[:revised_prompt] # DALL-E 3 may revise your prompt
90
+ end
91
+ ```
92
+
93
+ #### Google Gemini (Imagen)
94
+
95
+ ```ruby
96
+ client = Imago.new(provider: :gemini)
97
+
98
+ result = client.generate("A tropical beach", {
99
+ n: 1, # Number of images
100
+ aspect_ratio: '16:9', # Aspect ratio
101
+ negative_prompt: 'people', # What to exclude
102
+ seed: 12345 # For reproducibility
103
+ })
104
+
105
+ # Gemini returns base64-encoded images
106
+ result[:images].each do |image|
107
+ puts image[:base64]
108
+ puts image[:mime_type]
109
+ end
110
+ ```
111
+
112
+ #### xAI (Grok)
113
+
114
+ ```ruby
115
+ client = Imago.new(provider: :xai)
116
+
117
+ result = client.generate("A robot playing chess", {
118
+ n: 1,
119
+ response_format: 'url' # 'url' or 'b64_json'
120
+ })
121
+
122
+ result[:images].each do |image|
123
+ puts image[:url]
124
+ end
125
+ ```
126
+
127
+ ### Listing Available Models
128
+
129
+ ```ruby
130
+ client = Imago.new(provider: :openai)
131
+
132
+ # Returns available image generation models
133
+ models = client.models
134
+ # => ["dall-e-3", "dall-e-2", "gpt-image-1"]
135
+ ```
136
+
137
+ For providers with a models API (OpenAI, Gemini), this fetches from the API and caches the result. For providers without such an endpoint (xAI), it returns a curated list of known models.
138
+
139
+ ## Supported Providers
140
+
141
+ Model list last updated: 01/18/2026.
142
+
143
+ | Provider | Models | API Key Env Var |
144
+ |----------|--------|-----------------|
145
+ | OpenAI | `dall-e-3`, `dall-e-2`, `gpt-image-1`, `gpt-image-1.5`, `gpt-image-1-mini` | `OPENAI_API_KEY` |
146
+ | Gemini | `imagen-3.0-generate-002`, `imagen-3.0-generate-001`, `gemini-2.0-flash-exp-image-generation`, `gemini-2.5-flash-image`, `gemini-3-pro-image-preview` | `GEMINI_API_KEY` |
147
+ | xAI | `grok-2-image`, `grok-2-image-1212` | `XAI_API_KEY` |
148
+
149
+ ## Error Handling
150
+
151
+ Imago provides specific error classes for different failure scenarios:
152
+
153
+ ```ruby
154
+ begin
155
+ client = Imago.new(provider: :openai)
156
+ result = client.generate("A cat")
157
+ rescue Imago::AuthenticationError => e
158
+ puts "Invalid API key: #{e.message}"
159
+ rescue Imago::RateLimitError => e
160
+ puts "Rate limited: #{e.message}"
161
+ rescue Imago::InvalidRequestError => e
162
+ puts "Bad request: #{e.message}"
163
+ rescue Imago::ApiError => e
164
+ puts "API error: #{e.message}"
165
+ puts "Status code: #{e.status_code}"
166
+ rescue Imago::ConfigurationError => e
167
+ puts "Configuration error: #{e.message}"
168
+ rescue Imago::ProviderNotFoundError => e
169
+ puts "Unknown provider: #{e.message}"
170
+ end
171
+ ```
172
+
173
+ ## Development
174
+
175
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests. You can also run `rake rubocop` for linting.
176
+
177
+ ```bash
178
+ bundle install
179
+ bundle exec rake spec # Run tests
180
+ bundle exec rake rubocop # Run linter
181
+ bundle exec rake # Run both
182
+ ```
183
+
184
+ ## Contributing
185
+
186
+ Bug reports and pull requests are welcome on GitHub.
187
+
188
+ ## License
189
+
190
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ task default: %i[rubocop spec]
data/imago.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/imago/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'imago'
7
+ spec.version = Imago::VERSION
8
+ spec.authors = ['Your Name']
9
+ spec.email = ['your.email@example.com']
10
+
11
+ spec.summary = 'A unified Ruby interface for multiple image generation AI providers'
12
+ spec.description = 'Imago provides a simple, unified API to generate images using various AI providers ' \
13
+ 'including OpenAI (DALL-E), Google Gemini, and xAI (Grok).'
14
+ spec.homepage = 'https://github.com/example/imago'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = '>= 3.0.0'
17
+
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = spec.homepage
20
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
21
+ spec.metadata['rubygems_mfa_required'] = 'true'
22
+
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (File.expand_path(f) == __FILE__) ||
26
+ f.start_with?('bin/', 'test/', 'spec/', 'features/', '.git', '.github', 'appveyor', 'Gemfile')
27
+ end
28
+ end
29
+ spec.bindir = 'exe'
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ['lib']
32
+
33
+ spec.add_dependency 'faraday', '~> 2.0'
34
+ spec.add_dependency 'faraday-multipart', '~> 1.0'
35
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Imago
4
+ class Client
5
+ PROVIDERS = {
6
+ openai: Providers::OpenAI,
7
+ gemini: Providers::Gemini,
8
+ xai: Providers::XAI
9
+ }.freeze
10
+
11
+ attr_reader :provider, :model
12
+
13
+ def initialize(provider:, model: nil, api_key: nil)
14
+ @provider_name = provider.to_sym
15
+ @model = model
16
+ @api_key = api_key
17
+
18
+ validate_provider!
19
+ @provider = build_provider
20
+ end
21
+
22
+ def generate(prompt, opts = {})
23
+ provider.generate(prompt, opts)
24
+ end
25
+
26
+ def models
27
+ provider.models
28
+ end
29
+
30
+ private
31
+
32
+ def validate_provider!
33
+ return if PROVIDERS.key?(@provider_name)
34
+
35
+ raise ProviderNotFoundError, "Unknown provider: #{@provider_name}. " \
36
+ "Available providers: #{PROVIDERS.keys.join(', ')}"
37
+ end
38
+
39
+ def build_provider
40
+ PROVIDERS[@provider_name].new(model: @model, api_key: @api_key)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Imago
4
+ class Error < StandardError; end
5
+
6
+ class ConfigurationError < Error; end
7
+
8
+ class ApiError < Error
9
+ attr_reader :status_code, :response_body
10
+
11
+ def initialize(message, status_code: nil, response_body: nil)
12
+ @status_code = status_code
13
+ @response_body = response_body
14
+ super(message)
15
+ end
16
+ end
17
+
18
+ class AuthenticationError < ApiError; end
19
+
20
+ class RateLimitError < ApiError; end
21
+
22
+ class InvalidRequestError < ApiError; end
23
+
24
+ class ProviderNotFoundError < Error; end
25
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Imago
4
+ module Providers
5
+ class Base
6
+ attr_reader :model, :api_key
7
+
8
+ def initialize(model: nil, api_key: nil)
9
+ @model = model || default_model
10
+ @api_key = api_key || fetch_api_key
11
+ validate_api_key!
12
+ end
13
+
14
+ def generate(_prompt, _opts = {})
15
+ raise NotImplementedError, "#{self.class} must implement #generate"
16
+ end
17
+
18
+ def models
19
+ raise NotImplementedError, "#{self.class} must implement #models"
20
+ end
21
+
22
+ protected
23
+
24
+ def default_model
25
+ raise NotImplementedError, "#{self.class} must implement #default_model"
26
+ end
27
+
28
+ def env_key_name
29
+ raise NotImplementedError, "#{self.class} must implement #env_key_name"
30
+ end
31
+
32
+ def fetch_api_key
33
+ ENV.fetch(env_key_name, nil)
34
+ end
35
+
36
+ def validate_api_key!
37
+ return if api_key && !api_key.empty?
38
+
39
+ raise ConfigurationError,
40
+ "API key is required. Set #{env_key_name} environment variable or pass api_key option."
41
+ end
42
+
43
+ def connection(base_url)
44
+ Faraday.new(url: base_url) do |conn|
45
+ conn.request :json
46
+ conn.response :json
47
+ conn.adapter Faraday.default_adapter
48
+ end
49
+ end
50
+
51
+ def handle_response(response)
52
+ return response.body if response.status.between?(200, 299)
53
+
54
+ raise_response_error(response)
55
+ end
56
+
57
+ def raise_response_error(response)
58
+ error_class = error_class_for_status(response.status)
59
+ message = error_message_for_status(response)
60
+ raise error_class.new(message, status_code: response.status, response_body: response.body)
61
+ end
62
+
63
+ def error_class_for_status(status)
64
+ case status
65
+ when 401 then AuthenticationError
66
+ when 429 then RateLimitError
67
+ when 400..499 then InvalidRequestError
68
+ else ApiError
69
+ end
70
+ end
71
+
72
+ def error_message_for_status(response)
73
+ case response.status
74
+ when 401 then 'Invalid API key'
75
+ when 429 then 'Rate limit exceeded'
76
+ when 400..499 then "Request failed: #{response.body}"
77
+ else "API error: #{response.body}"
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Imago
4
+ module Providers
5
+ class Gemini < Base
6
+ BASE_URL = 'https://generativelanguage.googleapis.com/v1beta'
7
+
8
+ KNOWN_IMAGE_MODELS = %w[
9
+ imagen-3.0-generate-002
10
+ imagen-3.0-generate-001
11
+ gemini-2.0-flash-exp-image-generation
12
+ gemini-2.5-flash-image
13
+ gemini-3-pro-image-preview
14
+ ].freeze
15
+
16
+ def generate(prompt, opts = {})
17
+ conn = connection(BASE_URL)
18
+ endpoint = "models/#{model}:generateContent"
19
+
20
+ response = conn.post(endpoint) do |req|
21
+ req.params['key'] = api_key
22
+ req.body = build_request_body(prompt, opts)
23
+ end
24
+
25
+ parse_generate_response(handle_response(response))
26
+ end
27
+
28
+ def models
29
+ @models ||= fetch_models
30
+ end
31
+
32
+ protected
33
+
34
+ def default_model
35
+ 'gemini-3-pro-image-preview'
36
+ end
37
+
38
+ def env_key_name
39
+ 'GEMINI_API_KEY'
40
+ end
41
+
42
+ private
43
+
44
+ def build_request_body(prompt, opts)
45
+ body = { contents: [{ parts: [{ text: build_prompt(prompt, opts) }] }] }
46
+ body[:generationConfig] = build_generation_config(opts) if generation_config_present?(opts)
47
+ body
48
+ end
49
+
50
+ def build_prompt(prompt, opts)
51
+ return prompt unless opts[:negative_prompt]
52
+
53
+ "#{prompt}. Avoid: #{opts[:negative_prompt]}"
54
+ end
55
+
56
+ def generation_config_present?(opts)
57
+ opts[:n] || opts[:sample_count] || opts[:aspect_ratio] || opts[:seed]
58
+ end
59
+
60
+ def build_generation_config(opts)
61
+ config = {}
62
+ config[:candidateCount] = opts[:sample_count] || opts[:n] if opts[:n] || opts[:sample_count]
63
+ config[:seed] = opts[:seed] if opts[:seed]
64
+ config[:aspectRatio] = opts[:aspect_ratio] if opts[:aspect_ratio]
65
+ config
66
+ end
67
+
68
+ def parse_generate_response(body)
69
+ candidates = body['candidates'] || []
70
+ images = candidates.flat_map { |candidate| extract_images_from_candidate(candidate) }
71
+ { images: images }
72
+ end
73
+
74
+ def extract_images_from_candidate(candidate)
75
+ parts = candidate.dig('content', 'parts') || []
76
+ parts.filter_map do |part|
77
+ next unless part['inlineData']
78
+
79
+ { base64: part['inlineData']['data'], mime_type: part['inlineData']['mimeType'] }.compact
80
+ end
81
+ end
82
+
83
+ def fetch_models
84
+ conn = connection(BASE_URL)
85
+ response = conn.get('models') do |req|
86
+ req.params['key'] = api_key
87
+ end
88
+
89
+ body = handle_response(response)
90
+ filter_image_models(body['models'] || [])
91
+ rescue ApiError
92
+ KNOWN_IMAGE_MODELS
93
+ end
94
+
95
+ def filter_image_models(models)
96
+ image_model_names = models
97
+ .select { |m| m['supportedGenerationMethods']&.include?('generateContent') }
98
+ .map { |m| m['name'].sub('models/', '') }
99
+ .select { |name| name.include?('imagen') || name.include?('image') }
100
+
101
+ image_model_names.empty? ? KNOWN_IMAGE_MODELS : image_model_names
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Imago
4
+ module Providers
5
+ class OpenAI < Base
6
+ BASE_URL = 'https://api.openai.com/v1'
7
+
8
+ KNOWN_IMAGE_MODELS = %w[
9
+ dall-e-3
10
+ dall-e-2
11
+ gpt-image-1
12
+ gpt-image-1.5
13
+ gpt-image-1-mini
14
+ ].freeze
15
+
16
+ def generate(prompt, opts = {})
17
+ conn = connection(BASE_URL)
18
+ response = conn.post('images/generations') do |req|
19
+ req.headers['Authorization'] = "Bearer #{api_key}"
20
+ req.body = build_request_body(prompt, opts)
21
+ end
22
+
23
+ parse_generate_response(handle_response(response))
24
+ end
25
+
26
+ def models
27
+ @models ||= fetch_models
28
+ end
29
+
30
+ protected
31
+
32
+ def default_model
33
+ 'gpt-image-1.5'
34
+ end
35
+
36
+ def env_key_name
37
+ 'OPENAI_API_KEY'
38
+ end
39
+
40
+ private
41
+
42
+ def build_request_body(prompt, opts)
43
+ {
44
+ model: model,
45
+ prompt: prompt
46
+ }.merge(opts)
47
+ end
48
+
49
+ def parse_generate_response(body)
50
+ images = body['data']&.map { |img| parse_image(img) }
51
+ { images: images || [], created: body['created'] }
52
+ end
53
+
54
+ def parse_image(img)
55
+ { url: img['url'], base64: img['b64_json'], revised_prompt: img['revised_prompt'] }.compact
56
+ end
57
+
58
+ def fetch_models
59
+ conn = connection(BASE_URL)
60
+ response = conn.get('models') do |req|
61
+ req.headers['Authorization'] = "Bearer #{api_key}"
62
+ end
63
+
64
+ body = handle_response(response)
65
+ filter_image_models(body['data'] || [])
66
+ rescue ApiError
67
+ KNOWN_IMAGE_MODELS
68
+ end
69
+
70
+ def filter_image_models(models)
71
+ image_model_ids = models
72
+ .map { |m| m['id'] }
73
+ .select { |id| id.include?('dall-e') || id.include?('image') }
74
+
75
+ image_model_ids.empty? ? KNOWN_IMAGE_MODELS : image_model_ids
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Imago
4
+ module Providers
5
+ class XAI < Base
6
+ BASE_URL = 'https://api.x.ai/v1'
7
+
8
+ KNOWN_IMAGE_MODELS = %w[
9
+ grok-2-image
10
+ grok-2-image-1212
11
+ ].freeze
12
+
13
+ def generate(prompt, opts = {})
14
+ conn = connection(BASE_URL)
15
+ response = conn.post('images/generations') do |req|
16
+ req.headers['Authorization'] = "Bearer #{api_key}"
17
+ req.body = build_request_body(prompt, opts)
18
+ end
19
+
20
+ parse_generate_response(handle_response(response))
21
+ end
22
+
23
+ def models
24
+ KNOWN_IMAGE_MODELS
25
+ end
26
+
27
+ protected
28
+
29
+ def default_model
30
+ 'grok-2-image'
31
+ end
32
+
33
+ def env_key_name
34
+ 'XAI_API_KEY'
35
+ end
36
+
37
+ private
38
+
39
+ def build_request_body(prompt, opts)
40
+ {
41
+ model: model,
42
+ prompt: prompt,
43
+ n: opts[:n] || 1,
44
+ response_format: opts[:response_format] || 'url'
45
+ }.merge(opts.except(:n, :response_format))
46
+ end
47
+
48
+ def parse_generate_response(body)
49
+ images = body['data']&.map do |img|
50
+ {
51
+ url: img['url'],
52
+ base64: img['b64_json']
53
+ }.compact
54
+ end
55
+
56
+ {
57
+ images: images || [],
58
+ created: body['created']
59
+ }
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Imago
4
+ VERSION = '0.1.1'
5
+ end
data/lib/imago.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ require_relative 'imago/version'
7
+ require_relative 'imago/errors'
8
+ require_relative 'imago/providers/base'
9
+ require_relative 'imago/providers/openai'
10
+ require_relative 'imago/providers/gemini'
11
+ require_relative 'imago/providers/xai'
12
+ require_relative 'imago/client'
13
+
14
+ module Imago
15
+ class << self
16
+ def new(provider:, model: nil, api_key: nil)
17
+ Client.new(provider: provider, model: model, api_key: api_key)
18
+ end
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: imago
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Your Name
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: faraday-multipart
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.0'
40
+ description: Imago provides a simple, unified API to generate images using various
41
+ AI providers including OpenAI (DALL-E), Google Gemini, and xAI (Grok).
42
+ email:
43
+ - your.email@example.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".rubocop.yml"
49
+ - ".ruby-version"
50
+ - README.md
51
+ - Rakefile
52
+ - imago.gemspec
53
+ - lib/imago.rb
54
+ - lib/imago/client.rb
55
+ - lib/imago/errors.rb
56
+ - lib/imago/providers/base.rb
57
+ - lib/imago/providers/gemini.rb
58
+ - lib/imago/providers/openai.rb
59
+ - lib/imago/providers/xai.rb
60
+ - lib/imago/version.rb
61
+ homepage: https://github.com/example/imago
62
+ licenses:
63
+ - MIT
64
+ metadata:
65
+ homepage_uri: https://github.com/example/imago
66
+ source_code_uri: https://github.com/example/imago
67
+ changelog_uri: https://github.com/example/imago/blob/main/CHANGELOG.md
68
+ rubygems_mfa_required: 'true'
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 3.0.0
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubygems_version: 4.0.3
84
+ specification_version: 4
85
+ summary: A unified Ruby interface for multiple image generation AI providers
86
+ test_files: []