boxcars 0.1.3 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -2
- data/Gemfile.lock +1 -1
- data/README.md +29 -12
- data/boxcars.gemspec +3 -3
- data/lib/boxcars/boxcar/active_record.rb +170 -0
- data/lib/boxcars/boxcar/engine_boxcar.rb +1 -1
- data/lib/boxcars/boxcar/{serp.rb → google_search.rb} +6 -5
- data/lib/boxcars/boxcar/sql.rb +6 -19
- data/lib/boxcars/boxcar.rb +2 -1
- data/lib/boxcars/train/zero_shot.rb +4 -3
- data/lib/boxcars/train.rb +1 -1
- data/lib/boxcars/version.rb +1 -1
- data/lib/boxcars.rb +8 -5
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8eb0adb30464688c5a68391ffb19a5d08188f87283d7cf3de28b12a30b927971
|
4
|
+
data.tar.gz: 94605b14f7974159d21eb2cf219b8d4695533761084fe784419e47a04843c6c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b92e4e8c98ada38bb4acf5ed5f0bd563bcfe2ab29d9781002a585799aba35cfa82992086484886563585ad0b7a9795691f9804ef4807b58aaa29c8bea88a761
|
7
|
+
data.tar.gz: e46f9a26fad0b0eb339868daef5bd4c05d750af08277f83b4edb15839a712553584223f056dc2aa403fccb8b5292a6ea57aadf12c04595f909d561f1fbbe2995
|
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,29 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [
|
3
|
+
## [v0.1.4](https://github.com/BoxcarsAI/boxcars/tree/v0.1.4) (2023-02-22)
|
4
4
|
|
5
|
-
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.
|
5
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.3...v0.1.4)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Extend Sql concept to produce and run ActiveRecord code instead of SQL [\#9](https://github.com/BoxcarsAI/boxcars/issues/9)
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- first pass at an ActiveRecord boxcar [\#18](https://github.com/BoxcarsAI/boxcars/pull/18) ([francis](https://github.com/francis))
|
14
|
+
- change Boxcars::default\_train to Boxcars::train to improve code reada… [\#17](https://github.com/BoxcarsAI/boxcars/pull/17) ([francis](https://github.com/francis))
|
15
|
+
- rename class Serp to GoogleSearch [\#16](https://github.com/BoxcarsAI/boxcars/pull/16) ([francis](https://github.com/francis))
|
16
|
+
- Update README.md [\#15](https://github.com/BoxcarsAI/boxcars/pull/15) ([tabrez-syed](https://github.com/tabrez-syed))
|
17
|
+
|
18
|
+
## [v0.1.3](https://github.com/BoxcarsAI/boxcars/tree/v0.1.3) (2023-02-17)
|
19
|
+
|
20
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.2...v0.1.3)
|
6
21
|
|
7
22
|
**Closed issues:**
|
8
23
|
|
24
|
+
- generate changelog automatically [\#12](https://github.com/BoxcarsAI/boxcars/issues/12)
|
9
25
|
- Make sure the yard docs are up to date and have coverage [\#7](https://github.com/BoxcarsAI/boxcars/issues/7)
|
26
|
+
- Name changes and code movement. [\#6](https://github.com/BoxcarsAI/boxcars/issues/6)
|
10
27
|
- Specs need environment variables to be set to run green [\#4](https://github.com/BoxcarsAI/boxcars/issues/4)
|
11
28
|
|
12
29
|
**Merged pull requests:**
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,26 @@
|
|
1
|
-
|
1
|
+
<h2 align="center">Boxcars</h2>
|
2
2
|
|
3
|
-
|
3
|
+
<h4 align="center">
|
4
|
+
<a href="https://www.boxcars.ai">Website</a> |
|
5
|
+
<a href="https://www.boxcars.ai/roadmap">Roadmap</a> |
|
6
|
+
<a href="https://www.boxcars.ai/blog">Blog</a> |
|
7
|
+
<a href="https://github.com/BoxcarsAI/boxcars/wiki">Documentation</a>
|
8
|
+
</h4>
|
4
9
|
|
5
|
-
|
10
|
+
<p align="center">
|
11
|
+
<a href="https://github.com/BoxcarsAI/boxcars/blob/main/LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-informational" alt="License"></a>
|
12
|
+
</p>
|
13
|
+
|
14
|
+
Boxcars is a gem that enables you to create new systems with AI composability, using various concepts such as OpenAI, Search, SQL, Rails Active Record and more. This can even be extended with your concepts as well.(including your concepts).
|
15
|
+
|
16
|
+
This gem was inspired by the popular Python library Langchain. However, we wanted to give it a Ruby spin and make it more user-friendly for beginners to get started.
|
6
17
|
|
7
18
|
## Concepts
|
8
19
|
All of these concepts are in a module named Boxcars:
|
9
|
-
- Prompt:
|
10
|
-
- Engine: an entity that generates text from a Prompt.
|
11
|
-
- Boxcar: an encapsulation that
|
12
|
-
- Train:
|
20
|
+
- Prompt: used by an Engine to generate text results.
|
21
|
+
- Engine: an entity that generates text from a Prompt. OpenAI's LLM text generatory is the default Engine if no other is specified.
|
22
|
+
- Boxcar: an encapsulation of a concept that performs something of interest (such as search, math, or SQL). A can use an Engine to do its work.
|
23
|
+
- Train: Given a list of Boxcars and an 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, and you can either construct it directly or use `Boxcars::train` when you want to build a Train.
|
13
24
|
|
14
25
|
## Installation
|
15
26
|
|
@@ -29,7 +40,7 @@ Or install it yourself as:
|
|
29
40
|
|
30
41
|
## Usage
|
31
42
|
|
32
|
-
We will
|
43
|
+
We will be adding more examples soon, but here are a couple to get you started. First, you'll need to set up your environment variables for OpenAI and Google SERP (OPENAI_ACCESS_TOKEN, SERPAPI_API_KEY). If you prefer not to set these variables in your environment, you can pass them directly into the API.
|
33
44
|
|
34
45
|
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
46
|
```ruby
|
@@ -37,6 +48,11 @@ require "dotenv/load"
|
|
37
48
|
require "boxcars"
|
38
49
|
```
|
39
50
|
|
51
|
+
Note: if you want to try out the examples below, run this command and then paste in the code segments of interest:
|
52
|
+
```bash
|
53
|
+
irb -r dotenv/load -r boxcars
|
54
|
+
```
|
55
|
+
|
40
56
|
### Direct Boxcar Use
|
41
57
|
|
42
58
|
```ruby
|
@@ -45,7 +61,7 @@ engine = Boxcars::Openai.new(max_tokens: 256)
|
|
45
61
|
calc = Boxcars::Calculator.new(engine: engine)
|
46
62
|
puts calc.run "what is pi to the forth power divided by 22.1?"
|
47
63
|
```
|
48
|
-
|
64
|
+
Produces:
|
49
65
|
```text
|
50
66
|
> Entering Calculator#run
|
51
67
|
what is pi to the forth power divided by 22.1?
|
@@ -63,10 +79,11 @@ Note that since Openai is currently the most used Engine, if you do not pass in
|
|
63
79
|
calc = Boxcars::Calculator.new # just use the default Engine
|
64
80
|
puts calc.run "what is pi to the forth power divided by 22.1?"
|
65
81
|
```
|
82
|
+
You can change the default_engine with `Boxcars::configuration.default_engine = NewDefaultEngine`
|
66
83
|
### Boxcars currently implemmented
|
67
84
|
|
68
85
|
Here is what we have so far, but please put up a PR with your new ideas.
|
69
|
-
-
|
86
|
+
- GoogleSearch: uses the SERP API to do seaches
|
70
87
|
- Calculator: uses an Engine to generate ruby code to do math
|
71
88
|
- SQL: given an ActiveRecord connection, it will generate and run sql statments from a prompt.
|
72
89
|
|
@@ -74,10 +91,10 @@ Here is what we have so far, but please put up a PR with your new ideas.
|
|
74
91
|
```ruby
|
75
92
|
# run a Train for a calculator, and search using default Engine
|
76
93
|
boxcars = [Boxcars::Calculator.new, Boxcars::Serp.new]
|
77
|
-
train = Boxcars.
|
94
|
+
train = Boxcars.train.new(boxcars: boxcars)
|
78
95
|
puts train.run "What is pi times the square root of the average temperature in Austin TX in January?"
|
79
96
|
```
|
80
|
-
|
97
|
+
Produces:
|
81
98
|
```text
|
82
99
|
> Entering Zero Shot#run
|
83
100
|
What is pi times the square root of the average temperature in Austin TX in January?
|
data/boxcars.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Francis Sullivan", "Tabrez Syed"]
|
9
9
|
spec.email = ["hi@boxcars.ai"]
|
10
10
|
|
11
|
-
spec.summary = "Boxcars
|
12
|
-
spec.description = "You simply give a number of
|
11
|
+
spec.summary = "Boxcars is a gem that enables you to create new systems with AI composability. Inspired by python langchain."
|
12
|
+
spec.description = "You simply set an OpenAI key, give a number of Boxcars to a Train, and magic ensues when you run it."
|
13
13
|
spec.homepage = "https://github.com/BoxcarsAI/boxcars"
|
14
14
|
spec.license = "MIT"
|
15
15
|
spec.required_ruby_version = ">= 2.6.0"
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
24
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
25
|
`git ls-files -z`.split("\x0").reject do |f|
|
26
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
26
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features|notebooks)/|\.(?:git|travis|circleci)|appveyor)})
|
27
27
|
end
|
28
28
|
end
|
29
29
|
spec.bindir = "exe"
|
@@ -0,0 +1,170 @@
|
|
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 SQL code to get answers
|
6
|
+
class ActiveRecord < EngineBoxcar
|
7
|
+
# the description of this engine boxcar
|
8
|
+
ARDESC = "useful for when you need to query a database for an application named %<name>s."
|
9
|
+
LOCKED_OUT_MODELS = %w[ActiveRecord::SchemaMigration ActiveRecord::InternalMetadata ApplicationRecord].freeze
|
10
|
+
attr_accessor :connection, :input_key, :requested_models, :read_only
|
11
|
+
attr_reader :except_models
|
12
|
+
|
13
|
+
# @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
|
14
|
+
# @param models [Array<ActiveRecord::Model>] The models to use for this boxcar. Will use all if nil.
|
15
|
+
# @param read_only [Boolean] Whether to use read only models. Defaults to true.
|
16
|
+
# @param kwargs [Hash] Any other keyword arguments. These can include:
|
17
|
+
# :name, :description, :prompt, :input_key, :output_key and :except_models
|
18
|
+
def initialize(engine: nil, models: nil, read_only: true, **kwargs)
|
19
|
+
check_models(models)
|
20
|
+
@except_models = LOCKED_OUT_MODELS + kwargs[:except_models].to_a
|
21
|
+
@read_only = read_only
|
22
|
+
@input_key = kwargs[:input_key] || :question
|
23
|
+
@output_key = kwargs[:output_key] || :answer
|
24
|
+
the_prompt = kwargs[prompt] || my_prompt
|
25
|
+
name = kwargs[:name] || "Data"
|
26
|
+
super(name: name,
|
27
|
+
description: kwargs[:description] || format(ARDESC, name: name),
|
28
|
+
engine: engine,
|
29
|
+
prompt: the_prompt,
|
30
|
+
output_key: output_key)
|
31
|
+
end
|
32
|
+
|
33
|
+
# the input keys for the prompt
|
34
|
+
# @return [Array<Symbol>] The input keys for the prompt.
|
35
|
+
def input_keys
|
36
|
+
[input_key]
|
37
|
+
end
|
38
|
+
|
39
|
+
# the output keys for the prompt
|
40
|
+
# @return [Array<Symbol>] The output keys for the prompt.
|
41
|
+
def output_keys
|
42
|
+
[output_key]
|
43
|
+
end
|
44
|
+
|
45
|
+
# call the boxcar
|
46
|
+
# @param inputs [Hash] The inputs to the boxcar.
|
47
|
+
# @return [Hash] The outputs from the boxcar.
|
48
|
+
def call(inputs:)
|
49
|
+
t = predict(question: inputs[input_key], top_k: 5, model_info: model_info, stop: ["Answer:"]).strip
|
50
|
+
answer = get_answer(t)
|
51
|
+
puts answer.colorize(:magenta)
|
52
|
+
{ output_key => answer }
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def read_only?
|
58
|
+
read_only
|
59
|
+
end
|
60
|
+
|
61
|
+
def check_models(models)
|
62
|
+
if models.is_a?(Array) && models.length.positive?
|
63
|
+
@requested_models = models
|
64
|
+
models.each do |m|
|
65
|
+
raise ArgumentError, "model #{m} needs to be an Active Record model" unless m.ancestors.include?(::ActiveRecord::Base)
|
66
|
+
end
|
67
|
+
elsif models
|
68
|
+
raise ArgumentError, "models needs to be an array of Active Record models"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def wanted_models
|
73
|
+
the_models = requested_models || ::ActiveRecord::Base.descendants
|
74
|
+
the_models.reject { |m| except_models.include?(m.name) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def models
|
78
|
+
models = wanted_models.map(&:name)
|
79
|
+
models.join(", ")
|
80
|
+
end
|
81
|
+
|
82
|
+
def model_info
|
83
|
+
models = wanted_models
|
84
|
+
models.pretty_inspect
|
85
|
+
end
|
86
|
+
|
87
|
+
# to be safe, we wrap the code in a transaction and rollback
|
88
|
+
# rubocop:disable Lint/SuppressedException
|
89
|
+
def wrap_in_transaction
|
90
|
+
::ActiveRecord::Base.transaction do
|
91
|
+
yield
|
92
|
+
ensure
|
93
|
+
raise ::ActiveRecord::Rollback
|
94
|
+
end
|
95
|
+
rescue ::ActiveRecord::Rollback
|
96
|
+
end
|
97
|
+
# rubocop:enable Lint/SuppressedException
|
98
|
+
|
99
|
+
def safe_to_run?(code)
|
100
|
+
return true unless read_only?
|
101
|
+
|
102
|
+
bad_words = %w[delete delete_all destroy destroy_all update update_all upsert upsert_all create save insert drop alter
|
103
|
+
truncate revoke commit rollback reset execute].freeze
|
104
|
+
without_strings = code.gsub(/('([^'\\]*(\\.[^'\\]*)*)'|"([^"\\]*(\\.[^"\\]*)*"))/, 'XX')
|
105
|
+
word_list = without_strings.split(/[.,()]/)
|
106
|
+
|
107
|
+
bad_words.each do |w|
|
108
|
+
if word_list.include?(w)
|
109
|
+
puts "code included destructive instruction: #{w} #{code}"
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
def get_active_record_answer(text)
|
118
|
+
code = text[/^ARCode: (.*)/, 1]
|
119
|
+
puts code.colorize(:yellow)
|
120
|
+
raise SecurityError, "Can not run code that makes changes in read-only mode" unless safe_to_run?(code)
|
121
|
+
|
122
|
+
# rubocop:disable Security/Eval
|
123
|
+
output = eval code
|
124
|
+
# rubocop:enable Security/Eval
|
125
|
+
output = 0 if output.is_a?(Array) && output.empty?
|
126
|
+
output = output.first if output.is_a?(Array) && output.length == 1
|
127
|
+
"Answer: #{output.inspect}"
|
128
|
+
rescue StandardError => e
|
129
|
+
"Error: #{e.message}"
|
130
|
+
end
|
131
|
+
|
132
|
+
def get_answer(text)
|
133
|
+
case text
|
134
|
+
when /^ARCode:/
|
135
|
+
get_active_record_answer(text)
|
136
|
+
when /^Answer:/
|
137
|
+
text
|
138
|
+
else
|
139
|
+
raise Boxcars::Error "Unknown format from engine: #{text}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
TEMPLATE = <<~IPT
|
144
|
+
Given an input question, first create a syntactically correct Rails Active Record code to run,
|
145
|
+
then look at the results of the code and return the answer. Unless the user specifies
|
146
|
+
in her question a specific number of examples she wishes to obtain, limit your code
|
147
|
+
to at most %<top_k>s results.
|
148
|
+
|
149
|
+
Never query for all the columns from a specific model, only ask for a the few relevant attributes given the question.
|
150
|
+
|
151
|
+
Pay attention to use only the attribute names that you can see in the model description. Be careful to not query for attributes that do not exist.
|
152
|
+
Also, pay attention to which attribute is in which model.
|
153
|
+
|
154
|
+
Use the following format:
|
155
|
+
Question: "Question here"
|
156
|
+
ARCode: "Active Record code to run"
|
157
|
+
Answer: "Final answer here"
|
158
|
+
|
159
|
+
Only use the following Active Record models:
|
160
|
+
%<model_info>s
|
161
|
+
|
162
|
+
Question: %<question>s
|
163
|
+
IPT
|
164
|
+
|
165
|
+
# The prompt to use for the engine.
|
166
|
+
def my_prompt
|
167
|
+
@my_prompt ||= Prompt.new(input_variables: [:question, :top_k, :model_info], template: TEMPLATE)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -13,7 +13,7 @@ module Boxcars
|
|
13
13
|
# @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
|
14
14
|
def initialize(prompt:, engine: nil, output_key: "text", name: nil, description: nil)
|
15
15
|
@prompt = prompt
|
16
|
-
@engine = engine || Boxcars.
|
16
|
+
@engine = engine || Boxcars.engine.new
|
17
17
|
@output_key = output_key
|
18
18
|
super(name: name, description: description)
|
19
19
|
end
|
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'google_search_results'
|
4
4
|
module Boxcars
|
5
|
-
# A Boxcar that uses the Google
|
6
|
-
|
5
|
+
# A Boxcar that uses the Google SERP API to get answers to questions.
|
6
|
+
# It looks through SERP (search engine results page) results to find the answer.
|
7
|
+
class GoogleSearch < Boxcar
|
7
8
|
# the description of this boxcar
|
8
9
|
SERPDESC = "useful for when you need to answer questions about current events." \
|
9
10
|
"You should ask targeted questions"
|
@@ -15,14 +16,14 @@ module Boxcars
|
|
15
16
|
def initialize(name: "Search", description: SERPDESC, serpapi_api_key: "not set")
|
16
17
|
super(name: name, description: description)
|
17
18
|
api_key = Boxcars.configuration.serpapi_api_key(serpapi_api_key: serpapi_api_key)
|
18
|
-
GoogleSearch.api_key = api_key
|
19
|
+
::GoogleSearch.api_key = api_key
|
19
20
|
end
|
20
21
|
|
21
22
|
# Get an answer from Google using the SerpAPI.
|
22
23
|
# @param question [String] The question to ask Google.
|
23
24
|
# @return [String] The answer to the question.
|
24
25
|
def run(question)
|
25
|
-
search = GoogleSearch.new(q: question)
|
26
|
+
search = ::GoogleSearch.new(q: question)
|
26
27
|
rv = find_answer(search.get_hash)
|
27
28
|
puts "Question: #{question}"
|
28
29
|
puts "Answer: #{rv}"
|
@@ -33,7 +34,7 @@ module Boxcars
|
|
33
34
|
# @param question [String] The question to ask Google.
|
34
35
|
# @return [String] The location found.
|
35
36
|
def get_location(question)
|
36
|
-
search = GoogleSearch.new(q: question, limit: 3)
|
37
|
+
search = ::GoogleSearch.new(q: question, limit: 3)
|
37
38
|
rv = search.get_location
|
38
39
|
puts "Question: #{question}"
|
39
40
|
puts "Answer: #{rv}"
|
data/lib/boxcars/boxcar/sql.rb
CHANGED
@@ -5,7 +5,7 @@ module Boxcars
|
|
5
5
|
# A Boxcar that interprets a prompt and executes SQL code to get answers
|
6
6
|
class SQL < EngineBoxcar
|
7
7
|
# the description of this engine boxcar
|
8
|
-
SQLDESC = "useful for when you need to query a
|
8
|
+
SQLDESC = "useful for when you need to query a database for %<name>s."
|
9
9
|
attr_accessor :connection, :input_key
|
10
10
|
|
11
11
|
# @param connection [ActiveRecord::Connection] The SQL connection to use for this boxcar.
|
@@ -14,12 +14,13 @@ module Boxcars
|
|
14
14
|
# @param output_key [Symbol] The key to use for the output. Defaults to :answer.
|
15
15
|
# @param kwargs [Hash] Any other keyword arguments to pass to the parent class. This can include
|
16
16
|
# :name, :description and :prompt
|
17
|
-
def initialize(connection
|
18
|
-
@connection = connection
|
17
|
+
def initialize(connection: nil, engine: nil, input_key: :question, output_key: :answer, **kwargs)
|
18
|
+
@connection = connection || ::ActiveRecord::Base.connection
|
19
19
|
@input_key = input_key
|
20
20
|
the_prompt = kwargs[prompt] || my_prompt
|
21
|
-
|
22
|
-
|
21
|
+
name = kwargs[:name] || "data"
|
22
|
+
super(name: name,
|
23
|
+
description: kwargs[:description] || format(SQLDESC, name: name),
|
23
24
|
engine: engine,
|
24
25
|
prompt: the_prompt,
|
25
26
|
output_key: output_key)
|
@@ -73,7 +74,6 @@ module Boxcars
|
|
73
74
|
code = text[/^SQLQuery: (.*)/, 1]
|
74
75
|
puts code.colorize(:yellow)
|
75
76
|
output = connection.exec_query(code).to_a
|
76
|
-
puts "Answer: #{output}"
|
77
77
|
"Answer: #{output}"
|
78
78
|
end
|
79
79
|
|
@@ -116,18 +116,5 @@ module Boxcars
|
|
116
116
|
def my_prompt
|
117
117
|
@my_prompt ||= Prompt.new(input_variables: [:question, :dialect, :top_k], template: TEMPLATE)
|
118
118
|
end
|
119
|
-
|
120
|
-
# DECIDER_TEMPLATE = <<~DPT
|
121
|
-
# Given the below input question and list of potential tables, output a comma separated list of the table names that may
|
122
|
-
# be necessary to answer this question.
|
123
|
-
# Question: %<query>s
|
124
|
-
# Table Names: %<table_names>s
|
125
|
-
# Relevant Table Names:
|
126
|
-
# DPT
|
127
|
-
# DECIDER_PROMPT = Prompt.new(
|
128
|
-
# input_variables: %i[query table_names],
|
129
|
-
# template: DECIDER_TEMPLATE,
|
130
|
-
# output_parser: CommaSeparatedListOutputParser
|
131
|
-
# )
|
132
119
|
end
|
133
120
|
end
|
data/lib/boxcars/boxcar.rb
CHANGED
@@ -33,14 +33,15 @@ module Boxcars
|
|
33
33
|
# @param engine [Boxcars::Engine] The engine to use for this train.
|
34
34
|
# @param name [String] The name of the train. Defaults to 'Zero Shot'.
|
35
35
|
# @param description [String] The description of the train. Defaults to 'Zero Shot Train'.
|
36
|
-
|
36
|
+
# @param prompt [Boxcars::Prompt] The prompt to use. Defaults to the built-in prompt.
|
37
|
+
def initialize(boxcars:, engine: nil, name: 'Zero Shot', description: 'Zero Shot Train', prompt: nil)
|
37
38
|
@observation_prefix = 'Observation: '
|
38
39
|
@engine_prefix = 'Thought:'
|
39
|
-
prompt
|
40
|
+
prompt ||= self.class.create_prompt(boxcars: boxcars)
|
40
41
|
super(engine: engine, boxcars: boxcars, prompt: prompt, name: name, description: description)
|
41
42
|
end
|
42
43
|
|
43
|
-
# Create prompt in the style of the zero shot agent.
|
44
|
+
# Create prompt in the style of the zero shot agent. Without arguments, returns the default prompt.
|
44
45
|
# @param boxcars [Array<Boxcars::Boxcar>] List of boxcars the agent will have access to, used to format the prompt.
|
45
46
|
# @param prefix [String] String to put before the main prompt.
|
46
47
|
# @param suffix [String] String to put after the main prompt.
|
data/lib/boxcars/train.rb
CHANGED
@@ -205,7 +205,7 @@ module Boxcars
|
|
205
205
|
observation = "#{output.boxcar} is not a valid boxcar, try another one."
|
206
206
|
return_direct = false
|
207
207
|
end
|
208
|
-
puts "
|
208
|
+
puts "Observation: #{observation}".colorize(:green)
|
209
209
|
intermediate_steps.append([output, observation])
|
210
210
|
if return_direct
|
211
211
|
output = TrainFinish.new({ return_values[0] => observation }, "")
|
data/lib/boxcars/version.rb
CHANGED
data/lib/boxcars.rb
CHANGED
@@ -16,6 +16,9 @@ module Boxcars
|
|
16
16
|
# Error class for all Boxcars value errors.
|
17
17
|
class ValueError < Error; end
|
18
18
|
|
19
|
+
# Error class for all Boxcars security errors.
|
20
|
+
class SecurityError < Error; end
|
21
|
+
|
19
22
|
# simple string colorization
|
20
23
|
class ::String
|
21
24
|
# colorize a string
|
@@ -36,7 +39,7 @@ module Boxcars
|
|
36
39
|
# Configuration contains gem settings
|
37
40
|
class Configuration
|
38
41
|
attr_writer :openai_access_token, :serpapi_api_key
|
39
|
-
attr_accessor :organization_id, :logger, :log_prompts
|
42
|
+
attr_accessor :organization_id, :logger, :log_prompts, :default_train, :default_engine
|
40
43
|
|
41
44
|
def initialize
|
42
45
|
@organization_id = nil
|
@@ -96,13 +99,13 @@ module Boxcars
|
|
96
99
|
end
|
97
100
|
|
98
101
|
# Return the default Train class.
|
99
|
-
def self.
|
100
|
-
Boxcars::ZeroShot
|
102
|
+
def self.train
|
103
|
+
configuration.default_train || Boxcars::ZeroShot
|
101
104
|
end
|
102
105
|
|
103
106
|
# Return the default Engine class.
|
104
|
-
def self.
|
105
|
-
Boxcars::Openai
|
107
|
+
def self.engine
|
108
|
+
configuration.default_engine || Boxcars::Openai
|
106
109
|
end
|
107
110
|
end
|
108
111
|
|
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.1.
|
4
|
+
version: 0.1.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: 2023-02-
|
12
|
+
date: 2023-02-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debug
|
@@ -81,7 +81,8 @@ dependencies:
|
|
81
81
|
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '3.0'
|
84
|
-
description: You simply give a number of
|
84
|
+
description: You simply set an OpenAI key, give a number of Boxcars to a Train, and
|
85
|
+
magic ensues when you run it.
|
85
86
|
email:
|
86
87
|
- hi@boxcars.ai
|
87
88
|
executables: []
|
@@ -102,9 +103,10 @@ files:
|
|
102
103
|
- boxcars.gemspec
|
103
104
|
- lib/boxcars.rb
|
104
105
|
- lib/boxcars/boxcar.rb
|
106
|
+
- lib/boxcars/boxcar/active_record.rb
|
105
107
|
- lib/boxcars/boxcar/calculator.rb
|
106
108
|
- lib/boxcars/boxcar/engine_boxcar.rb
|
107
|
-
- lib/boxcars/boxcar/
|
109
|
+
- lib/boxcars/boxcar/google_search.rb
|
108
110
|
- lib/boxcars/boxcar/sql.rb
|
109
111
|
- lib/boxcars/engine.rb
|
110
112
|
- lib/boxcars/engine/engine_result.rb
|
@@ -143,6 +145,6 @@ requirements: []
|
|
143
145
|
rubygems_version: 3.2.32
|
144
146
|
signing_key:
|
145
147
|
specification_version: 4
|
146
|
-
summary: Boxcars
|
148
|
+
summary: Boxcars is a gem that enables you to create new systems with AI composability.
|
147
149
|
Inspired by python langchain.
|
148
150
|
test_files: []
|