stability_ai 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea1e45d07d4a8dddedcfc4f8e433e51f243022f0e55cb96b50448951e7dd6a64
4
- data.tar.gz: ea94f24e054cece698cb4616e3d3dd8495afba6eb2176a71082412887a52648a
3
+ metadata.gz: a74f16129b63c646329f0a2f3b35048a4da347a1e6f7c5e4850e1ce4d6739cc9
4
+ data.tar.gz: 74b7aae52e67b6aa8c9225c68d42f68e84903438e8037d61ad09370a78a89021
5
5
  SHA512:
6
- metadata.gz: 3415165709e357e8d1d291f21a62f7340714a3187eabd2ffd231754364961d559d04e92ce7c34b0d6b7246e9c575b9ec3e9f14f105aac5bb1039e23703b76505
7
- data.tar.gz: d2452910befdddf078445b45595e6b1961669a6d6febb705ec3f5ca10d81392ab2229431acf6972df6161f94dd7386f8082a5d77ebc6623f27df96f216cc8e27
6
+ metadata.gz: 33772dce8b02317032bc6292d632101f03744e50e64bd3a59f21cb4e02540643455e2c06309fc5d30be60257b4cc53bdda31b6c87742f8e1b4c99d09b0c88f2e
7
+ data.tar.gz: d098914d24d40e6e35ad6f58b41a3240ed08553248c172a80bd665bdb73f9f37177cf9b4c75053cfc63324ae9076375a7a0deb795e5214b0312201416325eed5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2023-04-20
3
+ ## [0.1.0] - 2023-04-22
4
4
 
5
5
  - Initial release
6
+
7
+ ## [0.1.1] - 2023-04-22
8
+
9
+ - Hotfix
10
+
11
+ ## [0.1.2] - 2023-04-22
12
+
13
+ - Hotfix 2: removed remaining `require byebug`
data/Gemfile CHANGED
@@ -10,3 +10,9 @@ gem "rake", "~> 13.0"
10
10
  gem "rspec", "~> 3.0"
11
11
 
12
12
  gem "rubocop", "~> 1.21"
13
+ gem "httparty", "~> 0.20.0"
14
+ gem "rmagick", "~> 5.2.0"
15
+
16
+ group :development do
17
+ gem "pry-byebug"
18
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,79 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ stability_ai (0.1.2)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ byebug (11.1.3)
11
+ coderay (1.1.3)
12
+ diff-lcs (1.5.0)
13
+ httparty (0.20.0)
14
+ mime-types (~> 3.0)
15
+ multi_xml (>= 0.5.2)
16
+ json (2.6.3)
17
+ method_source (1.0.0)
18
+ mime-types (3.4.1)
19
+ mime-types-data (~> 3.2015)
20
+ mime-types-data (3.2023.0218.1)
21
+ multi_xml (0.6.0)
22
+ parallel (1.23.0)
23
+ parser (3.2.2.0)
24
+ ast (~> 2.4.1)
25
+ pkg-config (1.5.1)
26
+ pry (0.14.2)
27
+ coderay (~> 1.1)
28
+ method_source (~> 1.0)
29
+ pry-byebug (3.10.1)
30
+ byebug (~> 11.0)
31
+ pry (>= 0.13, < 0.15)
32
+ rainbow (3.1.1)
33
+ rake (13.0.6)
34
+ regexp_parser (2.8.0)
35
+ rexml (3.2.5)
36
+ rmagick (5.2.0)
37
+ pkg-config (~> 1.4)
38
+ rspec (3.12.0)
39
+ rspec-core (~> 3.12.0)
40
+ rspec-expectations (~> 3.12.0)
41
+ rspec-mocks (~> 3.12.0)
42
+ rspec-core (3.12.2)
43
+ rspec-support (~> 3.12.0)
44
+ rspec-expectations (3.12.3)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.12.0)
47
+ rspec-mocks (3.12.5)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.12.0)
50
+ rspec-support (3.12.0)
51
+ rubocop (1.50.2)
52
+ json (~> 2.3)
53
+ parallel (~> 1.10)
54
+ parser (>= 3.2.0.0)
55
+ rainbow (>= 2.2.2, < 4.0)
56
+ regexp_parser (>= 1.8, < 3.0)
57
+ rexml (>= 3.2.5, < 4.0)
58
+ rubocop-ast (>= 1.28.0, < 2.0)
59
+ ruby-progressbar (~> 1.7)
60
+ unicode-display_width (>= 2.4.0, < 3.0)
61
+ rubocop-ast (1.28.0)
62
+ parser (>= 3.2.1.0)
63
+ ruby-progressbar (1.13.0)
64
+ unicode-display_width (2.4.2)
65
+
66
+ PLATFORMS
67
+ x86_64-darwin-22
68
+
69
+ DEPENDENCIES
70
+ httparty (~> 0.20.0)
71
+ pry-byebug
72
+ rake (~> 13.0)
73
+ rmagick (~> 5.2.0)
74
+ rspec (~> 3.0)
75
+ rubocop (~> 1.21)
76
+ stability_ai!
77
+
78
+ BUNDLED WITH
79
+ 2.4.12
data/README.md CHANGED
@@ -1,39 +1,94 @@
1
- # StabilityAi
1
+ # StabilityAI
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ StabilityAI is a Ruby gem that simplifies interactions with the Stability AI API. It supports image generation, image-to-image manipulation, upscaling, and masking.
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/stability_ai`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ ## Demo
6
+
7
+ I made this `gem` part of a personal project: [ciel.chat](https://ciel.chat) - an AI supercharged WhatsApp bot, using ChatGPT, Bard, StableDiffusion, Dalle, GoogleSpeech, ElevenLabs.
8
+ You can try it there for free ✌️
9
+
10
+ ## Disclaimer
11
+
12
+ It's my first gem ever. There are plenty of room for improvements there - feel free to contribute!
6
13
 
7
14
  ## Installation
8
15
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'stability_ai'
20
+ ```
10
21
 
