boxcars 0.2.5 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +21 -1
- data/README.md +22 -18
- data/lib/boxcars/boxcar/active_record.rb +21 -4
- data/lib/boxcars/boxcar/engine_boxcar.rb +1 -1
- data/lib/boxcars/boxcar/google_search.rb +4 -4
- data/lib/boxcars/boxcar/sql.rb +4 -2
- data/lib/boxcars/boxcar/swagger.rb +80 -0
- data/lib/boxcars/boxcar/wikipedia_search.rb +39 -0
- data/lib/boxcars/boxcar.rb +6 -1
- data/lib/boxcars/ruby_repl.rb +1 -0
- data/lib/boxcars/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c58233487372c9e99f160786cc18f8e5464262479110ae2fcf2048fc09f3b338
|
4
|
+
data.tar.gz: 237d72649f3faef07c493e93f514077afd144578782fc8861f5a0b0b40152828
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3c148dc072fea12862849183bfc37f4189639982e8a7409afab267aa22baed5b911dff223562705be42c5d57e06e76e6e8814b5366c120444fca529fe204187
|
7
|
+
data.tar.gz: acec67f2d4b5be3b660c2c6e8d90ef772925903f053f0a62965fc61f335a4fc84bbeee47265c49a596945e846d31ecad3b5a93602521037f91ed689c402712d8
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [Unreleased](https://github.com/BoxcarsAI/boxcars/tree/HEAD)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.2.5...HEAD)
|
6
|
+
|
7
|
+
**Closed issues:**
|
8
|
+
|
9
|
+
- The class name in the sample code of BoxCar-Google-Search wiki has not been changed. [\#50](https://github.com/BoxcarsAI/boxcars/issues/50)
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- Add Swagger Boxcar [\#51](https://github.com/BoxcarsAI/boxcars/pull/51) ([francis](https://github.com/francis))
|
14
|
+
- Boxcars::SQL tables and except\_tables [\#47](https://github.com/BoxcarsAI/boxcars/pull/47) ([arihh](https://github.com/arihh))
|
15
|
+
- ActiveRecord updates and new Wikipedia Search boxcar [\#46](https://github.com/BoxcarsAI/boxcars/pull/46) ([francis](https://github.com/francis))
|
16
|
+
- Fix README.md log\_prompts settings [\#45](https://github.com/BoxcarsAI/boxcars/pull/45) ([arihh](https://github.com/arihh))
|
17
|
+
- Update README.md to use the GoogleSearch Boxcar [\#44](https://github.com/BoxcarsAI/boxcars/pull/44) ([stockandawe](https://github.com/stockandawe))
|
18
|
+
|
19
|
+
## [v0.2.5](https://github.com/BoxcarsAI/boxcars/tree/v0.2.5) (2023-03-30)
|
20
|
+
|
21
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.2.4...v0.2.5)
|
22
|
+
|
23
|
+
**Merged pull requests:**
|
24
|
+
|
25
|
+
- switch to safe level 4 for eval, and rerun tests [\#43](https://github.com/BoxcarsAI/boxcars/pull/43) ([francis](https://github.com/francis))
|
26
|
+
|
3
27
|
## [v0.2.4](https://github.com/BoxcarsAI/boxcars/tree/v0.2.4) (2023-03-28)
|
4
28
|
|
5
29
|
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.2.3...v0.2.4)
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
boxcars (0.2.
|
4
|
+
boxcars (0.2.7)
|
5
5
|
google_search_results (~> 2.2)
|
6
6
|
ruby-openai (~> 3.0)
|
7
7
|
|
@@ -49,6 +49,8 @@ GEM
|
|
49
49
|
irb (>= 1.5.0)
|
50
50
|
reline (>= 0.3.1)
|
51
51
|
diff-lcs (1.5.0)
|
52
|
+
domain_name (0.5.20190701)
|
53
|
+
unf (>= 0.0.5, < 1.0.0)
|
52
54
|
dotenv (2.8.1)
|
53
55
|
faraday (2.7.4)
|
54
56
|
faraday-net_http (>= 2.0, < 3.1)
|
@@ -70,6 +72,9 @@ GEM
|
|
70
72
|
rake (>= 10.0)
|
71
73
|
google_search_results (2.2.0)
|
72
74
|
hashdiff (1.0.1)
|
75
|
+
http-accept (1.7.0)
|
76
|
+
http-cookie (1.0.5)
|
77
|
+
domain_name (~> 0.5)
|
73
78
|
httparty (0.21.0)
|
74
79
|
mini_mime (>= 1.0.0)
|
75
80
|
multi_xml (>= 0.5.2)
|
@@ -81,11 +86,15 @@ GEM
|
|
81
86
|
reline (>= 0.3.0)
|
82
87
|
json (2.6.3)
|
83
88
|
json (2.6.3-java)
|
89
|
+
mime-types (3.4.1)
|
90
|
+
mime-types-data (~> 3.2015)
|
91
|
+
mime-types-data (3.2023.0218.1)
|
84
92
|
mini_mime (1.1.2)
|
85
93
|
mini_portile2 (2.8.1)
|
86
94
|
minitest (5.18.0)
|
87
95
|
multi_json (1.15.0)
|
88
96
|
multi_xml (0.6.0)
|
97
|
+
netrc (0.11.0)
|
89
98
|
nio4r (2.5.8)
|
90
99
|
nio4r (2.5.8-java)
|
91
100
|
octokit (4.25.1)
|
@@ -107,6 +116,11 @@ GEM
|
|
107
116
|
regexp_parser (2.7.0)
|
108
117
|
reline (0.3.3)
|
109
118
|
io-console (~> 0.5)
|
119
|
+
rest-client (2.1.0)
|
120
|
+
http-accept (>= 1.7.0, < 2.0)
|
121
|
+
http-cookie (>= 1.0.2, < 2.0)
|
122
|
+
mime-types (>= 1.16, < 4.0)
|
123
|
+
netrc (~> 0.8)
|
110
124
|
rexml (3.2.5)
|
111
125
|
rspec (3.12.0)
|
112
126
|
rspec-core (~> 3.12.0)
|
@@ -155,6 +169,10 @@ GEM
|
|
155
169
|
traces (0.9.1)
|
156
170
|
tzinfo (2.0.6)
|
157
171
|
concurrent-ruby (~> 1.0)
|
172
|
+
unf (0.1.4)
|
173
|
+
unf_ext
|
174
|
+
unf (0.1.4-java)
|
175
|
+
unf_ext (0.0.8.2)
|
158
176
|
unicode-display_width (2.4.2)
|
159
177
|
vcr (6.1.0)
|
160
178
|
webmock (3.18.1)
|
@@ -170,12 +188,14 @@ PLATFORMS
|
|
170
188
|
|
171
189
|
DEPENDENCIES
|
172
190
|
activerecord (~> 7.0)
|
191
|
+
activesupport (~> 7.0)
|
173
192
|
boxcars!
|
174
193
|
debug (~> 1.1)
|
175
194
|
dotenv (~> 2.8)
|
176
195
|
faraday-retry (~> 2.0)
|
177
196
|
github_changelog_generator (~> 1.16)
|
178
197
|
rake (~> 13.0)
|
198
|
+
rest-client (~> 2.1)
|
179
199
|
rspec (~> 3.2)
|
180
200
|
rubocop (~> 1.21)
|
181
201
|
rubocop-rake (~> 0.6.0)
|
data/README.md
CHANGED
@@ -18,10 +18,10 @@ This gem was inspired by the popular Python library Langchain. However, we wante
|
|
18
18
|
## Concepts
|
19
19
|
All of these concepts are in a module named Boxcars:
|
20
20
|
|
21
|
-
- Boxcar - an encapsulation that performs something of interest (such as search, math, SQL
|
21
|
+
- Boxcar - an encapsulation that performs something of interest (such as search, math, SQL, an Active Record Query, or an API call to a service). A Boxcar can use an Engine (described below) to do its work, and if not specified but needed, the default Engine is used `Boxcars.engine`.
|
22
22
|
- Train - Given a list of Boxcars and optionally an Engine, a Train breaks down a problem into pieces for individual Boxcars to solve. The individual results are then combined until a final answer is found. ZeroShot is the only current implementation of Train (but we are adding more soon), and you can either construct it directly or use `Boxcars::train` when you want to build a Train.
|
23
|
-
- Prompt - used by an Engine to generate text results.
|
24
|
-
- Engine - an entity that generates text from a Prompt. OpenAI's LLM text generator is the default Engine if no other is specified.
|
23
|
+
- Prompt - used by an Engine to generate text results. Our Boxcars have built-in prompts, but you have the flexibility to change or augment them if you so desire.
|
24
|
+
- Engine - an entity that generates text from a Prompt. OpenAI's LLM text generator is the default Engine if no other is specified, and you can override the default engine if so desired (`Boxcar.configuration.default_engine`).
|
25
25
|
|
26
26
|
## Security
|
27
27
|
Currently, our system is designed for individuals who already possess administrative privileges for their project. It is likely possible to manipulate the system's prompts to carry out malicious actions, but if you already have administrative access, you can perform such actions without requiring boxcars in the first place.
|
@@ -90,14 +90,16 @@ You can change the default_engine with `Boxcars::configuration.default_engine =
|
|
90
90
|
|
91
91
|
Here is what we have so far, but please put up a PR with your new ideas.
|
92
92
|
- GoogleSearch: uses the SERP API to do seaches
|
93
|
+
- WikipediaSearch: uses the Wikipedia API to do searches
|
93
94
|
- Calculator: uses an Engine to generate ruby code to do math
|
94
95
|
- SQL: given an ActiveRecord connection, it will generate and run sql statments from a prompt.
|
95
96
|
- ActiveRecord: given an ActiveRecord connection, it will generate and run ActiveRecord statements from a prompt.
|
97
|
+
- Swagger: give a Swagger Open API file (YAML or JSON), answer questions about or run against the referenced service. See [here](https://github.com/BoxcarsAI/boxcars/blob/main/notebooks/swagger_examples.ipynb) for examples.
|
96
98
|
|
97
99
|
### Run a list of Boxcars
|
98
100
|
```ruby
|
99
101
|
# run a Train for a calculator, and search using default Engine
|
100
|
-
boxcars = [Boxcars::Calculator.new, Boxcars::
|
102
|
+
boxcars = [Boxcars::Calculator.new, Boxcars::GoogleSearch.new]
|
101
103
|
train = Boxcars.train.new(boxcars: boxcars)
|
102
104
|
train.run "What is pi times the square root of the average temperature in Austin TX in January?"
|
103
105
|
```
|
@@ -105,38 +107,40 @@ Produces:
|
|
105
107
|
```text
|
106
108
|
> Entering Zero Shot#run
|
107
109
|
What is pi times the square root of the average temperature in Austin TX in January?
|
108
|
-
Thought: We need to find the average temperature in Austin TX in January and then multiply it by pi and the square root of
|
110
|
+
Thought: We need to find the average temperature in Austin TX in January and then multiply it by pi and the square root of the average temperature. We can use a search engine to find the average temperature in Austin TX in January and a calculator to perform the multiplication.
|
109
111
|
Question: Average temperature in Austin TX in January
|
110
|
-
Answer: increase from 62°F to 64°F
|
111
|
-
Observation: increase from 62°F to 64°F
|
112
|
-
Thought:
|
112
|
+
Answer: January Weather in Austin Texas, United States. Daily high temperatures increase by 2°F, from 62°F to 64°F, rarely falling below 45°F or exceeding 76° ...
|
113
|
+
Observation: January Weather in Austin Texas, United States. Daily high temperatures increase by 2°F, from 62°F to 64°F, rarely falling below 45°F or exceeding 76° ...
|
114
|
+
Thought: We have found the average temperature in Austin TX in January, which is 64°F. Now we can use a calculator to perform the multiplication.
|
113
115
|
> Entering Calculator#run
|
114
|
-
pi * sqrt(
|
115
|
-
RubyREPL: puts(Math::PI * Math.sqrt(
|
116
|
-
Answer:
|
116
|
+
pi * sqrt(64)
|
117
|
+
RubyREPL: puts(Math::PI * Math.sqrt(64))
|
118
|
+
Answer: 25.132741228718345
|
117
119
|
|
118
|
-
{"status":"ok","answer":"
|
120
|
+
{"status":"ok","answer":"25.132741228718345","explanation":"Answer: 25.132741228718345","code":"puts(Math::PI * Math.sqrt(64))"}
|
119
121
|
< Exiting Calculator#run
|
120
|
-
Observation:
|
121
|
-
|
122
|
+
Observation: 25.132741228718345
|
123
|
+
We have the final answer.
|
122
124
|
|
123
|
-
Final Answer:
|
125
|
+
Final Answer: 25.132741228718345
|
124
126
|
|
125
127
|
Next Actions:
|
126
128
|
1. What is the average temperature in Austin TX in July?
|
127
|
-
2. What is the
|
128
|
-
3. What is the
|
129
|
+
2. What is the value of pi to 10 decimal places?
|
130
|
+
3. What is the square root of the average temperature in Miami FL in January?
|
129
131
|
< Exiting Zero Shot#run
|
130
132
|
```
|
131
133
|
### More Examples
|
132
134
|
See [this](https://github.com/BoxcarsAI/boxcars/blob/main/notebooks/boxcars_examples.ipynb) Jupyter Notebook for more examples.
|
133
135
|
|
136
|
+
For the new Swagger boxcar, see [this](https://github.com/BoxcarsAI/boxcars/blob/main/notebooks/swagger_examples.ipynb) Jupyter Notebook.
|
137
|
+
|
134
138
|
Note, some folks that we talked to didn't know that you could run Ruby Jupyter notebooks. [You can](https://github.com/SciRuby/iruby).
|
135
139
|
|
136
140
|
### Logging
|
137
141
|
If you use this in a Rails application, or configure `Boxcars.configuration.logger = your_logger`, logging will go to your log file.
|
138
142
|
|
139
|
-
Also, if you set this flag: `Boxcars.configuration.
|
143
|
+
Also, if you set this flag: `Boxcars.configuration.log_prompts = true`
|
140
144
|
The actual prompts handed to the connected Engine will be logged. This is off by default because it is very wordy, but handy if you are debugging prompts.
|
141
145
|
|
142
146
|
Otherwise, we print to standard out.
|
@@ -3,6 +3,7 @@
|
|
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
|
# A Boxcar that interprets a prompt and executes SQL code to get answers
|
6
|
+
# rubocop:disable Metrics/ClassLength
|
6
7
|
class ActiveRecord < EngineBoxcar
|
7
8
|
# the description of this engine boxcar
|
8
9
|
ARDESC = "useful for when you need to query a database for an application named %<name>s."
|
@@ -21,7 +22,7 @@ module Boxcars
|
|
21
22
|
@approval_callback = approval_callback
|
22
23
|
@read_only = read_only.nil? ? !approval_callback : read_only
|
23
24
|
@code_only = kwargs.delete(:code_only) || false
|
24
|
-
kwargs[:name] ||=
|
25
|
+
kwargs[:name] ||= get_name
|
25
26
|
kwargs[:description] ||= format(ARDESC, name: name)
|
26
27
|
kwargs[:prompt] ||= my_prompt
|
27
28
|
super(**kwargs)
|
@@ -34,6 +35,13 @@ module Boxcars
|
|
34
35
|
|
35
36
|
private
|
36
37
|
|
38
|
+
def get_name
|
39
|
+
return Rails.application.class.module_parent.name if defined?(Rails)
|
40
|
+
rescue StandardError => e
|
41
|
+
boxcars.error "Error getting rails name application name: #{e.message}"
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
37
45
|
def read_only?
|
38
46
|
read_only
|
39
47
|
end
|
@@ -44,6 +52,7 @@ module Boxcars
|
|
44
52
|
|
45
53
|
def check_models(models, exceptions)
|
46
54
|
if models.is_a?(Array) && models.length.positive?
|
55
|
+
models.map { |m| m.is_a?(Class) ? m : m.constantize }
|
47
56
|
@requested_models = models
|
48
57
|
models.each do |m|
|
49
58
|
raise ArgumentError, "model #{m} needs to be an Active Record model" unless m.ancestors.include?(::ActiveRecord::Base)
|
@@ -119,7 +128,10 @@ module Boxcars
|
|
119
128
|
# @return [Object] The result of the code
|
120
129
|
def eval_safe_wrapper(code)
|
121
130
|
# if the code used ActiveRecord, we need to add :: in front of it to escape the module
|
122
|
-
new_code = code.gsub(
|
131
|
+
new_code = code.gsub(/\b(ActiveRecord::)/, '::\1')
|
132
|
+
|
133
|
+
# sometimes the code will have a puts or print in it, which will miss. Remove them.
|
134
|
+
new_code = new_code.gsub(/\b(puts|print)\b/, '')
|
123
135
|
proc do
|
124
136
|
$SAFE = 4
|
125
137
|
# rubocop:disable Security/Eval
|
@@ -146,7 +158,11 @@ module Boxcars
|
|
146
158
|
def approved?(changes_code, code)
|
147
159
|
# find out how many changes there are
|
148
160
|
changes = change_count(changes_code)
|
149
|
-
|
161
|
+
begin
|
162
|
+
return true unless changes&.positive?
|
163
|
+
rescue StandardError => e
|
164
|
+
Boscar.error "Error while computing change count: #{e.message}", :red
|
165
|
+
end
|
150
166
|
|
151
167
|
Boxcars.debug "#{name}(Pending Changes): #{changes}", :yellow
|
152
168
|
if read_only?
|
@@ -242,7 +258,7 @@ module Boxcars
|
|
242
258
|
"Pay attention to use only the attribute names that you can see in the model description.\n",
|
243
259
|
"Do not make up variable or attribute names, and do not share variables between the code in ARChanges and ARCode\n",
|
244
260
|
"Be careful to not query for attributes that do not exist, and to use the format specified above.\n",
|
245
|
-
"Finally,
|
261
|
+
"Finally, try not to use print or puts in your code"
|
246
262
|
),
|
247
263
|
user("Question: %<question>s")
|
248
264
|
].freeze
|
@@ -257,4 +273,5 @@ module Boxcars
|
|
257
273
|
output_variables: [:answer])
|
258
274
|
end
|
259
275
|
end
|
276
|
+
# rubocop:enable Metrics/ClassLength
|
260
277
|
end
|
@@ -121,7 +121,7 @@ module Boxcars
|
|
121
121
|
# @param inputs [Hash] The inputs to the boxcar.
|
122
122
|
# @return Hash The variables for this boxcar.
|
123
123
|
def prediction_variables(inputs)
|
124
|
-
|
124
|
+
prediction_additional.merge(inputs)
|
125
125
|
end
|
126
126
|
|
127
127
|
# remove backticks or triple backticks from the code
|
@@ -34,11 +34,11 @@ module Boxcars
|
|
34
34
|
# @param question [String] The question to ask Google.
|
35
35
|
# @return [String] The location found.
|
36
36
|
def get_location(question)
|
37
|
+
Boxcars.debug "Question: #{question}", :yellow
|
37
38
|
search = ::GoogleSearch.new(q: question, limit: 3)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
rv
|
39
|
+
answer = search.get_location
|
40
|
+
Boxcars.debug "Answer: #{answer}", :yellow, style: :bold
|
41
|
+
answer
|
42
42
|
end
|
43
43
|
|
44
44
|
private
|
data/lib/boxcars/boxcar/sql.rb
CHANGED
@@ -41,6 +41,8 @@ module Boxcars
|
|
41
41
|
end
|
42
42
|
elsif rtables
|
43
43
|
raise ArgumentError, "tables needs to be an array of Strings"
|
44
|
+
else
|
45
|
+
@requested_tables = tables
|
44
46
|
end
|
45
47
|
@except_models = LOCKED_OUT_TABLES + exceptions.to_a
|
46
48
|
end
|
@@ -55,8 +57,8 @@ module Boxcars
|
|
55
57
|
");"].join("\n")
|
56
58
|
end
|
57
59
|
|
58
|
-
def schema
|
59
|
-
wanted_tables =
|
60
|
+
def schema
|
61
|
+
wanted_tables = @requested_tables - @except_models
|
60
62
|
wanted_tables.map(&method(:table_schema)).join("\n")
|
61
63
|
end
|
62
64
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Boxcars is a framework for running a series of tools to get an answer to a question.
|
4
|
+
module Boxcars
|
5
|
+
# A Boxcar that interprets a prompt and executes API calls to get an answer.
|
6
|
+
class Swagger < EngineBoxcar
|
7
|
+
# the description of this engine boxcar
|
8
|
+
DESC = "useful for when you need to make Open API calls to get an answer."
|
9
|
+
|
10
|
+
attr_accessor :swagger_url, :context
|
11
|
+
|
12
|
+
# @param swagger_url [String] The URL of the Open API Swagger file to use.
|
13
|
+
# @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
|
14
|
+
# @param prompt [Boxcars::Prompt] The prompt to use for this boxcar. Defaults to built-in prompt.
|
15
|
+
# @param context [String] Additional context to use for the prompt.
|
16
|
+
# @param kwargs [Hash] Any other keyword arguments to pass to the parent class.
|
17
|
+
def initialize(swagger_url:, engine: nil, prompt: nil, context: "", **kwargs)
|
18
|
+
@swagger_url = swagger_url
|
19
|
+
@context = context
|
20
|
+
the_prompt = prompt || my_prompt
|
21
|
+
kwargs[:stop] ||= ["```output"]
|
22
|
+
kwargs[:name] ||= "Swagger API"
|
23
|
+
kwargs[:description] ||= DESC
|
24
|
+
super(engine: engine, prompt: the_prompt, **kwargs)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return Hash The additional variables for this boxcar.
|
28
|
+
def prediction_additional
|
29
|
+
{ swagger_url: swagger_url, context: context }.merge super
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def get_embedded_ruby_answer(text)
|
35
|
+
code = text.split("```ruby\n").last.split("```").first.strip
|
36
|
+
ruby_executor = Boxcars::RubyREPL.new
|
37
|
+
ruby_executor.call(code: code)
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_answer(text)
|
41
|
+
case text
|
42
|
+
when /^```ruby/
|
43
|
+
get_embedded_ruby_answer(text)
|
44
|
+
when /^Answer:/
|
45
|
+
Result.from_text(text)
|
46
|
+
else
|
47
|
+
Result.new(status: :error,
|
48
|
+
explanation: "Error: expecting your response to begin with '```ruby'. Try answering the question again.")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# our template
|
53
|
+
CTEMPLATE = [
|
54
|
+
syst("Study this Open API Swagger file %<swagger_url>s\n",
|
55
|
+
"and write a Ruby Program that prints the answer to the following questions using the appropriate API calls:\n",
|
56
|
+
"Additional context that you might need in the Ruby program: (%<context>s)\n",
|
57
|
+
"Use the following format:\n",
|
58
|
+
"${{Question needing API calls and code}}\n",
|
59
|
+
"reply only with the following format:\n",
|
60
|
+
"```ruby\n${{Ruby code with API calls and code that prints the answer}}\n```\n",
|
61
|
+
"```output\n${{Output of your code}}\n```\n\n",
|
62
|
+
"Otherwise, if you know the answer and do not need any API calls, you should use this simpler format:\n",
|
63
|
+
"${{Question not needing API calls}}\n",
|
64
|
+
"Answer: ${{Answer}}\n\n",
|
65
|
+
"Do not give an explanation of the answer and make sure your answer starts with either 'Answer:' or '```ruby'. ",
|
66
|
+
"Make use of the rest-client gem to make your requests to the API. Just print the answer."),
|
67
|
+
user("%<question>s")
|
68
|
+
].freeze
|
69
|
+
|
70
|
+
# The prompt to use for the engine.
|
71
|
+
def my_prompt
|
72
|
+
@conversation ||= Conversation.new(lines: CTEMPLATE)
|
73
|
+
@my_prompt ||= ConversationPrompt.new(
|
74
|
+
conversation: @conversation,
|
75
|
+
input_variables: [:question],
|
76
|
+
other_inputs: [:context, :swagger_url],
|
77
|
+
output_variables: [:answer])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
module Boxcars
|
5
|
+
# A Boxcar that uses the Wikipedia search API to get answers to questions.
|
6
|
+
class WikipediaSearch < Boxcar
|
7
|
+
# the description of this boxcar
|
8
|
+
WDESC = "useful for when you need to answer questions about topics from Wikipedia." \
|
9
|
+
"You should ask targeted questions"
|
10
|
+
|
11
|
+
# implements a boxcar that uses the Wikipedia Search to get answers to questions.
|
12
|
+
# @param name [String] The name of the boxcar. Defaults to classname.
|
13
|
+
# @param description [String] A description of the boxcar. Defaults to SERPDESC.
|
14
|
+
# @param serpapi_api_key [String] The API key to use for the SerpAPI. Defaults to Boxcars.configuration.serpapi_api_key.
|
15
|
+
def initialize(name: "Wikipedia", description: WDESC)
|
16
|
+
super(name: name, description: description)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Get an answer from Google using the SerpAPI.
|
20
|
+
# @param question [String] The question to ask Google.
|
21
|
+
# @return [String] The answer to the question.
|
22
|
+
def run(question)
|
23
|
+
Boxcars.debug "Question: #{question}", :yellow
|
24
|
+
uri = URI("https://en.wikipedia.org/w/api.php")
|
25
|
+
params = { action: "query", list: "search", srsearch: question, format: "json" }
|
26
|
+
uri.query = URI.encode_www_form(params)
|
27
|
+
|
28
|
+
res = Net::HTTP.get_response(uri)
|
29
|
+
raise "Error getting response from Wikipedia: #{res.body}" unless res.is_a?(Net::HTTPSuccess)
|
30
|
+
|
31
|
+
response = JSON.parse res.body
|
32
|
+
answer = response.dig("query", "search", 0, "snippet").to_s.gsub(/<[^>]*>/, "")
|
33
|
+
pageid = response.dig("query", "search", 0, "pageid")
|
34
|
+
answer = "#{answer}\nurl: https://en.wikipedia.org/?curid=#{pageid}" if pageid
|
35
|
+
Boxcars.debug "Answer: #{answer}", :yellow, style: :bold
|
36
|
+
answer
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/boxcars/boxcar.rb
CHANGED
@@ -119,7 +119,10 @@ module Boxcars
|
|
119
119
|
|
120
120
|
return run_boxcar(inputs: args[0])[output_keys.first]
|
121
121
|
end
|
122
|
-
|
122
|
+
if args.empty?
|
123
|
+
ans = run_boxcar(inputs: kwargs)
|
124
|
+
return ans[output_keys.first]
|
125
|
+
end
|
123
126
|
|
124
127
|
raise Boxcars::ArgumentError, "run supported with either positional or keyword arguments but not both. Got args" \
|
125
128
|
": #{args} and kwargs: #{kwargs}."
|
@@ -149,5 +152,7 @@ require "boxcars/result"
|
|
149
152
|
require "boxcars/boxcar/engine_boxcar"
|
150
153
|
require "boxcars/boxcar/calculator"
|
151
154
|
require "boxcars/boxcar/google_search"
|
155
|
+
require "boxcars/boxcar/wikipedia_search"
|
152
156
|
require "boxcars/boxcar/sql"
|
157
|
+
require "boxcars/boxcar/swagger"
|
153
158
|
require "boxcars/boxcar/active_record"
|
data/lib/boxcars/ruby_repl.rb
CHANGED
@@ -20,6 +20,7 @@ module Boxcars
|
|
20
20
|
Boxcars.debug output, :red
|
21
21
|
Result.from_error(output, code: code)
|
22
22
|
else
|
23
|
+
output = ::Regexp.last_match(1) if output =~ /^\s*Answer:\s*(.*)$/m
|
23
24
|
Boxcars.debug "Answer: #{output}", :yellow, style: :bold
|
24
25
|
Result.from_text(output, code: code)
|
25
26
|
end
|
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.2.
|
4
|
+
version: 0.2.7
|
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: 2023-
|
12
|
+
date: 2023-04-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debug
|
@@ -109,6 +109,8 @@ files:
|
|
109
109
|
- lib/boxcars/boxcar/engine_boxcar.rb
|
110
110
|
- lib/boxcars/boxcar/google_search.rb
|
111
111
|
- lib/boxcars/boxcar/sql.rb
|
112
|
+
- lib/boxcars/boxcar/swagger.rb
|
113
|
+
- lib/boxcars/boxcar/wikipedia_search.rb
|
112
114
|
- lib/boxcars/conversation.rb
|
113
115
|
- lib/boxcars/conversation_prompt.rb
|
114
116
|
- lib/boxcars/engine.rb
|