boxcars 0.1.1 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -5
- data/Gemfile +2 -0
- data/Gemfile.lock +68 -2
- data/README.md +77 -3
- data/Rakefile +7 -0
- data/boxcars.gemspec +1 -1
- data/lib/boxcars/boxcar/calculator.rb +13 -5
- data/lib/boxcars/boxcar/engine_boxcar.rb +24 -20
- data/lib/boxcars/boxcar/serp.rb +2 -2
- data/lib/boxcars/boxcar/sql.rb +11 -4
- data/lib/boxcars/boxcar.rb +28 -17
- data/lib/boxcars/engine/openai.rb +24 -22
- data/lib/boxcars/ruby_repl.rb +4 -0
- data/lib/boxcars/{conductor/conductor_action.rb → train/train_action.rb} +2 -2
- data/lib/boxcars/{conductor/conductor_finish.rb → train/train_finish.rb} +2 -2
- data/lib/boxcars/{conductor → train}/zero_shot.rb +22 -13
- data/lib/boxcars/train.rb +224 -0
- data/lib/boxcars/version.rb +2 -1
- data/lib/boxcars.rb +22 -2
- metadata +7 -8
- data/lib/boxcars/conductor/conductor_executer.rb +0 -96
- data/lib/boxcars/conductor.rb +0 -147
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d5ae0de1aba4038723912365d6ac1d50da0e34a40aad508130ecc86e71f91de
|
4
|
+
data.tar.gz: e0430621516358a59b7eeaadfa44fe78eed0b3ef92d929c264435d0946dbce5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a054ad6b3b3caef1c6bb39fbd9a667779c4dc638800e905b717285b8f5dde4a578e3325373176b099af9f4f7d07b6f7803f87fe67c4f771bfce8894ef209188e
|
7
|
+
data.tar.gz: f3a3020bd0c393c25cd430b8702e26a7a39b87127372787c416042da63c6fb90826773ca81a456ba67a1add908790620757d8b9aab4db32269e3391d576c5ea5
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,36 @@
|
|
1
|
-
|
2
|
-
Changed
|
3
|
-
- updated to OpenAI gem 3.0
|
1
|
+
# Changelog
|
4
2
|
|
5
|
-
## [
|
3
|
+
## [Unreleased](https://github.com/BoxcarsAI/boxcars/tree/HEAD)
|
6
4
|
|
7
|
-
|
5
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.2...HEAD)
|
6
|
+
|
7
|
+
**Closed issues:**
|
8
|
+
|
9
|
+
- Make sure the yard docs are up to date and have coverage [\#7](https://github.com/BoxcarsAI/boxcars/issues/7)
|
10
|
+
- Specs need environment variables to be set to run green [\#4](https://github.com/BoxcarsAI/boxcars/issues/4)
|
11
|
+
|
12
|
+
**Merged pull requests:**
|
13
|
+
|
14
|
+
- Get GitHub Actions to green [\#5](https://github.com/BoxcarsAI/boxcars/pull/5) ([petergoldstein](https://github.com/petergoldstein))
|
15
|
+
- Fix typo introduced by merge. Pull publish-rubygem into its own job [\#3](https://github.com/BoxcarsAI/boxcars/pull/3) ([petergoldstein](https://github.com/petergoldstein))
|
16
|
+
|
17
|
+
## [v0.1.2](https://github.com/BoxcarsAI/boxcars/tree/v0.1.2) (2023-02-17)
|
18
|
+
|
19
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.1...v0.1.2)
|
20
|
+
|
21
|
+
**Merged pull requests:**
|
22
|
+
|
23
|
+
- Run GitHub Actions against multiple Rubies [\#2](https://github.com/BoxcarsAI/boxcars/pull/2) ([petergoldstein](https://github.com/petergoldstein))
|
24
|
+
- \[infra\] Added deployment step for the RubyGems [\#1](https://github.com/BoxcarsAI/boxcars/pull/1) ([AKovtunov](https://github.com/AKovtunov))
|
25
|
+
|
26
|
+
## [v0.1.1](https://github.com/BoxcarsAI/boxcars/tree/v0.1.1) (2023-02-16)
|
27
|
+
|
28
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.0...v0.1.1)
|
29
|
+
|
30
|
+
## [v0.1.0](https://github.com/BoxcarsAI/boxcars/tree/v0.1.0) (2023-02-15)
|
31
|
+
|
32
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/e3c50bdc76f71c6d2abb012c38174633a5847028...v0.1.0)
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
boxcars (0.1.
|
4
|
+
boxcars (0.1.3)
|
5
5
|
google_search_results (~> 2.2)
|
6
6
|
ruby-openai (~> 3.0)
|
7
7
|
|
@@ -21,7 +21,28 @@ GEM
|
|
21
21
|
addressable (2.8.1)
|
22
22
|
public_suffix (>= 2.0.2, < 6.0)
|
23
23
|
ast (2.4.2)
|
24
|
+
async (1.30.3)
|
25
|
+
console (~> 1.10)
|
26
|
+
nio4r (~> 2.3)
|
27
|
+
timers (~> 4.1)
|
28
|
+
async-http (0.60.1)
|
29
|
+
async (>= 1.25)
|
30
|
+
async-io (>= 1.28)
|
31
|
+
async-pool (>= 0.2)
|
32
|
+
protocol-http (~> 0.24.0)
|
33
|
+
protocol-http1 (~> 0.15.0)
|
34
|
+
protocol-http2 (~> 0.15.0)
|
35
|
+
traces (>= 0.8.0)
|
36
|
+
async-http-faraday (0.11.0)
|
37
|
+
async-http (~> 0.42)
|
38
|
+
faraday
|
39
|
+
async-io (1.34.3)
|
40
|
+
async
|
41
|
+
async-pool (0.3.12)
|
42
|
+
async (>= 1.25)
|
24
43
|
concurrent-ruby (1.2.0)
|
44
|
+
console (1.16.2)
|
45
|
+
fiber-local
|
25
46
|
crack (0.4.5)
|
26
47
|
rexml
|
27
48
|
debug (1.7.1)
|
@@ -29,6 +50,22 @@ GEM
|
|
29
50
|
reline (>= 0.3.1)
|
30
51
|
diff-lcs (1.5.0)
|
31
52
|
dotenv (2.8.1)
|
53
|
+
faraday (2.7.4)
|
54
|
+
faraday-net_http (>= 2.0, < 3.1)
|
55
|
+
ruby2_keywords (>= 0.0.4)
|
56
|
+
faraday-http-cache (2.4.1)
|
57
|
+
faraday (>= 0.8)
|
58
|
+
faraday-net_http (3.0.2)
|
59
|
+
fiber-local (1.0.0)
|
60
|
+
github_changelog_generator (1.16.4)
|
61
|
+
activesupport
|
62
|
+
async (>= 1.25.0)
|
63
|
+
async-http-faraday
|
64
|
+
faraday-http-cache
|
65
|
+
multi_json
|
66
|
+
octokit (~> 4.6)
|
67
|
+
rainbow (>= 2.2.1)
|
68
|
+
rake (>= 10.0)
|
32
69
|
google_search_results (2.2.0)
|
33
70
|
hashdiff (1.0.1)
|
34
71
|
httparty (0.21.0)
|
@@ -37,15 +74,31 @@ GEM
|
|
37
74
|
i18n (1.12.0)
|
38
75
|
concurrent-ruby (~> 1.0)
|
39
76
|
io-console (0.6.0)
|
77
|
+
io-console (0.6.0-java)
|
40
78
|
irb (1.6.2)
|
41
79
|
reline (>= 0.3.0)
|
42
80
|
json (2.6.3)
|
81
|
+
json (2.6.3-java)
|
43
82
|
mini_mime (1.1.2)
|
83
|
+
mini_portile2 (2.8.1)
|
44
84
|
minitest (5.17.0)
|
85
|
+
multi_json (1.15.0)
|
45
86
|
multi_xml (0.6.0)
|
87
|
+
nio4r (2.5.8)
|
88
|
+
nio4r (2.5.8-java)
|
89
|
+
octokit (4.25.1)
|
90
|
+
faraday (>= 1, < 3)
|
91
|
+
sawyer (~> 0.9)
|
46
92
|
parallel (1.22.1)
|
47
93
|
parser (3.2.1.0)
|
48
94
|
ast (~> 2.4.1)
|
95
|
+
protocol-hpack (1.4.2)
|
96
|
+
protocol-http (0.24.1)
|
97
|
+
protocol-http1 (0.15.0)
|
98
|
+
protocol-http (~> 0.22)
|
99
|
+
protocol-http2 (0.15.1)
|
100
|
+
protocol-hpack (~> 1.4)
|
101
|
+
protocol-http (~> 0.18)
|
49
102
|
public_suffix (5.0.1)
|
50
103
|
rainbow (3.1.1)
|
51
104
|
rake (13.0.6)
|
@@ -88,7 +141,16 @@ GEM
|
|
88
141
|
ruby-openai (3.3.0)
|
89
142
|
httparty (>= 0.18.1)
|
90
143
|
ruby-progressbar (1.11.0)
|
144
|
+
ruby2_keywords (0.0.5)
|
145
|
+
sawyer (0.9.2)
|
146
|
+
addressable (>= 2.3.5)
|
147
|
+
faraday (>= 0.17.3, < 3)
|
148
|
+
sqlite3 (1.6.0)
|
149
|
+
mini_portile2 (~> 2.8.0)
|
91
150
|
sqlite3 (1.6.0-x86_64-darwin)
|
151
|
+
sqlite3 (1.6.0-x86_64-linux)
|
152
|
+
timers (4.3.5)
|
153
|
+
traces (0.8.0)
|
92
154
|
tzinfo (2.0.6)
|
93
155
|
concurrent-ruby (~> 1.0)
|
94
156
|
unicode-display_width (2.4.2)
|
@@ -99,13 +161,17 @@ GEM
|
|
99
161
|
hashdiff (>= 0.4.0, < 2.0.0)
|
100
162
|
|
101
163
|
PLATFORMS
|
164
|
+
universal-java-11
|
102
165
|
x86_64-darwin-21
|
166
|
+
x86_64-darwin-22
|
167
|
+
x86_64-linux
|
103
168
|
|
104
169
|
DEPENDENCIES
|
105
170
|
activerecord (~> 7.0)
|
106
171
|
boxcars!
|
107
172
|
debug (~> 1.1)
|
108
173
|
dotenv (~> 2.8)
|
174
|
+
github_changelog_generator (~> 1.16)
|
109
175
|
rake (~> 13.0)
|
110
176
|
rspec (~> 3.2)
|
111
177
|
rubocop (~> 1.21)
|
@@ -116,4 +182,4 @@ DEPENDENCIES
|
|
116
182
|
webmock (~> 3.18.1)
|
117
183
|
|
118
184
|
BUNDLED WITH
|
119
|
-
2.
|
185
|
+
2.4.7
|
data/README.md
CHANGED
@@ -1,8 +1,15 @@
|
|
1
1
|
# Boxcars
|
2
2
|
|
3
|
-
|
3
|
+
This gem lets you compose new systems with composability using systems like OpenAI, Search, and SQL (and many more).
|
4
4
|
|
5
|
-
|
5
|
+
The popular python library langchain is a precursor to this work, but we wanted to put a ruby spin on things and make it easier to get started.
|
6
|
+
|
7
|
+
## Concepts
|
8
|
+
All of these concepts are in a module named Boxcars:
|
9
|
+
- Prompt: a prompt is used by an Engine to generate text results.
|
10
|
+
- Engine: an entity that generates text from a Prompt.
|
11
|
+
- Boxcar: an encapsulation that does one thing (search, math, SQL, etc) and a many use an Engine to get their work accomplished.cc
|
12
|
+
- Train: given a list of Boxcars and an Engine, an answer if found by breaking the promlem into peices for an indvidual Boxcar to solve. This is all joined back together to yield a final result. There is currently only one implementation - ZeroShot. You can construct it directly, or just use `Boxcars::default_train`
|
6
13
|
|
7
14
|
## Installation
|
8
15
|
|
@@ -22,7 +29,74 @@ Or install it yourself as:
|
|
22
29
|
|
23
30
|
## Usage
|
24
31
|
|
25
|
-
|
32
|
+
We will document many more examples soon, but here are a couple. The first step is to setup your environment variables for OpenAI and Serp (OPENAI_ACCESS_TOKEN, SERPAPI_API_KEY). If you don't want to set them in your environment, they can be passed in as well to the API.
|
33
|
+
|
34
|
+
In the examples below, we added one rubygem to load the environment at the first line, but depending on what you want, you might not need this.
|
35
|
+
```ruby
|
36
|
+
require "dotenv/load"
|
37
|
+
require "boxcars"
|
38
|
+
```
|
39
|
+
|
40
|
+
### Direct Boxcar Use
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# run the calculator
|
44
|
+
engine = Boxcars::Openai.new(max_tokens: 256)
|
45
|
+
calc = Boxcars::Calculator.new(engine: engine)
|
46
|
+
puts calc.run "what is pi to the forth power divided by 22.1?"
|
47
|
+
```
|
48
|
+
This segment above (try it by pasting into an `irb` session)
|
49
|
+
```text
|
50
|
+
> Entering Calculator#run
|
51
|
+
what is pi to the forth power divided by 22.1?
|
52
|
+
RubyREPL: puts(Math::PI**4 / 22.1)
|
53
|
+
Answer: 4.407651178009159
|
54
|
+
|
55
|
+
4.407651178009159
|
56
|
+
< Exiting Calculator#run
|
57
|
+
4.407651178009159
|
58
|
+
```
|
59
|
+
|
60
|
+
Note that since Openai is currently the most used Engine, if you do not pass in an engine, it will default as expected. So, this is the equialent shorter version of the above script:
|
61
|
+
```ruby
|
62
|
+
# run the calculator
|
63
|
+
calc = Boxcars::Calculator.new # just use the default Engine
|
64
|
+
puts calc.run "what is pi to the forth power divided by 22.1?"
|
65
|
+
```
|
66
|
+
### Boxcars currently implemmented
|
67
|
+
|
68
|
+
Here is what we have so far, but please put up a PR with your new ideas.
|
69
|
+
- Search: uses the SERP API to do seaches
|
70
|
+
- Calculator: uses an Engine to generate ruby code to do math
|
71
|
+
- SQL: given an ActiveRecord connection, it will generate and run sql statments from a prompt.
|
72
|
+
|
73
|
+
### Run a list of Boxcars
|
74
|
+
```ruby
|
75
|
+
# run a Train for a calculator, and search using default Engine
|
76
|
+
boxcars = [Boxcars::Calculator.new, Boxcars::Serp.new]
|
77
|
+
train = Boxcars.default_train.new(boxcars: boxcars)
|
78
|
+
puts train.run "What is pi times the square root of the average temperature in Austin TX in January?"
|
79
|
+
```
|
80
|
+
This outputs:
|
81
|
+
```text
|
82
|
+
> Entering Zero Shot#run
|
83
|
+
What is pi times the square root of the average temperature in Austin TX in January?
|
84
|
+
Question: Average temperature in Austin TX in January
|
85
|
+
Answer: increase from 62°F to 64°F
|
86
|
+
#Observation: increase from 62°F to 64°F
|
87
|
+
> Entering Calculator#run
|
88
|
+
64°F x pi
|
89
|
+
RubyREPL: puts (64 * Math::PI).round(2)
|
90
|
+
Answer: 201.06
|
91
|
+
|
92
|
+
201.06
|
93
|
+
< Exiting Calculator#run
|
94
|
+
#Observation: 201.06
|
95
|
+
I now know the final answer
|
96
|
+
Final Answer: 201.06
|
97
|
+
< Exiting Zero Shot#run
|
98
|
+
201.06
|
99
|
+
```
|
26
100
|
|
27
101
|
## Development
|
28
102
|
|
data/Rakefile
CHANGED
@@ -10,3 +10,10 @@ require "rubocop/rake_task"
|
|
10
10
|
RuboCop::RakeTask.new
|
11
11
|
|
12
12
|
task default: %i[spec rubocop]
|
13
|
+
|
14
|
+
require 'github_changelog_generator/task'
|
15
|
+
|
16
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
17
|
+
config.user = 'BoxcarsAI'
|
18
|
+
config.project = 'boxcars'
|
19
|
+
end
|
data/boxcars.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.email = ["hi@boxcars.ai"]
|
10
10
|
|
11
11
|
spec.summary = "Boxcars provide an API to connect together Boxcars and then conduct them. Inspired by python langchain."
|
12
|
-
spec.description = "You simply give a number of boxcars to a
|
12
|
+
spec.description = "You simply give a number of boxcars to a train, and it does the magic."
|
13
13
|
spec.homepage = "https://github.com/BoxcarsAI/boxcars"
|
14
14
|
spec.license = "MIT"
|
15
15
|
spec.required_ruby_version = ">= 2.6.0"
|
@@ -4,15 +4,15 @@
|
|
4
4
|
module Boxcars
|
5
5
|
# A Boxcar that interprets a prompt and executes ruby code to do math
|
6
6
|
class Calculator < EngineBoxcar
|
7
|
+
# the description of this engine boxcar
|
7
8
|
CALCDESC = "useful for when you need to answer questions about math"
|
8
9
|
attr_accessor :input_key
|
9
10
|
|
10
|
-
# @param
|
11
|
-
# @param
|
12
|
-
# @param description [String] A description of the boxcar.
|
13
|
-
# @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a conductor if nil.
|
11
|
+
# @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
|
12
|
+
# @param prompt [Boxcars::Prompt] The prompt to use for this boxcar. Defaults to built-in prompt.
|
14
13
|
# @param input_key [Symbol] The key to use for the input. Defaults to :question.
|
15
14
|
# @param output_key [Symbol] The key to use for the output. Defaults to :answer.
|
15
|
+
# @param kwargs [Hash] Any other keyword arguments to pass to the parent class.
|
16
16
|
def initialize(engine: nil, prompt: nil, input_key: :question, output_key: :answer, **kwargs)
|
17
17
|
# def initialize(engine:, prompt: my_prompt, input_key: :question, output_key: :answer, **kwargs)
|
18
18
|
@input_key = input_key
|
@@ -24,14 +24,19 @@ module Boxcars
|
|
24
24
|
output_key: output_key)
|
25
25
|
end
|
26
26
|
|
27
|
+
# the prompt input keys
|
27
28
|
def input_keys
|
28
29
|
[input_key]
|
29
30
|
end
|
30
31
|
|
32
|
+
# the output keys
|
31
33
|
def output_keys
|
32
34
|
[output_key]
|
33
35
|
end
|
34
36
|
|
37
|
+
# call the calculator
|
38
|
+
# @param inputs [Hash] The inputs to the boxcar.
|
39
|
+
# @return [Hash] The outputs from the boxcar.
|
35
40
|
def call(inputs:)
|
36
41
|
t = predict(question: inputs[input_key], stop: ["```output"]).strip
|
37
42
|
answer = get_answer(t)
|
@@ -58,7 +63,9 @@ module Boxcars
|
|
58
63
|
end
|
59
64
|
end
|
60
65
|
|
61
|
-
|
66
|
+
# our template
|
67
|
+
# rubocop:disable Style/RedundantHeredocDelimiterQuotes
|
68
|
+
TEMPLATE = <<~'IPT'
|
62
69
|
You are GPT-3, and you can't do math.
|
63
70
|
You can do basic math, and your memorization abilities are impressive, but you can't do any complex calculations that a human could not do in their head. You also have an annoying tendency to just make up highly specific, but wrong, answers.
|
64
71
|
So we hooked you up to a Ruby 3 kernel, and now you can execute ruby code. If anyone gives you a hard math problem, just use this format and we’ll take care of the rest:
|
@@ -93,6 +100,7 @@ module Boxcars
|
|
93
100
|
|
94
101
|
Question: %<question>s
|
95
102
|
IPT
|
103
|
+
# rubocop:enable Style/RedundantHeredocDelimiterQuotes
|
96
104
|
|
97
105
|
# The prompt to use for the engine.
|
98
106
|
def my_prompt
|
@@ -3,55 +3,48 @@
|
|
3
3
|
# Boxcars is a framework for running a series of tools to get an answer to a question.
|
4
4
|
module Boxcars
|
5
5
|
# For Boxcars that use an engine to do their work.
|
6
|
-
|
7
|
-
class EngineBoxcar < Boxcars::Boxcar
|
6
|
+
class EngineBoxcar < Boxcar
|
8
7
|
attr_accessor :prompt, :engine, :output_key
|
9
8
|
|
10
9
|
# A Boxcar is a container for a single tool to run.
|
11
10
|
# @param prompt [Boxcars::Prompt] The prompt to use for this boxcar with sane defaults.
|
12
11
|
# @param name [String] The name of the boxcar. Defaults to classname.
|
13
12
|
# @param description [String] A description of the boxcar.
|
14
|
-
# @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a
|
15
|
-
def initialize(prompt:, engine
|
13
|
+
# @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
|
14
|
+
def initialize(prompt:, engine: nil, output_key: "text", name: nil, description: nil)
|
16
15
|
@prompt = prompt
|
17
|
-
@engine = engine
|
16
|
+
@engine = engine || Boxcars.default_engine.new
|
18
17
|
@output_key = output_key
|
19
18
|
super(name: name, description: description)
|
20
19
|
end
|
21
20
|
|
21
|
+
# input keys for the prompt
|
22
22
|
def input_keys
|
23
23
|
prompt.input_variables
|
24
24
|
end
|
25
25
|
|
26
|
+
# output keys
|
26
27
|
def output_keys
|
27
28
|
[output_key]
|
28
29
|
end
|
29
30
|
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# raise Boxcars::ArgumentError, "Missing some input keys: #{missing_keys}" if missing_keys.any?
|
34
|
-
|
35
|
-
# inputs
|
36
|
-
# end
|
37
|
-
|
38
|
-
# def validate_outputs(outputs:)
|
39
|
-
# return if outputs.sort == output_keys.sort
|
40
|
-
|
41
|
-
# raise Boxcars::ArgumentError, "Did not get out keys that were expected, got: #{outputs}. Expected: #{output_keys}"
|
42
|
-
# end
|
43
|
-
|
31
|
+
# generate a response from the engine
|
32
|
+
# @param input_list [Array<Hash>] A list of hashes of input values to use for the prompt.
|
33
|
+
# @return [Boxcars::EngineResult] The result from the engine.
|
44
34
|
def generate(input_list:)
|
45
35
|
stop = input_list[0][:stop]
|
46
36
|
prompts = []
|
47
37
|
input_list.each do |inputs|
|
48
38
|
new_prompt = prompt.format(**inputs)
|
49
|
-
puts "Prompt after formatting:\n#{new_prompt.colorize(:cyan)}"
|
39
|
+
puts "Prompt after formatting:\n#{new_prompt.colorize(:cyan)}" if Boxcars.configuration.log_prompts
|
50
40
|
prompts.push(new_prompt)
|
51
41
|
end
|
52
42
|
engine.generate(prompts: prompts, stop: stop)
|
53
43
|
end
|
54
44
|
|
45
|
+
# apply a response from the engine
|
46
|
+
# @param input_list [Array<Hash>] A list of hashes of input values to use for the prompt.
|
47
|
+
# @return [Hash] A hash of the output key and the output value.
|
55
48
|
def apply(input_list:)
|
56
49
|
response = generate(input_list: input_list)
|
57
50
|
response.generations.to_h do |generation|
|
@@ -59,10 +52,16 @@ module Boxcars
|
|
59
52
|
end
|
60
53
|
end
|
61
54
|
|
55
|
+
# predict a response from the engine
|
56
|
+
# @param kwargs [Hash] A hash of input values to use for the prompt.
|
57
|
+
# @return [String] The output value.
|
62
58
|
def predict(**kwargs)
|
63
59
|
apply(input_list: [kwargs])[output_key]
|
64
60
|
end
|
65
61
|
|
62
|
+
# predict a response from the engine and parse it
|
63
|
+
# @param kwargs [Hash] A hash of input values to use for the prompt.
|
64
|
+
# @return [String] The output value.
|
66
65
|
def predict_and_parse(**kwargs)
|
67
66
|
result = predict(**kwargs)
|
68
67
|
if prompt.output_parser
|
@@ -72,6 +71,9 @@ module Boxcars
|
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
74
|
+
# apply a response from the engine and parse it
|
75
|
+
# @param input_list [Array<Hash>] A list of hashes of input values to use for the prompt.
|
76
|
+
# @return [Array<String>] The output values.
|
75
77
|
def apply_and_parse(input_list:)
|
76
78
|
result = apply(input_list: input_list)
|
77
79
|
if prompt.output_parser
|
@@ -81,6 +83,8 @@ module Boxcars
|
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
86
|
+
# check that there is exactly one output key
|
87
|
+
# @raise [Boxcars::ArgumentError] if there is not exactly one output key.
|
84
88
|
def check_output_keys
|
85
89
|
return unless output_keys.length != 1
|
86
90
|
|
data/lib/boxcars/boxcar/serp.rb
CHANGED
@@ -4,14 +4,14 @@ require 'google_search_results'
|
|
4
4
|
module Boxcars
|
5
5
|
# A Boxcar that uses the Google SerpAPI to get answers to questions.
|
6
6
|
class Serp < Boxcar
|
7
|
+
# the description of this boxcar
|
7
8
|
SERPDESC = "useful for when you need to answer questions about current events." \
|
8
9
|
"You should ask targeted questions"
|
9
10
|
|
10
11
|
# implements a boxcar that uses the Google SerpAPI to get answers to questions.
|
11
12
|
# @param name [String] The name of the boxcar. Defaults to classname.
|
12
13
|
# @param description [String] A description of the boxcar. Defaults to SERPDESC.
|
13
|
-
# @param
|
14
|
-
#
|
14
|
+
# @param serpapi_api_key [String] The API key to use for the SerpAPI. Defaults to Boxcars.configuration.serpapi_api_key.
|
15
15
|
def initialize(name: "Search", description: SERPDESC, serpapi_api_key: "not set")
|
16
16
|
super(name: name, description: description)
|
17
17
|
api_key = Boxcars.configuration.serpapi_api_key(serpapi_api_key: serpapi_api_key)
|
data/lib/boxcars/boxcar/sql.rb
CHANGED
@@ -4,16 +4,16 @@
|
|
4
4
|
module Boxcars
|
5
5
|
# A Boxcar that interprets a prompt and executes SQL code to get answers
|
6
6
|
class SQL < EngineBoxcar
|
7
|
+
# the description of this engine boxcar
|
7
8
|
SQLDESC = "useful for when you need to query a SQL database"
|
8
9
|
attr_accessor :connection, :input_key
|
9
10
|
|
10
11
|
# @param connection [ActiveRecord::Connection] The SQL connection to use for this boxcar.
|
11
|
-
# @param
|
12
|
-
# @param name [String] The name of the boxcar. Defaults to classname.
|
13
|
-
# @param description [String] A description of the boxcar.
|
14
|
-
# @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a conductor if nil.
|
12
|
+
# @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
|
15
13
|
# @param input_key [Symbol] The key to use for the input. Defaults to :question.
|
16
14
|
# @param output_key [Symbol] The key to use for the output. Defaults to :answer.
|
15
|
+
# @param kwargs [Hash] Any other keyword arguments to pass to the parent class. This can include
|
16
|
+
# :name, :description and :prompt
|
17
17
|
def initialize(connection:, engine: nil, input_key: :question, output_key: :answer, **kwargs)
|
18
18
|
@connection = connection
|
19
19
|
@input_key = input_key
|
@@ -25,14 +25,21 @@ module Boxcars
|
|
25
25
|
output_key: output_key)
|
26
26
|
end
|
27
27
|
|
28
|
+
# the input keys for the prompt
|
29
|
+
# @return [Array<Symbol>] The input keys for the prompt.
|
28
30
|
def input_keys
|
29
31
|
[input_key]
|
30
32
|
end
|
31
33
|
|
34
|
+
# the output keys for the prompt
|
35
|
+
# @return [Array<Symbol>] The output keys for the prompt.
|
32
36
|
def output_keys
|
33
37
|
[output_key]
|
34
38
|
end
|
35
39
|
|
40
|
+
# call the boxcar
|
41
|
+
# @param inputs [Hash] The inputs to the boxcar.
|
42
|
+
# @return [Hash] The outputs from the boxcar.
|
36
43
|
def call(inputs:)
|
37
44
|
t = predict(question: inputs[input_key], dialect: dialect, top_k: 5, table_info: schema, stop: ["Answer:"]).strip
|
38
45
|
answer = get_answer(t)
|
data/lib/boxcars/boxcar.rb
CHANGED
@@ -11,7 +11,7 @@ module Boxcars
|
|
11
11
|
# @param return_direct [Boolean] If true, return the output of this boxcar directly, without merging it with the inputs.
|
12
12
|
def initialize(description:, name: nil, return_direct: false)
|
13
13
|
@name = name || self.class.name
|
14
|
-
@description = description
|
14
|
+
@description = description || @name
|
15
15
|
@return_direct = return_direct
|
16
16
|
end
|
17
17
|
|
@@ -26,6 +26,8 @@ module Boxcars
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# Check that all inputs are present.
|
29
|
+
# @param inputs [Hash] The inputs.
|
30
|
+
# @raise [RuntimeError] If the inputs are not the same.
|
29
31
|
def validate_inputs(inputs:)
|
30
32
|
missing_keys = input_keys - inputs.keys
|
31
33
|
raise "Missing some input keys: #{missing_keys}" if missing_keys.any?
|
@@ -33,6 +35,9 @@ module Boxcars
|
|
33
35
|
inputs
|
34
36
|
end
|
35
37
|
|
38
|
+
# check that all outputs are present
|
39
|
+
# @param outputs [Array<String>] The output keys.
|
40
|
+
# @raise [RuntimeError] If the outputs are not the same.
|
36
41
|
def validate_outputs(outputs:)
|
37
42
|
return if outputs.sort == output_keys.sort
|
38
43
|
|
@@ -44,6 +49,28 @@ module Boxcars
|
|
44
49
|
raise NotImplementedError
|
45
50
|
end
|
46
51
|
|
52
|
+
# Apply the boxcar to a list of inputs.
|
53
|
+
# @param input_list [Array<Hash>] The list of inputs.
|
54
|
+
# @return [Array<Boxcars::Boxcar>] The list of outputs.
|
55
|
+
def apply(input_list:)
|
56
|
+
raise NotImplementedError
|
57
|
+
end
|
58
|
+
|
59
|
+
# Get an answer from the boxcar.
|
60
|
+
# @param args [Array] The positional arguments to pass to the boxcar.
|
61
|
+
# @param kwargs [Hash] The keyword arguments to pass to the boxcar.
|
62
|
+
# you can pass one or the other, but not both.
|
63
|
+
# @return [String] The answer to the question.
|
64
|
+
def run(*args, **kwargs)
|
65
|
+
puts "> Entering #{name}#run".colorize(:gray, style: :bold)
|
66
|
+
rv = do_run(*args, **kwargs)
|
67
|
+
puts "< Exiting #{name}#run".colorize(:gray, style: :bold)
|
68
|
+
rv
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# Get an answer from the boxcar.
|
47
74
|
def do_call(inputs:, return_only_outputs: false)
|
48
75
|
inputs = our_inputs(inputs)
|
49
76
|
output = nil
|
@@ -60,22 +87,6 @@ module Boxcars
|
|
60
87
|
inputs.merge(output)
|
61
88
|
end
|
62
89
|
|
63
|
-
def apply(input_list:)
|
64
|
-
input_list.map { |inputs| new(**inputs) }
|
65
|
-
end
|
66
|
-
|
67
|
-
# Get an answer from the boxcar.
|
68
|
-
# @param question [String] The question to ask the boxcar.
|
69
|
-
# @return [String] The answer to the question.
|
70
|
-
def run(*args, **kwargs)
|
71
|
-
puts "> Enterning #{name} boxcar#run".colorize(:gray, style: :bold)
|
72
|
-
rv = do_run(*args, **kwargs)
|
73
|
-
puts "< Exiting #{name} boxcar#run".colorize(:gray, style: :bold)
|
74
|
-
rv
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
90
|
def do_run(*args, **kwargs)
|
80
91
|
if kwargs.empty?
|
81
92
|
raise Boxcars::ArgumentError, "run supports only one positional argument." if args.length != 1
|