11
- Install the gem and add to the application's Gemfile by executing:
22
+ And then execute:
12
23
 
13
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
24
+ ```ruby
25
+ $ bundle install
26
+ ```
14
27
 
15
- If bundler is not being used to manage dependencies, install the gem by executing:
28
+ Or install it yourself as:
16
29
 
17
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
30
+ ```ruby
31
+ gem install stability_ai
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ Create an initializer in your Rails project or any Ruby application (e.g., `config/initializers/stability_ai.rb`) to configure your API keys and credentials:
37
+
38
+ ```ruby
39
+ StabilityAI.configure do |config|
40
+ config.stability_api_key = 'your_stability_api_key'
41
+ config.path_prefix = './'
42
+ end
43
+ ```
18
44
 
19
45
  ## Usage
20
46
 
21
- TODO: Write usage instructions here
47
+ Here's an example of how to use the gem with the Stability AI API:
48
+ Check [StabilityAI API](https://api.stability.ai/docs) for all the options available. If there are not passed in the `options` hash, the default value is used.
22
49
 
23
- ## Development
50
+ ```ruby
51
+ require 'stability_ai'
24
52
 
25
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
26
53
 
27
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
54
+ client = StabilityAI::Client.new
28
55
 
29
- ## Contributing
56
+ # Text to image
57
+ text_to_image_response = client.text_to_image('engine_id', text_prompts: [{ text: 'A lighthouse on a cliff' }])
58
+ uri_image_1 = text_to_image_response.image_uris.first # -> <img src="#{uri_image_1}"/> or image_tag(uri_image_1)
59
+ text_to_image_response.save_images('your_image_name_prefix') # -> returns ["your_image_name_prefix_1.png", "your_image_name_prefix_2.png", ...]
30
60
 
31
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/stability_ai. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/stability_ai/blob/master/CODE_OF_CONDUCT.md).
61
+ # Image to image
32
62
 
33
- ## License
63
+ options = {
64
+ text_prompts: [
65
+ {
66
+ text: "Snow",
67
+ }
68
+ ],
69
+ image_strength: 0.35, # Default: 0.35 How much influence the init_image has on the diffusion process. Values close to 1 will yield images very similar to the init_image while values close to 0 will yield images wildly different than the init_image
70
+ cfg_scale: 7, # DEFAULT: [0..35] How strictly the diffusion process adheres to the prompt text (higher values keep your image closer to your prompt),
71
+ # clip_guidance_preset: "FAST_BLUE", # DEFAULT: NONE, WTF IS THAT?? FAST_BLUE FAST_GREEN NONE SIMPLE SLOW SLOWER SLOWEST
72
+ # sampler: "DDIM", # DEFAULT: Automatically choose by StableAI. DDIM DDPM K_DPMPP_2M K_DPMPP_2S_ANCESTRAL K_DPM_2 K_DPM_2_ANCESTRAL K_EULER K_EULER_ANCESTRAL K_HEUN K_LMS
73
+ sytle_preset: "neon-punk", # check
74
+ }
75
+ response = client.image_to_image(image_path: image_path, )
76
+
77
+ # Image to image upscale
78
+ response = client.image_to_image_upscale(engine_id: "esrgan-v1-x2plus", image_path: image_path, options: { width: 1024 })
79
+ response = client.image_to_image_upscale(image_path: image_path, use_maximum_resolution: true) # default engine: esrgan-v1-x2plus / use `use_maximum_resolution: true` is to use 2048px
80
+ response = client.image_to_image_upscale(image_binary: image_binary, )
34
81
 
