rager 0.2.1 → 0.4.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 +4 -4
- data/README.md +1 -1
- data/lib/rager/chat/providers/openai.rb +72 -105
- data/lib/rager/chat.rb +1 -1
- data/lib/rager/config.rb +21 -5
- data/lib/rager/context.rb +48 -32
- data/lib/rager/embed/options.rb +0 -11
- data/lib/rager/embed/providers/openai.rb +5 -17
- data/lib/rager/embed.rb +1 -1
- data/lib/rager/errors/http_error.rb +2 -2
- data/lib/rager/errors/options_error.rb +1 -1
- data/lib/rager/http/response.rb +7 -0
- data/lib/rager/image_gen/options.rb +1 -11
- data/lib/rager/image_gen/output_format.rb +18 -0
- data/lib/rager/image_gen/providers/replicate.rb +16 -20
- data/lib/rager/image_gen.rb +1 -1
- data/lib/rager/mesh_gen/options.rb +0 -11
- data/lib/rager/mesh_gen/providers/replicate.rb +12 -18
- data/lib/rager/mesh_gen.rb +1 -1
- data/lib/rager/options.rb +5 -3
- data/lib/rager/rerank/options.rb +0 -11
- data/lib/rager/rerank/providers/cohere.rb +13 -27
- data/lib/rager/rerank.rb +1 -1
- data/lib/rager/result.rb +59 -52
- data/lib/rager/search/options.rb +0 -11
- data/lib/rager/search/providers/brave.rb +19 -36
- data/lib/rager/search.rb +1 -1
- data/lib/rager/template/options.rb +0 -9
- data/lib/rager/template.rb +1 -1
- data/lib/rager/types.rb +0 -1
- data/lib/rager/utils/http.rb +49 -0
- data/lib/rager/utils/replicate.rb +97 -0
- data/lib/rager/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5799720e30799c04913866e328e581ed4670f6008489a00d78b438306a6d72e3
|
4
|
+
data.tar.gz: 30c3b31026a2ddcc9436fdb0f911f98129ce471ab0deb2ffdb05fb567fb4d030
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42f1d694221214b2d098b5996d870fe02dd7704ffce9f2ca44c154e790c6713bf23f98fb649a2ff601f8ab7c3a45da9571bbfcd643628b8c72b64df792bb524c
|
7
|
+
data.tar.gz: d4440b82e846327792039b33d352320ed00a1c72ac93701e3bed56a9e9f3cacaea5d300fe8853eaf7b2cd93b6c0a2d440d59c6c486707035fd982b7827a01b1a
|
data/README.md
CHANGED
@@ -22,63 +22,50 @@ module Rager
|
|
22
22
|
api_key = options.api_key || ENV["OPENAI_API_KEY"]
|
23
23
|
raise Rager::Errors::MissingCredentialsError.new("OpenAI", "OPENAI_API_KEY") if api_key.nil?
|
24
24
|
|
25
|
-
url = options.url || ENV["OPENAI_URL"] || "https://api.openai.com/v1/chat/completions"
|
26
|
-
model = options.model || "gpt-4.1"
|
27
|
-
|
28
|
-
openai_messages = build_openai_messages(messages, options.history, options.system_prompt)
|
29
|
-
|
30
|
-
headers = {
|
31
|
-
"Content-Type" => "application/json"
|
32
|
-
}
|
33
|
-
headers["Authorization"] = "Bearer #{api_key}" if api_key
|
34
|
-
|
35
25
|
body = {
|
36
|
-
model: model,
|
37
|
-
messages:
|
38
|
-
}
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
26
|
+
model: options.model || "gpt-4.1",
|
27
|
+
messages: build_openai_messages(messages, options.history, options.system_prompt)
|
28
|
+
}.tap do |b|
|
29
|
+
b[:temperature] = options.temperature if options.temperature
|
30
|
+
b[:n] = options.n if options.n
|
31
|
+
b[:stream] = options.stream if options.stream
|
32
|
+
b[:seed] = options.seed if options.seed
|
33
|
+
|
34
|
+
if options.schema && options.schema_name
|
35
|
+
b[:response_format] = {
|
36
|
+
type: "json_schema",
|
37
|
+
json_schema: {
|
38
|
+
name: T.must(options.schema_name).downcase,
|
39
|
+
strict: true,
|
40
|
+
schema: Rager::Chat::Schema.dry_schema_to_json_schema(T.must(options.schema))
|
41
|
+
}
|
51
42
|
}
|
52
|
-
|
43
|
+
end
|
53
44
|
end
|
54
45
|
|
46
|
+
headers = {"Content-Type" => "application/json"}
|
47
|
+
headers["Authorization"] = "Bearer #{api_key}" if api_key
|
48
|
+
|
55
49
|
request = Rager::Http::Request.new(
|
56
50
|
verb: Rager::Http::Verb::Post,
|
57
|
-
url: url,
|
51
|
+
url: options.url || ENV["OPENAI_URL"] || "https://api.openai.com/v1/chat/completions",
|
58
52
|
headers: headers,
|
59
53
|
body: body.to_json
|
60
54
|
)
|
61
55
|
|
62
|
-
|
63
|
-
response = http_adapter.make_request(request)
|
56
|
+
response = Rager.config.http_adapter.make_request(request)
|
64
57
|
response_body = T.must(response.body)
|
65
58
|
|
66
|
-
if response.status != 200
|
67
|
-
raise Rager::Errors::HttpError.new(
|
68
|
-
http_adapter,
|
69
|
-
response.status,
|
70
|
-
T.cast(response_body, String)
|
71
|
-
)
|
72
|
-
end
|
59
|
+
raise Rager::Errors::HttpError.new(Rager.config.http_adapter, response.status, T.cast(response_body, String)) if response.status != 200
|
73
60
|
|
74
61
|
case response_body
|
75
|
-
when String
|
76
|
-
|
77
|
-
when Enumerator
|
78
|
-
create_message_delta_stream(response_body)
|
62
|
+
when String then handle_non_stream_body(response_body)
|
63
|
+
when Enumerator then handle_stream_body(response_body)
|
79
64
|
end
|
80
65
|
end
|
81
66
|
|
67
|
+
private
|
68
|
+
|
82
69
|
sig do
|
83
70
|
params(
|
84
71
|
messages: T::Array[Rager::Chat::Message],
|
@@ -90,94 +77,75 @@ module Rager
|
|
90
77
|
result = T.let([], OpenaiMessages)
|
91
78
|
|
92
79
|
if history.empty? && system_prompt && !system_prompt.empty?
|
93
|
-
result << {"role" => "system",
|
94
|
-
"content" => system_prompt}
|
80
|
+
result << {"role" => "system", "content" => system_prompt}
|
95
81
|
end
|
96
82
|
|
97
|
-
history.each do |
|
98
|
-
|
99
|
-
result << {"role" => role_str, "content" => msg.content}
|
100
|
-
end
|
101
|
-
|
102
|
-
messages.each do |message|
|
103
|
-
role_str = message.role.is_a?(String) ? message.role : message.role.serialize
|
83
|
+
(history + messages).each do |message|
|
84
|
+
role = message.role.is_a?(String) ? message.role : message.role.serialize
|
104
85
|
content = message.content
|
105
86
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
when Rager::Chat::MessageContentType::Text
|
113
|
-
{"type" => "text", "text" => item.content}
|
114
|
-
when Rager::Chat::MessageContentType::ImageUrl
|
115
|
-
{"type" => "image_url", "image_url" => {"url" => item.content}}
|
116
|
-
when Rager::Chat::MessageContentType::ImageBase64
|
117
|
-
image_type = T.must(item.image_type)
|
118
|
-
image_mime_type = case image_type
|
119
|
-
when Rager::Chat::MessageContentImageType::Jpeg then "image/jpeg"
|
120
|
-
when Rager::Chat::MessageContentImageType::Png then "image/png"
|
121
|
-
when Rager::Chat::MessageContentImageType::Webp then "image/webp"
|
122
|
-
end
|
123
|
-
data_uri = "data:#{image_mime_type};base64,#{item.content}"
|
124
|
-
{"type" => "image_url", "image_url" => {"url" => data_uri}}
|
125
|
-
end
|
126
|
-
end
|
127
|
-
result << {"role" => role_str, "content" => formatted_content}
|
87
|
+
case content
|
88
|
+
when String
|
89
|
+
result << {"role" => role, "content" => content}
|
90
|
+
when Array
|
91
|
+
formatted_content = content.map { |item| format_content_item(item) }
|
92
|
+
result << {"role" => role, "content" => formatted_content}
|
128
93
|
end
|
129
94
|
end
|
130
95
|
|
131
96
|
result
|
132
97
|
end
|
133
98
|
|
134
|
-
sig { params(
|
135
|
-
def
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
99
|
+
sig { params(item: Rager::Chat::MessageContent).returns(T::Hash[String, T.untyped]) }
|
100
|
+
def format_content_item(item)
|
101
|
+
case item.type
|
102
|
+
when Rager::Chat::MessageContentType::Text
|
103
|
+
{"type" => "text", "text" => item.content}
|
104
|
+
when Rager::Chat::MessageContentType::ImageUrl
|
105
|
+
{"type" => "image_url", "image_url" => {"url" => item.content}}
|
106
|
+
when Rager::Chat::MessageContentType::ImageBase64
|
107
|
+
mime_type = case T.must(item.image_type)
|
108
|
+
when Rager::Chat::MessageContentImageType::Jpeg then "image/jpeg"
|
109
|
+
when Rager::Chat::MessageContentImageType::Png then "image/png"
|
110
|
+
when Rager::Chat::MessageContentImageType::Webp then "image/webp"
|
145
111
|
end
|
146
|
-
|
147
|
-
raise Rager::Errors::ParseError.new(
|
148
|
-
"OpenAI response body is not valid JSON",
|
149
|
-
body
|
150
|
-
)
|
112
|
+
{"type" => "image_url", "image_url" => {"url" => "data:#{mime_type};base64,#{item.content}"}}
|
151
113
|
end
|
114
|
+
end
|
152
115
|
|
153
|
-
|
116
|
+
sig { params(body: String).returns(T::Array[String]) }
|
117
|
+
def handle_non_stream_body(body)
|
118
|
+
response_data = JSON.parse(body)
|
119
|
+
return [] unless response_data.key?("choices") && response_data["choices"].is_a?(Array)
|
120
|
+
|
121
|
+
response_data["choices"].filter_map do |choice|
|
122
|
+
text = choice.dig("message", "content").to_s
|
123
|
+
text unless text.empty?
|
124
|
+
end
|
125
|
+
rescue JSON::ParserError
|
126
|
+
raise Rager::Errors::ParseError.new("OpenAI response body is not valid JSON", body)
|
154
127
|
end
|
155
128
|
|
156
129
|
sig { params(body: T::Enumerator[String]).returns(T::Enumerator[Rager::Chat::MessageDelta]) }
|
157
|
-
def
|
130
|
+
def handle_stream_body(body)
|
158
131
|
Enumerator.new do |yielder|
|
159
132
|
buffer = +""
|
160
133
|
|
161
|
-
process_chunk =
|
134
|
+
process_chunk = ->(chunk) do
|
162
135
|
buffer << chunk
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
data_line = event_match[1] || event_match[2]
|
167
|
-
|
168
|
-
buffer.delete_prefix!(full_event)
|
136
|
+
while (match = buffer.match(/\Adata: (.*?)\n\n|\Adata: (.*?)\n/))
|
137
|
+
buffer.delete_prefix!(T.must(match[0]))
|
138
|
+
data_line = match[1] || match[2]
|
169
139
|
|
170
|
-
next if data_line.nil? || data_line.strip.empty?
|
171
|
-
next if data_line.strip == "[DONE]"
|
140
|
+
next if data_line.nil? || data_line.strip.empty? || data_line.strip == "[DONE]"
|
172
141
|
|
173
142
|
begin
|
174
143
|
data = JSON.parse(data_line)
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
end
|
144
|
+
next unless data.key?("choices") && data["choices"].is_a?(Array)
|
145
|
+
|
146
|
+
data["choices"].each do |choice|
|
147
|
+
delta = choice.dig("delta", "content")
|
148
|
+
yielder << Rager::Chat::MessageDelta.new(index: choice.dig("index") || 0, content: delta) if delta
|
181
149
|
end
|
182
150
|
rescue JSON::ParserError
|
183
151
|
next
|
@@ -186,7 +154,6 @@ module Rager
|
|
186
154
|
end
|
187
155
|
|
188
156
|
body.each(&process_chunk)
|
189
|
-
|
190
157
|
process_chunk.call("\n") unless buffer.empty?
|
191
158
|
end
|
192
159
|
end
|
data/lib/rager/chat.rb
CHANGED
data/lib/rager/config.rb
CHANGED
@@ -7,10 +7,10 @@ module Rager
|
|
7
7
|
class Config
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
-
sig { returns(Rager::Http::Adapters::Abstract) }
|
11
|
-
attr_accessor :http_adapter
|
12
|
-
|
13
10
|
sig { returns(T.nilable(Rager::Logger)) }
|
11
|
+
attr_accessor :logger_type
|
12
|
+
|
13
|
+
sig { returns(::Logger) }
|
14
14
|
attr_accessor :logger
|
15
15
|
|
16
16
|
sig { returns(T.nilable(String)) }
|
@@ -21,10 +21,26 @@ module Rager
|
|
21
21
|
|
22
22
|
sig { void }
|
23
23
|
def initialize
|
24
|
-
@http_adapter = T.let(
|
25
|
-
@
|
24
|
+
@http_adapter = T.let(nil, T.nilable(Rager::Http::Adapters::Abstract))
|
25
|
+
@logger_type = T.let(nil, T.nilable(Rager::Logger))
|
26
|
+
@logger = T.let(::Logger.new($stdout), ::Logger)
|
26
27
|
@url = T.let(nil, T.nilable(String))
|
27
28
|
@api_key = T.let(nil, T.nilable(String))
|
28
29
|
end
|
30
|
+
|
31
|
+
sig { returns(Rager::Http::Adapters::Abstract) }
|
32
|
+
def http_adapter
|
33
|
+
@http_adapter ||= default_http_adapter
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { params(http_adapter: Rager::Http::Adapters::Abstract).void }
|
37
|
+
attr_writer :http_adapter
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
sig { returns(Rager::Http::Adapters::Abstract) }
|
42
|
+
def default_http_adapter
|
43
|
+
Rager::Http::Adapters::AsyncHttp.new
|
44
|
+
end
|
29
45
|
end
|
30
46
|
end
|
data/lib/rager/context.rb
CHANGED
@@ -12,17 +12,17 @@ module Rager
|
|
12
12
|
attr_reader :id
|
13
13
|
|
14
14
|
sig { returns(T.nilable(String)) }
|
15
|
-
attr_reader :
|
15
|
+
attr_reader :name
|
16
16
|
|
17
|
-
sig { params(id: T.nilable(String)).void }
|
18
|
-
def initialize(id: nil)
|
17
|
+
sig { params(id: T.nilable(String), name: T.nilable(String)).void }
|
18
|
+
def initialize(id: nil, name: nil)
|
19
19
|
@id = T.let(id || SecureRandom.uuid, String)
|
20
|
-
@
|
20
|
+
@name = T.let(name, T.nilable(String))
|
21
21
|
end
|
22
22
|
|
23
23
|
sig do
|
24
24
|
params(
|
25
|
-
messages: T.any(String,
|
25
|
+
messages: T.any(String, Rager::Types::ChatInput),
|
26
26
|
kwargs: T.untyped
|
27
27
|
).returns(Rager::Result)
|
28
28
|
end
|
@@ -46,7 +46,7 @@ module Rager
|
|
46
46
|
|
47
47
|
sig do
|
48
48
|
params(
|
49
|
-
text: T.any(String,
|
49
|
+
text: T.any(String, Rager::Types::EmbedInput),
|
50
50
|
kwargs: T.untyped
|
51
51
|
).returns(Rager::Result)
|
52
52
|
end
|
@@ -65,7 +65,7 @@ module Rager
|
|
65
65
|
|
66
66
|
sig do
|
67
67
|
params(
|
68
|
-
prompt:
|
68
|
+
prompt: Rager::Types::ImageGenInput,
|
69
69
|
kwargs: T.untyped
|
70
70
|
).returns(Rager::Result)
|
71
71
|
end
|
@@ -80,7 +80,7 @@ module Rager
|
|
80
80
|
|
81
81
|
sig do
|
82
82
|
params(
|
83
|
-
prompt:
|
83
|
+
prompt: Rager::Types::MeshGenInput,
|
84
84
|
kwargs: T.untyped
|
85
85
|
).returns(Rager::Result)
|
86
86
|
end
|
@@ -95,7 +95,7 @@ module Rager
|
|
95
95
|
|
96
96
|
sig do
|
97
97
|
params(
|
98
|
-
query: Rager::
|
98
|
+
query: Rager::Types::RerankInput,
|
99
99
|
kwargs: T.untyped
|
100
100
|
).returns(Rager::Result)
|
101
101
|
end
|
@@ -110,7 +110,7 @@ module Rager
|
|
110
110
|
|
111
111
|
sig do
|
112
112
|
params(
|
113
|
-
query:
|
113
|
+
query: Rager::Types::SearchInput,
|
114
114
|
kwargs: T.untyped
|
115
115
|
).returns(Rager::Result)
|
116
116
|
end
|
@@ -125,7 +125,7 @@ module Rager
|
|
125
125
|
|
126
126
|
sig do
|
127
127
|
params(
|
128
|
-
input: Rager::
|
128
|
+
input: Rager::Types::TemplateInput,
|
129
129
|
kwargs: T.untyped
|
130
130
|
).returns(Rager::Result)
|
131
131
|
end
|
@@ -150,33 +150,49 @@ module Rager
|
|
150
150
|
).returns(Rager::Result)
|
151
151
|
end
|
152
152
|
def execute(operation, options_struct, kwargs, input, &block)
|
153
|
-
|
153
|
+
name = kwargs.delete(:name)
|
154
|
+
iids = kwargs.delete(:iids)
|
154
155
|
|
155
156
|
options = options_struct.new(**kwargs)
|
156
157
|
options.validate
|
157
158
|
|
158
159
|
start_time = Time.now
|
159
160
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
161
|
+
begin
|
162
|
+
output = yield(options)
|
163
|
+
|
164
|
+
Result.new(
|
165
|
+
id: SecureRandom.uuid,
|
166
|
+
context_id: @id,
|
167
|
+
operation: operation,
|
168
|
+
input: input,
|
169
|
+
output: output,
|
170
|
+
options: options,
|
171
|
+
start_time: start_time.to_i,
|
172
|
+
end_time: Time.now.to_i,
|
173
|
+
name: name,
|
174
|
+
context_name: @name,
|
175
|
+
iids: iids,
|
176
|
+
error: nil
|
177
|
+
).tap(&:log)
|
178
|
+
rescue => e
|
179
|
+
Result.new(
|
180
|
+
id: SecureRandom.uuid,
|
181
|
+
context_id: @id,
|
182
|
+
operation: operation,
|
183
|
+
input: input,
|
184
|
+
output: nil,
|
185
|
+
options: options,
|
186
|
+
start_time: start_time.to_i,
|
187
|
+
end_time: Time.now.to_i,
|
188
|
+
name: name,
|
189
|
+
context_name: @name,
|
190
|
+
iids: iids,
|
191
|
+
error: e.message
|
192
|
+
).tap(&:log)
|
193
|
+
|
194
|
+
raise e
|
195
|
+
end
|
180
196
|
end
|
181
197
|
end
|
182
198
|
end
|
data/lib/rager/embed/options.rb
CHANGED
@@ -14,17 +14,6 @@ module Rager
|
|
14
14
|
const :model, T.nilable(String)
|
15
15
|
const :api_key, T.nilable(String)
|
16
16
|
const :seed, T.nilable(Integer)
|
17
|
-
|
18
|
-
sig { override.returns(T::Hash[String, T.untyped]) }
|
19
|
-
def serialize_safe
|
20
|
-
result = serialize
|
21
|
-
result["api_key"] = "[REDACTED]" if result.key?("api_key")
|
22
|
-
result
|
23
|
-
end
|
24
|
-
|
25
|
-
sig { override.void }
|
26
|
-
def validate
|
27
|
-
end
|
28
17
|
end
|
29
18
|
end
|
30
19
|
end
|
@@ -20,37 +20,25 @@ module Rager
|
|
20
20
|
api_key = options.api_key || ENV["OPENAI_API_KEY"]
|
21
21
|
raise Rager::Errors::MissingCredentialsError.new("OpenAI", "OPENAI_API_KEY") if api_key.nil?
|
22
22
|
|
23
|
-
|
24
|
-
model = options.model || "text-embedding-3-large"
|
25
|
-
|
26
|
-
headers = {
|
27
|
-
"Content-Type" => "application/json"
|
28
|
-
}
|
23
|
+
headers = {"Content-Type" => "application/json"}
|
29
24
|
headers["Authorization"] = "Bearer #{api_key}" if api_key
|
30
25
|
|
31
26
|
body = {
|
32
|
-
model: model,
|
27
|
+
model: options.model || "text-embedding-3-large",
|
33
28
|
input: text
|
34
29
|
}
|
35
30
|
|
36
31
|
request = Rager::Http::Request.new(
|
37
32
|
verb: Rager::Http::Verb::Post,
|
38
|
-
url: url,
|
33
|
+
url: options.url || ENV["OPENAI_URL"] || "https://api.openai.com/v1/embeddings",
|
39
34
|
headers: headers,
|
40
35
|
body: body.to_json
|
41
36
|
)
|
42
37
|
|
43
|
-
|
44
|
-
response = http_adapter.make_request(request)
|
38
|
+
response = Rager.config.http_adapter.make_request(request)
|
45
39
|
response_body = T.cast(T.must(response.body), String)
|
46
40
|
|
47
|
-
if response.status != 200
|
48
|
-
raise Rager::Errors::HttpError.new(
|
49
|
-
http_adapter,
|
50
|
-
response.status,
|
51
|
-
response_body
|
52
|
-
)
|
53
|
-
end
|
41
|
+
raise Rager::Errors::HttpError.new(Rager.config.http_adapter, response.status, response_body) if response.status != 200
|
54
42
|
|
55
43
|
parsed_response = JSON.parse(response_body)
|
56
44
|
parsed_response["data"].map { |item| item["embedding"] }
|
data/lib/rager/embed.rb
CHANGED
@@ -10,8 +10,8 @@ module Rager
|
|
10
10
|
|
11
11
|
sig { params(adapter: Rager::Http::Adapters::Abstract, status: Integer, body: T.nilable(String)).void }
|
12
12
|
def initialize(adapter, status, body)
|
13
|
-
message = "HTTP Error #{status} using
|
14
|
-
message += "
|
13
|
+
message = "HTTP Error #{status} using #{adapter.class.name}"
|
14
|
+
message += ": #{body}" if body
|
15
15
|
super(message)
|
16
16
|
end
|
17
17
|
end
|
@@ -11,7 +11,7 @@ module Rager
|
|
11
11
|
sig { params(invalid_keys: T::Array[String], description: T.nilable(String)).void }
|
12
12
|
def initialize(invalid_keys:, description: nil)
|
13
13
|
message = "Invalid keys #{invalid_keys.join(", ")}"
|
14
|
-
message += "
|
14
|
+
message += " (#{description})" if description
|
15
15
|
super(message)
|
16
16
|
end
|
17
17
|
end
|
data/lib/rager/http/response.rb
CHANGED
@@ -6,9 +6,16 @@ require "sorbet-runtime"
|
|
6
6
|
module Rager
|
7
7
|
module Http
|
8
8
|
class Response < T::Struct
|
9
|
+
extend T::Sig
|
10
|
+
|
9
11
|
const :status, Integer
|
10
12
|
const :headers, T::Hash[String, T.any(String, T::Array[String])]
|
11
13
|
const :body, T.nilable(T.any(String, T::Enumerator[String]))
|
14
|
+
|
15
|
+
sig { returns(T::Boolean) }
|
16
|
+
def success?
|
17
|
+
status >= 200 && status < 300
|
18
|
+
end
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
@@ -11,19 +11,9 @@ module Rager
|
|
11
11
|
|
12
12
|
const :provider, String, default: "replicate"
|
13
13
|
const :model, String, default: "black-forest-labs/flux-schnell"
|
14
|
+
const :output_format, T.nilable(Rager::ImageGen::OutputFormat)
|
14
15
|
const :api_key, T.nilable(String)
|
15
16
|
const :seed, T.nilable(Integer)
|
16
|
-
|
17
|
-
sig { override.returns(T::Hash[String, T.untyped]) }
|
18
|
-
def serialize_safe
|
19
|
-
result = serialize
|
20
|
-
result["api_key"] = "[REDACTED]" if result.key?("api_key")
|
21
|
-
result
|
22
|
-
end
|
23
|
-
|
24
|
-
sig { override.void }
|
25
|
-
def validate
|
26
|
-
end
|
27
17
|
end
|
28
18
|
end
|
29
19
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
6
|
+
module Rager
|
7
|
+
module ImageGen
|
8
|
+
class OutputFormat < T::Enum
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
enums do
|
12
|
+
Png = new("png")
|
13
|
+
Jpg = new("jpg")
|
14
|
+
Webp = new("webp")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|