boxcars 0.6.4 → 0.6.5
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/.ruby-version +1 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile +5 -5
- data/Gemfile.lock +30 -31
- data/lib/boxcars/boxcar/json_engine_boxcar.rb +29 -12
- data/lib/boxcars/boxcar.rb +1 -1
- data/lib/boxcars/engine/openai.rb +10 -1
- data/lib/boxcars/engine/perplexityai.rb +48 -0
- data/lib/boxcars/engine.rb +0 -1
- data/lib/boxcars/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 164d55b95e134a691b4525f778a83f6d06cdaa1948028b87371cb6cb8a16fd43
|
4
|
+
data.tar.gz: 2707ac063bbc1127d75398be8770812ae258447ba021c0b9527cd3fbf113ff02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b0d7909ef7c049d7c393b646abd072c01dd4b295a7af909bbe2f85fe48b8425c946f956440548fa3902182c636d3e57e81279332d331a9d7c4df4181cd4e4d5
|
7
|
+
data.tar.gz: ed1c903fb5575ae563ccab8adb0e80cfed9c00e529a5850fc7b89acaf165eecaf42e69cdd548cdec3622855645b5bf88591b3d6a6cb1af47bfbe97d5d6d16ad9
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.3.
|
1
|
+
3.3.5
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v0.6.4](https://github.com/BoxcarsAI/boxcars/tree/v0.6.4) (2024-07-27)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.6.3...v0.6.4)
|
6
|
+
|
7
|
+
**Merged pull requests:**
|
8
|
+
|
9
|
+
- Add Ollama Engine [\#200](https://github.com/BoxcarsAI/boxcars/pull/200) ([francis](https://github.com/francis))
|
10
|
+
|
3
11
|
## [v0.6.3](https://github.com/BoxcarsAI/boxcars/tree/v0.6.3) (2024-07-26)
|
4
12
|
|
5
13
|
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.6.2...v0.6.3)
|
data/Gemfile
CHANGED
@@ -15,13 +15,13 @@ gem "sqlite3", "~> 1.7"
|
|
15
15
|
|
16
16
|
gem "async", "~>1.32.1"
|
17
17
|
|
18
|
-
gem "activerecord", "~> 7.
|
18
|
+
gem "activerecord", "~> 7.1"
|
19
19
|
|
20
20
|
gem "github_changelog_generator", "~> 1.16"
|
21
21
|
|
22
22
|
gem "faraday-retry", "~> 2.0"
|
23
23
|
|
24
|
-
gem "activesupport", "~> 7.
|
24
|
+
gem "activesupport", "~> 7.1"
|
25
25
|
|
26
26
|
gem "rest-client", "~> 2.1"
|
27
27
|
|
@@ -32,9 +32,9 @@ gem "pgvector", "~> 0.2.2"
|
|
32
32
|
|
33
33
|
group :development, :test do
|
34
34
|
gem "rspec", "~> 3.13"
|
35
|
-
gem "rubocop", "~> 1.
|
36
|
-
gem "vcr", "~> 6.
|
35
|
+
gem "rubocop", "~> 1.66"
|
36
|
+
gem "vcr", "~> 6.3.1"
|
37
37
|
gem "webmock", "~> 3.23.1"
|
38
38
|
gem "rubocop-rake", "~> 0.6.0"
|
39
|
-
gem "rubocop-rspec", "~> 3.
|
39
|
+
gem "rubocop-rspec", "~> 3.1"
|
40
40
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
boxcars (0.6.
|
4
|
+
boxcars (0.6.5)
|
5
5
|
anthropic (~> 0.1)
|
6
6
|
google_search_results (~> 2.2)
|
7
7
|
gpt4all (~> 0.0.4)
|
@@ -13,13 +13,13 @@ PATH
|
|
13
13
|
GEM
|
14
14
|
remote: https://rubygems.org/
|
15
15
|
specs:
|
16
|
-
activemodel (7.1.
|
17
|
-
activesupport (= 7.1.
|
18
|
-
activerecord (7.1.
|
19
|
-
activemodel (= 7.1.
|
20
|
-
activesupport (= 7.1.
|
16
|
+
activemodel (7.1.4)
|
17
|
+
activesupport (= 7.1.4)
|
18
|
+
activerecord (7.1.4)
|
19
|
+
activemodel (= 7.1.4)
|
20
|
+
activesupport (= 7.1.4)
|
21
21
|
timeout (>= 0.4.0)
|
22
|
-
activesupport (7.1.
|
22
|
+
activesupport (7.1.4)
|
23
23
|
base64
|
24
24
|
bigdecimal
|
25
25
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
@@ -57,7 +57,7 @@ GEM
|
|
57
57
|
async (>= 1.25)
|
58
58
|
base64 (0.2.0)
|
59
59
|
bigdecimal (3.1.8)
|
60
|
-
concurrent-ruby (1.3.
|
60
|
+
concurrent-ruby (1.3.4)
|
61
61
|
connection_pool (2.4.1)
|
62
62
|
console (1.27.0)
|
63
63
|
fiber-annotation
|
@@ -71,7 +71,7 @@ GEM
|
|
71
71
|
reline (>= 0.3.8)
|
72
72
|
diff-lcs (1.5.1)
|
73
73
|
domain_name (0.6.20240107)
|
74
|
-
dotenv (3.1.
|
74
|
+
dotenv (3.1.4)
|
75
75
|
drb (2.2.1)
|
76
76
|
event_stream_parser (1.0.0)
|
77
77
|
faraday (2.10.0)
|
@@ -120,7 +120,7 @@ GEM
|
|
120
120
|
mime-types (3.5.2)
|
121
121
|
mime-types-data (~> 3.2015)
|
122
122
|
mime-types-data (3.2024.0702)
|
123
|
-
minitest (5.
|
123
|
+
minitest (5.25.1)
|
124
124
|
multi_json (1.15.0)
|
125
125
|
multipart-post (2.4.1)
|
126
126
|
mutex_m (0.2.0)
|
@@ -128,19 +128,19 @@ GEM
|
|
128
128
|
uri
|
129
129
|
netrc (0.11.0)
|
130
130
|
nio4r (2.7.3)
|
131
|
-
nokogiri (1.16.
|
131
|
+
nokogiri (1.16.7-arm64-darwin)
|
132
132
|
racc (~> 1.4)
|
133
|
-
nokogiri (1.16.
|
133
|
+
nokogiri (1.16.7-x86_64-linux)
|
134
134
|
racc (~> 1.4)
|
135
135
|
octokit (4.25.1)
|
136
136
|
faraday (>= 1, < 3)
|
137
137
|
sawyer (~> 0.9)
|
138
138
|
os (1.1.4)
|
139
|
-
parallel (1.
|
140
|
-
parser (3.3.
|
139
|
+
parallel (1.26.3)
|
140
|
+
parser (3.3.5.0)
|
141
141
|
ast (~> 2.4.1)
|
142
142
|
racc
|
143
|
-
pg (1.5.
|
143
|
+
pg (1.5.8)
|
144
144
|
pgvector (0.2.2)
|
145
145
|
protocol-hpack (1.4.3)
|
146
146
|
protocol-http (0.26.8)
|
@@ -152,7 +152,7 @@ GEM
|
|
152
152
|
psych (5.1.2)
|
153
153
|
stringio
|
154
154
|
public_suffix (6.0.0)
|
155
|
-
racc (1.8.
|
155
|
+
racc (1.8.1)
|
156
156
|
rainbow (3.1.1)
|
157
157
|
rake (13.2.1)
|
158
158
|
rdoc (6.7.0)
|
@@ -165,8 +165,7 @@ GEM
|
|
165
165
|
http-cookie (>= 1.0.2, < 2.0)
|
166
166
|
mime-types (>= 1.16, < 4.0)
|
167
167
|
netrc (~> 0.8)
|
168
|
-
rexml (3.3.
|
169
|
-
strscan
|
168
|
+
rexml (3.3.8)
|
170
169
|
rspec (3.13.0)
|
171
170
|
rspec-core (~> 3.13.0)
|
172
171
|
rspec-expectations (~> 3.13.0)
|
@@ -180,22 +179,21 @@ GEM
|
|
180
179
|
diff-lcs (>= 1.2.0, < 2.0)
|
181
180
|
rspec-support (~> 3.13.0)
|
182
181
|
rspec-support (3.13.1)
|
183
|
-
rubocop (1.
|
182
|
+
rubocop (1.66.1)
|
184
183
|
json (~> 2.3)
|
185
184
|
language_server-protocol (>= 3.17.0)
|
186
185
|
parallel (~> 1.10)
|
187
186
|
parser (>= 3.3.0.2)
|
188
187
|
rainbow (>= 2.2.2, < 4.0)
|
189
188
|
regexp_parser (>= 2.4, < 3.0)
|
190
|
-
|
191
|
-
rubocop-ast (>= 1.31.1, < 2.0)
|
189
|
+
rubocop-ast (>= 1.32.2, < 2.0)
|
192
190
|
ruby-progressbar (~> 1.7)
|
193
191
|
unicode-display_width (>= 2.4.0, < 3.0)
|
194
|
-
rubocop-ast (1.
|
192
|
+
rubocop-ast (1.32.3)
|
195
193
|
parser (>= 3.3.1.0)
|
196
194
|
rubocop-rake (0.6.0)
|
197
195
|
rubocop (~> 1.0)
|
198
|
-
rubocop-rspec (3.0
|
196
|
+
rubocop-rspec (3.1.0)
|
199
197
|
rubocop (~> 1.61)
|
200
198
|
ruby-openai (7.1.0)
|
201
199
|
event_stream_parser (>= 0.3.0, < 2.0.0)
|
@@ -209,7 +207,6 @@ GEM
|
|
209
207
|
sqlite3 (1.7.3-x86_64-linux)
|
210
208
|
stringio (3.1.1)
|
211
209
|
strings-ansi (0.2.0)
|
212
|
-
strscan (3.1.0)
|
213
210
|
timeout (0.4.1)
|
214
211
|
timers (4.3.5)
|
215
212
|
traces (0.11.1)
|
@@ -222,9 +219,10 @@ GEM
|
|
222
219
|
tty-screen (0.8.2)
|
223
220
|
tzinfo (2.0.6)
|
224
221
|
concurrent-ruby (~> 1.0)
|
225
|
-
unicode-display_width (2.
|
222
|
+
unicode-display_width (2.6.0)
|
226
223
|
uri (0.13.0)
|
227
|
-
vcr (6.
|
224
|
+
vcr (6.3.1)
|
225
|
+
base64
|
228
226
|
webmock (3.23.1)
|
229
227
|
addressable (>= 2.8.0)
|
230
228
|
crack (>= 0.3.2)
|
@@ -233,11 +231,12 @@ GEM
|
|
233
231
|
PLATFORMS
|
234
232
|
arm64-darwin-22
|
235
233
|
arm64-darwin-23
|
234
|
+
arm64-darwin-24
|
236
235
|
x86_64-linux
|
237
236
|
|
238
237
|
DEPENDENCIES
|
239
|
-
activerecord (~> 7.
|
240
|
-
activesupport (~> 7.
|
238
|
+
activerecord (~> 7.1)
|
239
|
+
activesupport (~> 7.1)
|
241
240
|
async (~> 1.32.1)
|
242
241
|
boxcars!
|
243
242
|
debug (~> 1.9)
|
@@ -250,11 +249,11 @@ DEPENDENCIES
|
|
250
249
|
rake (~> 13.2)
|
251
250
|
rest-client (~> 2.1)
|
252
251
|
rspec (~> 3.13)
|
253
|
-
rubocop (~> 1.
|
252
|
+
rubocop (~> 1.66)
|
254
253
|
rubocop-rake (~> 0.6.0)
|
255
|
-
rubocop-rspec (~> 3.
|
254
|
+
rubocop-rspec (~> 3.1)
|
256
255
|
sqlite3 (~> 1.7)
|
257
|
-
vcr (~> 6.
|
256
|
+
vcr (~> 6.3.1)
|
258
257
|
webmock (~> 3.23.1)
|
259
258
|
|
260
259
|
BUNDLED WITH
|
@@ -50,12 +50,14 @@ module Boxcars
|
|
50
50
|
# @param engine_output [String] The output from the engine.
|
51
51
|
# @return [Result] The result.
|
52
52
|
def get_answer(engine_output)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
json_string = extract_json(engine_output)
|
54
|
+
reply = JSON.parse(json_string, symbolize_names: symbolize)
|
55
|
+
Result.new(status: :ok, answer: reply, explanation: reply)
|
56
|
+
rescue JSON::ParserError => e
|
57
|
+
Boxcars.debug "JSON: #{engine_output}", :red
|
58
|
+
Result.from_error("JSON parsing error: #{e.message}")
|
57
59
|
rescue StandardError => e
|
58
|
-
Result.from_error("
|
60
|
+
Result.from_error("Unexpected error: #{e.message}")
|
59
61
|
end
|
60
62
|
|
61
63
|
# get answer from parsed JSON
|
@@ -63,14 +65,29 @@ module Boxcars
|
|
63
65
|
# @return [Result] The result.
|
64
66
|
def extract_answer(data)
|
65
67
|
reply = data
|
68
|
+
Result.new(status: :ok, answer: reply, explanation: reply)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def extract_json(text)
|
74
|
+
# Escape control characters (U+0000 to U+001F)
|
75
|
+
text = text.gsub(/[\u0000-\u001F]/, '')
|
76
|
+
# first strip hidden characters
|
77
|
+
# text = text.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
|
78
|
+
|
79
|
+
# sometimes the LLM adds text in front of the JSON output, so let's strip it here
|
80
|
+
json_start = text.index("{")
|
81
|
+
json_end = text.rindex("}")
|
82
|
+
text[json_start..json_end]
|
83
|
+
end
|
84
|
+
|
85
|
+
def extract_json2(text)
|
86
|
+
# Match the outermost JSON object
|
87
|
+
match = text.match(/\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}/)
|
88
|
+
raise StandardError, "No valid JSON object found in the output" unless match
|
66
89
|
|
67
|
-
|
68
|
-
Result.new(status: :ok, answer: reply, explanation: reply)
|
69
|
-
else
|
70
|
-
# we have an unexpected output from the engine
|
71
|
-
Result.new(status: :error, answer: nil,
|
72
|
-
explanation: "You gave me an improperly formatted answer. I was expecting a valid reply.")
|
73
|
-
end
|
90
|
+
match[0]
|
74
91
|
end
|
75
92
|
end
|
76
93
|
end
|
data/lib/boxcars/boxcar.rb
CHANGED
@@ -166,7 +166,7 @@ module Boxcars
|
|
166
166
|
output = call(inputs: inputs)
|
167
167
|
rescue StandardError => e
|
168
168
|
Boxcars.error "Error in #{name} boxcar#call: #{e}\nbt:#{e.backtrace[0..5].join("\n ")}", :red
|
169
|
-
Boxcars.error("Response Body: #{e.response[:body]}", :red) if e.respond_to?(:response)
|
169
|
+
Boxcars.error("Response Body: #{e.response[:body]}", :red) if e.respond_to?(:response) && e.response.present?
|
170
170
|
raise e
|
171
171
|
end
|
172
172
|
validate_outputs(outputs: output.keys)
|
@@ -28,6 +28,11 @@ module Boxcars
|
|
28
28
|
# @param batch_size [Integer] The number of prompts to send to the engine at once. Defaults to 20.
|
29
29
|
def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs)
|
30
30
|
@open_ai_params = DEFAULT_PARAMS.merge(kwargs)
|
31
|
+
if @open_ai_params[:model] =~ /^o/ && @open_ai_params[:max_tokens].present?
|
32
|
+
@open_ai_params[:max_completion_tokens] = @open_ai_params.delete(:max_tokens)
|
33
|
+
@open_ai_params.delete(:temperature)
|
34
|
+
end
|
35
|
+
|
31
36
|
@prompts = prompts
|
32
37
|
@batch_size = batch_size
|
33
38
|
super(description: description, name: name)
|
@@ -44,7 +49,7 @@ module Boxcars
|
|
44
49
|
end
|
45
50
|
|
46
51
|
def conversation_model?(model)
|
47
|
-
!!(model =~ /(^gpt-4)|(-turbo\b)/)
|
52
|
+
!!(model =~ /(^gpt-4)|(-turbo\b)|(^o\d)/)
|
48
53
|
end
|
49
54
|
|
50
55
|
# Get an answer from the engine.
|
@@ -57,6 +62,10 @@ module Boxcars
|
|
57
62
|
params = open_ai_params.merge(kwargs)
|
58
63
|
if conversation_model?(params[:model])
|
59
64
|
prompt = prompt.first if prompt.is_a?(Array)
|
65
|
+
if params[:model] =~ /^o/
|
66
|
+
params.delete(:response_format)
|
67
|
+
params.delete(:stop)
|
68
|
+
end
|
60
69
|
params = prompt.as_messages(inputs).merge(params)
|
61
70
|
if Boxcars.configuration.log_prompts
|
62
71
|
Boxcars.debug(params[:messages].last(2).map { |p| ">>>>>> Role: #{p[:role]} <<<<<<\n#{p[:content]}" }.join("\n"), :cyan)
|
@@ -40,6 +40,7 @@ module Boxcars
|
|
40
40
|
faraday.request :json
|
41
41
|
faraday.response :json
|
42
42
|
faraday.response :raise_error
|
43
|
+
# faraday.options.timeout = 180 # 3 minutes
|
43
44
|
end
|
44
45
|
|
45
46
|
response = conn.post do |req|
|
@@ -122,4 +123,51 @@ module Boxcars
|
|
122
123
|
def max_tokens_for_prompt(_prompt_text)
|
123
124
|
8096
|
124
125
|
end
|
126
|
+
|
127
|
+
# Get generation informaton
|
128
|
+
# @param sub_choices [Array<Hash>] The choices to get generation info for.
|
129
|
+
# @return [Array<Generation>] The generation information.
|
130
|
+
def generation_info(sub_choices)
|
131
|
+
sub_choices.map do |choice|
|
132
|
+
Generation.new(
|
133
|
+
text: choice.dig("message", "content") || choice["text"],
|
134
|
+
generation_info: {
|
135
|
+
finish_reason: choice.fetch("finish_reason", nil),
|
136
|
+
logprobs: choice.fetch("logprobs", nil)
|
137
|
+
}
|
138
|
+
)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Call out to endpoint with k unique prompts.
|
143
|
+
# @param prompts [Array<String>] The prompts to pass into the model.
|
144
|
+
# @param inputs [Array<String>] The inputs to subsitite into the prompt.
|
145
|
+
# @param stop [Array<String>] Optional list of stop words to use when generating.
|
146
|
+
# @return [EngineResult] The full engine output.
|
147
|
+
def generate(prompts:, stop: nil)
|
148
|
+
params = {}
|
149
|
+
params[:stop] = stop if stop
|
150
|
+
choices = []
|
151
|
+
token_usage = {}
|
152
|
+
# Get the token usage from the response.
|
153
|
+
# Includes prompt, completion, and total tokens used.
|
154
|
+
inkeys = %w[completion_tokens prompt_tokens total_tokens].freeze
|
155
|
+
prompts.each_slice(batch_size) do |sub_prompts|
|
156
|
+
sub_prompts.each do |sprompts, inputs|
|
157
|
+
response = client(prompt: sprompts, inputs: inputs, **params)
|
158
|
+
check_response(response)
|
159
|
+
choices.concat(response["choices"])
|
160
|
+
usage_keys = inkeys & response["usage"].keys
|
161
|
+
usage_keys.each { |key| token_usage[key] = token_usage[key].to_i + response["usage"][key] }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
n = params.fetch(:n, 1)
|
166
|
+
generations = []
|
167
|
+
prompts.each_with_index do |_prompt, i|
|
168
|
+
sub_choices = choices[i * n, (i + 1) * n]
|
169
|
+
generations.push(generation_info(sub_choices))
|
170
|
+
end
|
171
|
+
EngineResult.new(generations: generations, engine_output: { token_usage: token_usage })
|
172
|
+
end
|
125
173
|
end
|
data/lib/boxcars/engine.rb
CHANGED
data/lib/boxcars/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: boxcars
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Francis Sullivan
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-10-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: anthropic
|
@@ -219,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
219
|
- !ruby/object:Gem::Version
|
220
220
|
version: '0'
|
221
221
|
requirements: []
|
222
|
-
rubygems_version: 3.5.
|
222
|
+
rubygems_version: 3.5.20
|
223
223
|
signing_key:
|
224
224
|
specification_version: 4
|
225
225
|
summary: Boxcars is a gem that enables you to create new systems with AI composability.
|