35
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
82
+ # Image to image masking
83
+ # TODO
84
+ ```
36
85
 
37
- ## Code of Conduct
86
+ Replace `'engine_id'` with the appropriate engine ID for each method call.
87
+
88
+ ## Contributing
89
+
90
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mael-ha/stability_ai.
91
+
92
+ ## License
38
93
 
39
- Everyone interacting in the StabilityAi project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/stability_ai/blob/master/CODE_OF_CONDUCT.md).
94
+ The gem is available as open source under the terms of the MIT License.
@@ -0,0 +1,16 @@
1
+ module StabilityAI
2
+ module API
3
+ module Engines
4
+ def engines_list
5
+ response = self.class.get('/v1/engines/list')
6
+ if response.code == 200
7
+ StabilityAI::Response::EnginesListResponse.new(response)
8
+ else
9
+ error_data = response.parsed_response
10
+ raise StabilityAI::StabilityAIError.new(response.code, error_data["id"], error_data["name"], error_data["message"])
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,176 @@
1
+ require "uri"
2
+ require "rmagick"
3
+
4
+ module StabilityAI
5
+ module API
6
+ module Generation
7
+ def text_to_image(engine_id: nil, options: {})
8
+ response = self.class.post("/v1/generation/#{get_engine_id(engine_id)}/text-to-image", body: options.to_json,
9
+ headers: { "Content-Type" => "application/json" })
10
+ handle_response(response)
11
+ end
12
+
13
+ def image_to_image(engine_id: nil, image_binary: nil, image_base64: nil, image_path: nil, options: {})
14
+ raise "No image file path provided." unless image_path || image_binary || image_base64
15
+ raise "No prompt provided." if options[:text_prompts].nil?
16
+
17
+ image_payload = create_payload(image_binary, image_base64, image_path)
18
+ image = convert_and_resize_image(image_payload)
19
+ temp_file = create_temp_file_from_image(image)
20
+ form_data = set_form_data(image:, endpoint: :image_to_image, options:, temp_file:)
21
+
22
+ default_weight = options[:text_prompts].count > 1 ? (1 / options[:text_prompts].count).round(2) : 1
23
+ options[:text_prompts].each_with_index do |text_prompt, i|
24
+ form_data.merge!("text_prompts[#{i}][text]" => text_prompt[:text]) unless text_prompt[:text].nil?
25
+ form_data.merge!("text_prompts[#{i}][weight]" => text_prompt[:weight] || default_weight) unless text_prompt[:weight].nil?
26
+ end
27
+
28
+ headers = { "Content-Type" => "multipart/form-data" }
29
+ response = self.class.post("/v1/generation/#{get_engine_id(engine_id)}/image-to-image",
30
+ headers: headers, multipart: true, body: form_data)
31
+ handle_response(response)
32
+ ensure
33
+ if temp_file
34
+ temp_file.close
35
+ temp_file.unlink
36
+ end
37
+ end
38
+
39
+ def image_to_image_upscale(engine_id: "esrgan-v1-x2plus", image_binary: nil, image_base64: nil, image_path: nil, use_maximum_resolution: false, options: {})
40
+ raise "No image file path provided." unless image_path || image_binary || image_base64
41
+
42
+ image_payload = create_payload(image_binary, image_base64, image_path)
43
+ image = convert_and_resize_image(image_payload)
44
+ temp_file = create_temp_file_from_image(image)
45
+ form_data = set_form_data(image:, endpoint: :image_to_image_upscale, options: options, temp_file:)
46
+
47
+ headers = { "Content-Type" => "multipart/form-data" }
48
+ response = self.class.post("/v1/generation/#{engine_id}/image-to-image/upscale", headers: headers, multipart: true, body: form_data)
49
+ handle_response(response)
50
+ ensure
51
+ if temp_file
52
+ temp_file.close
53
+ temp_file.unlink
54
+ end
55
+ end
56
+
57
+ # def text_to_animation(engine_id: nil, options: {})
58
+ # response = self.class.post("/v1/generation/#{get_engine_id(engine_id)}/text-to-animation", body: options.to_json,
59
+ # headers: { "Content-Type" => "application/json" })
60
+ # handle_response(response)
61
+ # end
62
+
63
+ private
64
+
65
+ def get_engine_id(engine_id)
66
+ engine_id || StabilityAI.configuration.default_engine_id
67
+ end
68
+
69
+ def handle_response(response)
70
+ if response.code == 200
71
+ StabilityAI::Response::ImageResponse.new(response)
72
+ else
73
+ error_data = response.parsed_response
74
+ raise StabilityAI::StabilityAIError.new(response.code, error_data["id"], error_data["name"],
75
+ error_data["message"])
76
+ end
77
+ end
78
+
79
+ def create_payload(image_binary, image_base64, image_path)
80
+ if image_binary
81
+ StringIO.new(image_binary).read
82
+ elsif image_base64
83
+ StringIO.new(Base64.decode64(image_base64)).read
84
+ elsif image_path
85
+ File.read(File.open(image_path, 'rb'))
86
+ else
87
+ raise "No image binary, base64, or file path provided."
88
+ end
89
+ end
90
+
91
+ def create_temp_file_from_image(image)
92
+ temp_file = Tempfile.new(['image', '.png'])
93
+ temp_file.binmode
94
+ image.format = 'PNG' # Set the format explicitly before calling to_blob
95
+ temp_file.write(image.to_blob)
96
+ temp_file.flush
97
+ temp_file.rewind
98
+ temp_file
99
+ end
100
+
101
+ def get_image_dimensions(image)
102
+ [image.columns, image.rows]
103
+ end
104
+
105
+ def set_max_dimension(image, options, use_maximum_resolution)
106
+ if use_maximum_resolution
107
+ width, height = get_image_dimensions(image)
108
+ (width > height) ? { 'width' => 2048 } : { 'height' => 2048 }
109
+ else
110
+ case
111
+ when !options[:width].nil?
112
+ { 'width' => options[:width] }
113
+ when !options[:height].nil?
114
+ { 'height' => options[:height] }
115
+ else
116
+ nil
117
+ end
118
+ end
119
+ end
120
+
121
+ def set_form_data(image:, endpoint:, options:, temp_file:, use_maximum_resolution: true)
122
+ raise "No image file provided." unless temp_file
123
+
124
+ form_data = {}
125
+ case endpoint
126
+ when :image_to_image
127
+ form_data.merge!("init_image" => temp_file)
128
+ parameters = %w[image_strength, init_image_mode, cfg_scale, clip_guidance_preset, samples, steps]
129
+ parameters.each do |parameter|
130
+ next if options[parameter.to_sym].nil?
131
+ form_data.merge!(parameter => options[parameter.to_sym])
132
+ end
133
+ form_data
134
+ when :image_to_image_upscale
135
+ form_data.merge!("image" => temp_file)
136
+ max_dimension = set_max_dimension(image, options, use_maximum_resolution)
137
+ form_data.merge!(max_dimension) if max_dimension
138
+ end
139
+ end
140
+
141
+ def get_new_dimensions(width, height, step = 64)
142
+ new_width = (width / step) * step
143
+ new_height = (height / step) * step
144
+ [new_width, new_height]
145
+ end
146
+
147
+ def convert_and_resize_image(image_payload)
148
+ # Convert the input image to PNG format if it's a JPG or JPEG file
149
+ image = Magick::Image.from_blob(image_payload).first
150
+ image.format = 'PNG' if %w[JPG JPEG].include?(image.format)
151
+
152
+ if image.columns % 64 != 0 || image.rows % 64 != 0
153
+ # Calculate new dimensions
154
+ new_width, new_height = get_new_dimensions(image.columns, image.rows)
155
+
156
+ # Resize the image while maintaining aspect ratio
157
+ image.change_geometry("#{new_width}x#{new_height}") do |cols, rows, img|
158
+ img.resize!(cols, rows)
159
+ end
160
+
161
+ # Find the nearest multiples of 64 for both width and height
162
+ width_multiple = (image.columns / 64.0).floor * 64
163
+ height_multiple = (image.rows / 64.0).floor * 64
164
+
165
+ # Calculate new offsets for cropping
166
+ x_offset = (image.columns - width_multiple) / 2
167
+ y_offset = (image.rows - height_multiple) / 2
168
+
169
+ # Crop the centered part to ensure dimensions are multiples of 64
170
+ image.crop!(x_offset, y_offset, width_multiple, height_multiple)
171
+ end
172
+ image
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,16 @@
1
+ module StabilityAI
2
+ module API
3
+ module User
4
+ def balance
5
+ response = self.class.get('/v1/user/balance')
6
+ if response.code == 200
7
+ StabilityAI::Response::UserResponse.new(response)
8
+ else
9
+ error_data = response.parsed_response
10
+ raise StabilityAI::StabilityAIError.new(response.code, error_data["id"], error_data["name"], error_data["message"])
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,4 @@
1
+ module StabilityAI
2
+ module API
3
+ end
4
+ end
@@ -0,0 +1,39 @@
1
+ module StabilityAI
2
+ class Client
3
+ include HTTParty
4
+ include StabilityAI::API::User
5
+ include StabilityAI::API::Engines
6
+ include StabilityAI::API::Generation
7
+
8
+ base_uri "https://api.stability.ai"
9
+ format :json
10
+
11
+ def initialize(api_key = nil)
12
+ @api_key = api_key || StabilityAI.configuration.stability_api_key || ENV["STABILITY_API_KEY"]
13
+ raise ArgumentError, "Missing Stability API key." unless @api_key
14
+
15
+ self.class.default_options.merge!(
16
+ headers: {
17
+ "Authorization" => "Bearer #{@api_key}",
18
+ "Content-Type" => "application/json",
19
+ "Accept" => "application/json"
20
+ }
21
+ )
22
+
23
+ set_default_engine_id
24
+ end
25
+
26
+ private
27
+
28
+ def set_default_engine_id
29
+ # Setting stable-diffusion-xl as default engine
30
+ return if StabilityAI.configuration.default_engine_id
31
+
32
+ engines_list_response = engines_list
33
+ engines = engines_list_response.engines
34
+
35
+ default_engine = engines.find { |engine| engine.id.include?("stable-diffusion-xl") }
36
+ StabilityAI.configuration.default_engine_id = default_engine.id if default_engine
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ module StabilityAI
2
+ class Configuration
3
+ attr_accessor :stability_api_key, :default_engine_id, :path_prefix
4
+
5
+ def initialize
6
+ @stability_api_key = nil
7
+ @default_engine_id = nil
8
+ @path_prefix = './'
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,16 @@
1
+ module StabilityAI
2
+ module Helpers
3
+ class ImageHelper
4
+ def self.save_artifacts(artifacts, prefix = "output")
5
+ artifacts.each_with_index do |artifact, i|
6
+ save_base64_image("#{prefix}_#{i}.png", artifact.base64)
7
+ end
8
+ end
9
+
10
+ def self.save_base64_image(file_path, base64_image)
11
+ File.binwrite(file_path, Base64.decode64(base64_image))
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,14 @@
1
+ module StabilityAI
2
+ module Response
3
+ class BaseResponse
4
+ attr_reader :raw_response, :http_status
5
+
6
+ def initialize(raw_response)
7
+ @raw_response = raw_response
8
+ @parsed_response = @raw_response.parsed_response
9
+ @http_status = raw_response.code
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,9 @@
1
+ module StabilityAI
2
+ module Response
3
+ class EnginesListResponse < BaseResponse
4
+ def engines
5
+ @parsed_response.map { |engine| OpenStruct.new(engine) }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ module StabilityAI
2
+ module Response
3
+ class ImageResponse < BaseResponse
4
+ attr_reader :artifacts
5
+
6
+ def initialize(response)
7
+ super(response)
8
+ @artifacts = response.parsed_response["artifacts"]
9
+ convert_artifacts_to_openstruct
10
+ end
11
+
12
+ def convert_artifacts_to_openstruct
13
+ @artifacts.map! do |artifact|
14
+ image_binary_data = Base64.decode64(artifact["base64"])
15
+ artifact["image_binary"] = image_binary_data
16
+ artifact.delete("base64")
17
+ OpenStruct.new(artifact)
18
+ end
19
+ end
20
+
21
+ def save_images(filename_prefix: nil)
22
+ filename_prefix = Time.now.utc.strftime("%Y%m%d%H%M%S") if filename_prefix.nil?
23
+ downloaded_images = []
24
+ path_prefix = StabilityAI.configuration.path_prefix
25
+ @artifacts.each_with_index do |artifact, i|
26
+ image_name = "#{filename_prefix}_#{i}.png"
27
+ image_path = path_prefix + image_name
28
+ File.binwrite(image_path, artifact["image_binary"])
29
+ downloaded_images << {
30
+ file_name: image_name,
31
+ seed: artifact["seed"],
32
+ finish_reason: artifact["finishReason"],
33
+ }
34
+ end
35
+ downloaded_images
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,10 @@
1
+ module StabilityAI
2
+ module Response
3
+ class UserResponse < BaseResponse
4
+ def credits
5
+ @parsed_response['credits']
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,14 @@
1
+ module StabilityAI
2
+ class StabilityAIError < StandardError
3
+ attr_reader :id, :name, :message
4
+
5
+ def initialize(code, id, name, message)
6
+ @code = code
7
+ @id = id
8
+ @name = name
9
+ @message= message
10
+ super("#{code}# #{name}: #{message} (ID: #{id})")
11
+ end
12
+ end
13
+ end
14
+
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module StabilityAi
4
- VERSION = "0.1.0"
3
+ module StabilityAI
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/stability_ai.rb CHANGED
@@ -1,8 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "httparty"
4
+ require "dotenv/load"
5
+ require "base64"
6
+ require "uri"
3
7
  require_relative "stability_ai/version"
8
+ require_relative "stability_ai/api"
9
+ require_relative "stability_ai/api/user"
10
+ require_relative "stability_ai/api/engines"
11
+ require_relative "stability_ai/api/generation"
12
+ require_relative "stability_ai/client"
13
+ require_relative "stability_ai/response/base_response"
14
+ require_relative "stability_ai/response/user_response"
15
+ require_relative "stability_ai/response/engines_response"
16
+ require_relative "stability_ai/response/image_response"
17
+ require_relative "stability_ai/stability_ai_error"
18
+ require_relative "stability_ai/configuration"
19
+
20
+ module StabilityAI
21
+ class << self
22
+ attr_accessor :configuration
23
+ end
24
+
25
+ def self.configure
26
+ self.configuration ||= Configuration.new
27
+ yield(configuration)
28
+ end
4
29
 
5
- module StabilityAi
6
30
  class Error < StandardError; end
7
- # Your code goes here...
8
31
  end
data/stability_ai.gemspec CHANGED
@@ -4,7 +4,7 @@ require_relative "lib/stability_ai/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "stability_ai"
7
- spec.version = StabilityAi::VERSION
7
+ spec.version = StabilityAI::VERSION
8
8
  spec.authors = ["Maël Harnois"]
9
9
  spec.email = ["m@maelus.com"]
10
10
 
@@ -13,7 +13,6 @@ Gem::Specification.new do |spec|
13
13
  spec.license = "MIT"
14
14
  spec.required_ruby_version = ">= 2.6.0"
15
15
 
16
-
17
16
  spec.metadata["homepage_uri"] = spec.homepage
18
17
  spec.metadata["source_code_uri"] = "https://github.com/mael-ha/stability_ai"
19
18
  spec.metadata["changelog_uri"] = "https://github.com/mael-ha/stability_ai/blob/main/CHANGELOG.md"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stability_ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maël Harnois
@@ -22,10 +22,23 @@ files:
22
22
  - CHANGELOG.md
23
23
  - CODE_OF_CONDUCT.md
24
24
  - Gemfile
25
+ - Gemfile.lock
25
26
  - LICENSE.txt
26
27
  - README.md
27
28
  - Rakefile
28
29
  - lib/stability_ai.rb
30
+ - lib/stability_ai/api.rb
31
+ - lib/stability_ai/api/engines.rb
32
+ - lib/stability_ai/api/generation.rb
33
+ - lib/stability_ai/api/user.rb
34
+ - lib/stability_ai/client.rb
35
+ - lib/stability_ai/configuration.rb
36
+ - lib/stability_ai/helpers/image_helper.rb
37
+ - lib/stability_ai/response/base_response.rb
38
+ - lib/stability_ai/response/engines_response.rb
39
+ - lib/stability_ai/response/image_response.rb
40
+ - lib/stability_ai/response/user_response.rb
41
+ - lib/stability_ai/stability_ai_error.rb
29
42
  - lib/stability_ai/version.rb
30
43
  - sig/stability_ai.rbs
31
44
  - stability_ai.gemspec