aigifmaker 0.1.0

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: c93c6ee3782f75742a19707c49bfe0988a265330640750624fa23603b7851ea5
4
+ data.tar.gz: cf2f3f1c6c24ce99d569f081183b37bbdfb095eb27ed8f049f372a117d63ec5b
5
+ SHA512:
6
+ metadata.gz: 59d9728075bd774d504deb46ee3aca29c15f1be907d37404bbf4239bd6dc7dd8aeac7937ad47ba1b7099c3aeb7f99882d0e51da72f3f201a93e42d28d9b324ab
7
+ data.tar.gz: dea93c1b9b94aeb4017f8da901d704ea513478c4e35901babd7d1d9403dea9e281097e948473c3d80e0a0c42a0ac4eb66f6da7b903c65efdd4ae8538d4adb03e
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AI GIF Maker (https://aigifmaker.ai)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # aigifmaker
2
+
3
+ Turn text into animated GIFs with AI GIF Maker. Native GIF generation — no video conversion. Type what you want and download your GIF in about a minute.
4
+
5
+ This is the official Ruby client for [AI GIF Maker](https://aigifmaker.ai/?utm_source=rubygems&utm_medium=package). One call sends your prompt, waits for the GIF and returns its URL.
6
+
7
+ ```bash
8
+ gem install aigifmaker
9
+ ```
10
+
11
+ ```ruby
12
+ require "aigifmaker"
13
+
14
+ url = Aigifmaker.generate("a corgi in sunglasses dancing on a beach, looping")
15
+ puts url # the finished GIF
16
+ ```
17
+
18
+ Standard library only (`net/http`, `json`), no dependencies. Ruby 2.6+.
19
+
20
+ ## API key
21
+
22
+ Create a key at https://aigifmaker.ai/settings/apikeys, then pass it as `api_key:` or export it:
23
+
24
+ ```bash
25
+ export AIGIFMAKER_API_KEY=sk-...
26
+ ```
27
+
28
+ Each GIF costs 1 credit on your AI GIF Maker account, the same as on the website. New accounts get one free GIF (it carries a small aigifmaker.ai badge). A GIF that fails to generate gives its credit back. Credit packs are on the [pricing](https://aigifmaker.ai/pricing?utm_source=rubygems&utm_medium=package) page.
29
+
30
+ ```ruby
31
+ puts Aigifmaker.credits # remaining credits, free to call
32
+ ```
33
+
34
+ ## Client
35
+
36
+ ```ruby
37
+ gif = Aigifmaker::Client.new("sk-...", timeout: 300) # timeout in seconds, 5 minutes by default
38
+ url = gif.generate("a tiny dragon sneezing a puff of glitter")
39
+ ```
40
+
41
+ ## Submit now, collect later
42
+
43
+ ```ruby
44
+ task_id = gif.submit("happy birthday text bouncing in rainbow letters")
45
+ puts gif.status(task_id)["status"] # pending | processing | success | failed
46
+ url = gif.wait(task_id) # polls every 3 seconds
47
+ ```
48
+
49
+ A run from an account that has not bought credits yet may wait in a short queue first (`"queued" => true` while `status` stays `processing`). That is normal; `generate` and `wait` keep polling.
50
+
51
+ ## Errors worth catching
52
+
53
+ Each failure is its own subclass of `Aigifmaker::Error`:
54
+
55
+ - `Aigifmaker::AuthError`: no key, or the key is wrong or deleted
56
+ - `Aigifmaker::QuotaError`: the account is out of credits
57
+ - `Aigifmaker::RejectedError`: the content filter refused the prompt, or a cooldown is active; reword it
58
+ - `Aigifmaker::GenerationFailed`: the run was accepted but failed; the message says why
59
+ - `Aigifmaker::TimeoutError`: still running when the timeout passed; the GIF may finish later in your history
60
+
61
+ Any other refusal raises `Aigifmaker::Error` with the server's message.
62
+
63
+ ## Tests
64
+
65
+ ```bash
66
+ ruby test/test_aigifmaker.rb # mocked, offline
67
+ ruby test/smoke_live.rb # two free live checks, no generation
68
+ ```
69
+
70
+ MIT licensed. Questions: support@aigifmaker.ai
@@ -0,0 +1,3 @@
1
+ module Aigifmaker
2
+ VERSION = "0.1.0"
3
+ end
data/lib/aigifmaker.rb ADDED
@@ -0,0 +1,179 @@
1
+ # Official Ruby SDK for AI GIF Maker (https://aigifmaker.ai): turn text into
2
+ # animated GIFs.
3
+ #
4
+ # require "aigifmaker"
5
+ # url = Aigifmaker.generate("a corgi in sunglasses dancing on a beach")
6
+ #
7
+ # Create a key at https://aigifmaker.ai/settings/apikeys and pass it as
8
+ # api_key: or set AIGIFMAKER_API_KEY. Each GIF costs 1 credit on your
9
+ # AI GIF Maker account, the same as on the website.
10
+ require "json"
11
+ require "net/http"
12
+ require "uri"
13
+ require_relative "aigifmaker/version"
14
+
15
+ module Aigifmaker
16
+ BASE_URL = "https://aigifmaker.ai".freeze
17
+ KEYS_URL = "https://aigifmaker.ai/settings/apikeys".freeze
18
+ PRICING_URL = "https://aigifmaker.ai/pricing".freeze
19
+ DEFAULT_TIMEOUT = 300
20
+ POLL_EVERY = 3
21
+
22
+ # Base of every error this gem raises. #code is the JSON code when there was one.
23
+ class Error < StandardError
24
+ attr_reader :code
25
+ def initialize(msg = nil, code: nil)
26
+ super(msg)
27
+ @code = code
28
+ end
29
+ end
30
+ # No API key, or the key is invalid or deleted.
31
+ class AuthError < Error; end
32
+ # The account is out of credits.
33
+ class QuotaError < Error; end
34
+ # The content filter refused the prompt, or a cooldown is active. Reword it.
35
+ class RejectedError < Error; end
36
+ # The GIF was accepted but the run ended as failed or canceled.
37
+ class GenerationFailed < Error; end
38
+ # The deadline passed; the GIF may still finish in your AI GIF Maker history.
39
+ class TimeoutError < Error; end
40
+
41
+ # Return data for code 0; otherwise raise the error that says what to do next.
42
+ # Every response is HTTP 200; the JSON code tells success from refusal.
43
+ def self.unwrap(http_status, env)
44
+ env = {} unless env.is_a?(Hash)
45
+ code = env["code"]
46
+ data = env["data"].is_a?(Hash) ? env["data"] : {}
47
+ if code == 0
48
+ raise AuthError.new("an API key is required; create one at #{KEYS_URL} and set AIGIFMAKER_API_KEY", code: code) if data["wall"]
49
+
50
+ return data
51
+ end
52
+ msg = (env["message"] || env["error"] || "HTTP #{http_status}").to_s
53
+ low = msg.downcase
54
+ c = code.is_a?(Integer) ? code : nil
55
+ raise AuthError.new(msg, code: c) if low.include?("invalid api key") || low.include?("no auth") || http_status == 401
56
+ raise QuotaError.new("#{msg}. Top up at #{PRICING_URL}", code: c) if low.include?("insufficient credits")
57
+ raise RejectedError.new(msg, code: c) if c && c != -1
58
+
59
+ raise Error.new(msg, code: c)
60
+ end
61
+
62
+ # A client bound to one API key. transport: is a callable (url, body, headers) -> [status, hash], for tests.
63
+ class Client
64
+ attr_accessor :poll_every, :timeout
65
+
66
+ def initialize(api_key = nil, base_url: BASE_URL, timeout: DEFAULT_TIMEOUT, poll_every: POLL_EVERY, transport: nil)
67
+ key = (api_key || ENV["AIGIFMAKER_API_KEY"]).to_s.strip
68
+ @key = key.empty? ? nil : key
69
+ @base = base_url.chomp("/")
70
+ @timeout = timeout
71
+ @poll_every = poll_every
72
+ @transport = transport || method(:http)
73
+ end
74
+
75
+ # Start one GIF and return its task id without waiting.
76
+ def submit(prompt)
77
+ raise ArgumentError, "prompt is required" if prompt.to_s.strip.empty?
78
+
79
+ data = post("/api/ai/generate", {
80
+ "provider" => "openlux",
81
+ "mediaType" => "image",
82
+ "model" => "gif-maker-v1",
83
+ "scene" => "text-to-image",
84
+ "prompt" => prompt,
85
+ "options" => { "output_format" => "gif" }
86
+ })
87
+ raise Error, "the service returned no task id" unless data["id"]
88
+
89
+ data["id"].to_s
90
+ end
91
+
92
+ # Return the task record: "status" is pending, processing, success or failed;
93
+ # "images"[0] holds the GIF URL when it succeeds.
94
+ def status(task_id)
95
+ post("/api/ai/query", { "taskId" => task_id })
96
+ end
97
+
98
+ # Poll a task every 3 seconds until it finishes and return the GIF URL.
99
+ def wait(task_id, timeout: nil)
100
+ limit = timeout || @timeout
101
+ deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + limit
102
+ loop do
103
+ d = begin
104
+ status(task_id)
105
+ rescue SystemCallError, SocketError, Net::OpenTimeout, Net::ReadTimeout
106
+ {} # a dropped poll is not a failed generation
107
+ end
108
+ state = d["status"].to_s.downcase
109
+ images = d["images"] || []
110
+ return images[0].to_s if state == "success" && !images.empty?
111
+
112
+ if %w[failed canceled].include?(state)
113
+ msg = (d["errorMessage"] || "the GIF #{state}").to_s
114
+ raise RejectedError, msg if d["failureKind"] == "moderation"
115
+
116
+ raise GenerationFailed, msg
117
+ end
118
+ if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline
119
+ raise TimeoutError, "still running after #{limit}s; task #{task_id} may finish later in your AI GIF Maker history"
120
+ end
121
+
122
+ sleep @poll_every
123
+ end
124
+ end
125
+
126
+ # Generate one animated GIF and return its URL.
127
+ def generate(prompt)
128
+ wait(submit(prompt))
129
+ end
130
+
131
+ # Remaining credits on the account. Free to call.
132
+ def credits
133
+ post("/api/user/get-user-credits", nil)["remainingCredits"].to_i
134
+ end
135
+
136
+ private
137
+
138
+ def post(path, body)
139
+ headers = { "Content-Type" => "application/json", "User-Agent" => "aigifmaker-ruby/#{VERSION}" }
140
+ headers["Authorization"] = "Bearer #{@key}" if @key
141
+ st, env = @transport.call("#{@base}#{path}", body, headers)
142
+ Aigifmaker.unwrap(st, env)
143
+ end
144
+
145
+ def http(url, body, headers)
146
+ uri = URI(url)
147
+ req = Net::HTTP::Post.new(uri)
148
+ headers.each { |k, v| req[k] = v }
149
+ req.body = JSON.generate(body || {})
150
+ res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https", read_timeout: 60) { |h| h.request(req) }
151
+ parsed = begin
152
+ JSON.parse(res.body.to_s.empty? ? "{}" : res.body)
153
+ rescue JSON::ParserError
154
+ { "code" => -1, "message" => res.body.to_s[0, 200] }
155
+ end
156
+ [res.code.to_i, parsed.is_a?(Hash) ? parsed : { "code" => -1, "message" => parsed.to_s }]
157
+ end
158
+ end
159
+
160
+ # Generate one animated GIF and return its URL.
161
+ def self.generate(prompt, api_key: nil, **opts)
162
+ Client.new(api_key, **opts).generate(prompt)
163
+ end
164
+
165
+ # Start one GIF and return its task id.
166
+ def self.submit(prompt, api_key: nil, **opts)
167
+ Client.new(api_key, **opts).submit(prompt)
168
+ end
169
+
170
+ # Return the task record for task_id.
171
+ def self.status(task_id, api_key: nil, **opts)
172
+ Client.new(api_key, **opts).status(task_id)
173
+ end
174
+
175
+ # Remaining credits on the account.
176
+ def self.credits(api_key: nil, **opts)
177
+ Client.new(api_key, **opts).credits
178
+ end
179
+ end
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aigifmaker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - hanshs474
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-11-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Turn text into animated GIFs with AI GIF Maker. Native GIF generation
14
+ — no video conversion. Type what you want and download your GIF in about a minute.
15
+ email:
16
+ - support@aigifmaker.ai
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE
22
+ - README.md
23
+ - lib/aigifmaker.rb
24
+ - lib/aigifmaker/version.rb
25
+ homepage: https://aigifmaker.ai/?utm_source=rubygems&utm_medium=package
26
+ licenses:
27
+ - MIT
28
+ metadata:
29
+ homepage_uri: https://aigifmaker.ai/?utm_source=rubygems&utm_medium=package
30
+ source_code_uri: https://github.com/hanshs474/aigifmaker-rb
31
+ bug_tracker_uri: https://github.com/hanshs474/aigifmaker-rb/issues
32
+ rubygems_mfa_required: 'false'
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '2.6'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubygems_version: 3.0.3.1
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: 'Official SDK for AI GIF Maker (aigifmaker.ai): turn text into animated GIFs.'
52
+ test_files: []