boxcars 0.6.8 → 0.6.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b025b4faf290736766df116e4146cdcea5285bfbd54b6b1c8eaae1e3fc220507
4
- data.tar.gz: cdc51dd2f92609b3b2d52879de4716fe8a34e20a15c9bc5d9f27c005bd5f760f
3
+ metadata.gz: a058c8e9111ba8c7b3e29d25c6f9226f87c862c4b10b26c3c05f8a69dbe7659c
4
+ data.tar.gz: 718546be88153f0f26ba932811e30fa9f8c3a467ac029a76c88d554912640b29
5
5
  SHA512:
6
- metadata.gz: 4267533089c1c3be564ac59d321a8adb670d4197d0548767be1291835049c1edf86f6994b93186d4b0c5ab49445f17d1bdba35bc3b983eafea150c0b05732775
7
- data.tar.gz: 3d37938ea2c431fe3f1b839471421fc5af46e0c60ede688265874d8b1ac93a6e58e440509a66aea4c91375986ed0295a477cca3adca75f68ffc028f33976583a
6
+ metadata.gz: baf4a36fbb72e064f110576f73945d276794b7f235935d9dc0797460ac3a641439ff29e7e650c93d468e9a70a0f148d0fabde6724cc82b7c3cd05df2020974cd
7
+ data.tar.gz: 85e40690235ed5e13daa9a326cfef6dae29cd882a18716913a264026fed46cde355ea50c01703aac26da5b77ac3aefc22eaa7eb2583b12485840b32d45f1c94b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boxcars (0.6.8)
4
+ boxcars (0.6.9)
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.2.2)
17
- activesupport (= 7.2.2)
18
- activerecord (7.2.2)
19
- activemodel (= 7.2.2)
20
- activesupport (= 7.2.2)
16
+ activemodel (7.2.2.1)
17
+ activesupport (= 7.2.2.1)
18
+ activerecord (7.2.2.1)
19
+ activemodel (= 7.2.2.1)
20
+ activesupport (= 7.2.2.1)
21
21
  timeout (>= 0.4.0)
22
- activesupport (7.2.2)
22
+ activesupport (7.2.2.1)
23
23
  base64
24
24
  benchmark (>= 0.3)
25
25
  bigdecimal
@@ -50,41 +50,43 @@ GEM
50
50
  protocol-http1 (~> 0.19.0)
51
51
  protocol-http2 (~> 0.16.0)
52
52
  traces (>= 0.10.0)
53
- async-http-faraday (0.14.0)
53
+ async-http-faraday (0.19.0)
54
54
  async-http (~> 0.42)
55
55
  faraday
56
56
  async-io (1.43.2)
57
57
  async
58
- async-pool (0.7.0)
58
+ async-pool (0.10.2)
59
59
  async (>= 1.25)
60
+ traces
60
61
  base64 (0.2.0)
61
62
  benchmark (0.4.0)
62
63
  bigdecimal (3.1.8)
63
64
  concurrent-ruby (1.3.4)
64
65
  connection_pool (2.4.1)
65
- console (1.27.0)
66
+ console (1.29.2)
66
67
  fiber-annotation
67
68
  fiber-local (~> 1.1)
68
69
  json
69
70
  crack (1.0.0)
70
71
  bigdecimal
71
72
  rexml
72
- debug (1.9.2)
73
+ date (3.4.1)
74
+ debug (1.10.0)
73
75
  irb (~> 1.10)
74
76
  reline (>= 0.3.8)
75
77
  diff-lcs (1.5.1)
76
78
  domain_name (0.6.20240107)
77
- dotenv (3.1.4)
79
+ dotenv (3.1.7)
78
80
  drb (2.2.1)
79
81
  event_stream_parser (1.0.0)
80
- faraday (2.12.1)
82
+ faraday (2.12.2)
81
83
  faraday-net_http (>= 2.0, < 3.5)
82
84
  json
83
85
  logger
84
86
  faraday-http-cache (2.5.1)
85
87
  faraday (>= 0.8)
86
- faraday-multipart (1.0.4)
87
- multipart-post (~> 2)
88
+ faraday-multipart (1.1.0)
89
+ multipart-post (~> 2.0)
88
90
  faraday-net_http (3.4.0)
89
91
  net-http (>= 0.5.0)
90
92
  faraday-retry (2.2.1)
@@ -92,7 +94,7 @@ GEM
92
94
  fiber-annotation (0.2.0)
93
95
  fiber-local (1.1.0)
94
96
  fiber-storage
95
- fiber-storage (0.1.2)
97
+ fiber-storage (1.0.0)
96
98
  github_changelog_generator (1.16.4)
97
99
  activesupport
98
100
  async (>= 1.25.0)
@@ -107,33 +109,34 @@ GEM
107
109
  faraday (~> 2.7)
108
110
  os (~> 1.1)
109
111
  tty-progressbar (~> 0.18.2)
110
- hashdiff (1.1.1)
112
+ hashdiff (1.1.2)
111
113
  hnswlib (0.9.0)
112
114
  http-accept (1.7.0)
113
- http-cookie (1.0.6)
115
+ http-cookie (1.0.8)
114
116
  domain_name (~> 0.5)
115
117
  i18n (1.14.6)
116
118
  concurrent-ruby (~> 1.0)
117
- io-console (0.7.2)
118
- irb (1.14.0)
119
+ io-console (0.8.0)
120
+ irb (1.14.3)
119
121
  rdoc (>= 4.0.0)
120
122
  reline (>= 0.4.2)
121
- json (2.9.0)
123
+ json (2.9.1)
122
124
  language_server-protocol (3.17.0.3)
123
- logger (1.6.2)
124
- mime-types (3.5.2)
125
+ logger (1.6.4)
126
+ mime-types (3.6.0)
127
+ logger
125
128
  mime-types-data (~> 3.2015)
126
- mime-types-data (3.2024.0702)
129
+ mime-types-data (3.2024.1203)
127
130
  minitest (5.25.4)
128
131
  multi_json (1.15.0)
129
132
  multipart-post (2.4.1)
130
133
  net-http (0.6.0)
131
134
  uri
132
135
  netrc (0.11.0)
133
- nio4r (2.7.3)
134
- nokogiri (1.16.8-arm64-darwin)
136
+ nio4r (2.7.4)
137
+ nokogiri (1.17.2-arm64-darwin)
135
138
  racc (~> 1.4)
136
- nokogiri (1.16.8-x86_64-linux)
139
+ nokogiri (1.17.2-x86_64-linux)
137
140
  racc (~> 1.4)
138
141
  octokit (4.25.1)
139
142
  faraday (>= 1, < 3)
@@ -145,44 +148,45 @@ GEM
145
148
  racc
146
149
  pg (1.5.9)
147
150
  pgvector (0.2.2)
148
- protocol-hpack (1.4.3)
151
+ protocol-hpack (1.5.1)
149
152
  protocol-http (0.26.8)
150
153
  protocol-http1 (0.19.1)
151
154
  protocol-http (~> 0.22)
152
155
  protocol-http2 (0.16.0)
153
156
  protocol-hpack (~> 1.4)
154
157
  protocol-http (~> 0.18)
155
- psych (5.1.2)
158
+ psych (5.2.2)
159
+ date
156
160
  stringio
157
161
  public_suffix (6.0.1)
158
162
  racc (1.8.1)
159
163
  rainbow (3.1.1)
160
164
  rake (13.2.1)
161
- rdoc (6.7.0)
165
+ rdoc (6.10.0)
162
166
  psych (>= 4.0.0)
163
167
  regexp_parser (2.9.3)
164
- reline (0.5.9)
168
+ reline (0.6.0)
165
169
  io-console (~> 0.5)
166
170
  rest-client (2.1.0)
167
171
  http-accept (>= 1.7.0, < 2.0)
168
172
  http-cookie (>= 1.0.2, < 2.0)
169
173
  mime-types (>= 1.16, < 4.0)
170
174
  netrc (~> 0.8)
171
- rexml (3.3.9)
175
+ rexml (3.4.0)
172
176
  rspec (3.13.0)
173
177
  rspec-core (~> 3.13.0)
174
178
  rspec-expectations (~> 3.13.0)
175
179
  rspec-mocks (~> 3.13.0)
176
- rspec-core (3.13.0)
180
+ rspec-core (3.13.2)
177
181
  rspec-support (~> 3.13.0)
178
- rspec-expectations (3.13.1)
182
+ rspec-expectations (3.13.3)
179
183
  diff-lcs (>= 1.2.0, < 2.0)
180
184
  rspec-support (~> 3.13.0)
181
- rspec-mocks (3.13.1)
185
+ rspec-mocks (3.13.2)
182
186
  diff-lcs (>= 1.2.0, < 2.0)
183
187
  rspec-support (~> 3.13.0)
184
- rspec-support (3.13.1)
185
- rubocop (1.69.1)
188
+ rspec-support (3.13.2)
189
+ rubocop (1.69.2)
186
190
  json (~> 2.3)
187
191
  language_server-protocol (>= 3.17.0)
188
192
  parallel (~> 1.10)
@@ -192,11 +196,11 @@ GEM
192
196
  rubocop-ast (>= 1.36.2, < 2.0)
193
197
  ruby-progressbar (~> 1.7)
194
198
  unicode-display_width (>= 2.4.0, < 4.0)
195
- rubocop-ast (1.36.2)
199
+ rubocop-ast (1.37.0)
196
200
  parser (>= 3.3.1.0)
197
201
  rubocop-rake (0.6.0)
198
202
  rubocop (~> 1.0)
199
- rubocop-rspec (3.2.0)
203
+ rubocop-rspec (3.3.0)
200
204
  rubocop (~> 1.61)
201
205
  ruby-openai (7.3.1)
202
206
  event_stream_parser (>= 0.3.0, < 2.0.0)
@@ -206,16 +210,16 @@ GEM
206
210
  sawyer (0.9.2)
207
211
  addressable (>= 2.3.5)
208
212
  faraday (>= 0.17.3, < 3)
209
- securerandom (0.4.0)
210
- sqlite3 (2.0.4-arm64-darwin)
211
- sqlite3 (2.0.4-x86_64-linux-gnu)
212
- stringio (3.1.1)
213
+ securerandom (0.4.1)
214
+ sqlite3 (2.4.1-arm64-darwin)
215
+ sqlite3 (2.4.1-x86_64-linux-gnu)
216
+ stringio (3.1.2)
213
217
  strings-ansi (0.2.0)
214
- timeout (0.4.2)
218
+ timeout (0.4.3)
215
219
  timers (4.3.5)
216
- traces (0.11.1)
220
+ traces (0.14.1)
217
221
  tty-cursor (0.7.1)
218
- tty-progressbar (0.18.2)
222
+ tty-progressbar (0.18.3)
219
223
  strings-ansi (~> 0.2)
220
224
  tty-cursor (~> 0.7)
221
225
  tty-screen (~> 0.8)
@@ -78,7 +78,7 @@ module Boxcars
78
78
  raise Error, "Anthropic: #{response['error']}" if response['error']
79
79
 
80
80
  answer = response['completion']
81
- Boxcars.debug(response, :yellow)
81
+ Boxcars.debug("Answer: #{answer}", :cyan)
82
82
  answer
83
83
  end
84
84
 
@@ -78,7 +78,7 @@ module Boxcars
78
78
  raise Error, "Cohere: #{response[:error]}" if response[:error]
79
79
 
80
80
  answer = response[:text]
81
- Boxcars.debug(response, :yellow)
81
+ Boxcars.debug("Answer: #{answer}", :cyan)
82
82
  answer
83
83
  end
84
84
 
@@ -1,73 +1,66 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Boxcars - a framework for running a series of tools to get an answer to a question.
3
+ # Boxcars is a framework for running a series of tools to get an answer to a question.
4
4
  module Boxcars
5
- # A engine that uses Gemini's API.
5
+ # A engine that uses GeminiAI's API.
6
6
  class GeminiAi < Engine
7
- attr_reader :prompts, :llm_params, :model_kwargs, :batch_size
7
+ attr_reader :prompts, :llm_parmas, :model_kwargs, :batch_size
8
8
 
9
9
  # The default parameters to use when asking the engine.
10
10
  DEFAULT_PARAMS = {
11
- model: "gemini-1.5-flash-latest"
11
+ model: "gemini-1.5-flash-latest",
12
+ temperature: 0.1
12
13
  }.freeze
13
14
 
14
15
  # the default name of the engine
15
- DEFAULT_NAME = "Google Gemini AI engine"
16
+ DEFAULT_NAME = "GeminiAI engine"
16
17
  # the default description of the engine
17
- DEFAULT_DESCRIPTION = "useful for when you need to use Google Gemini AI to answer questions. " \
18
+ DEFAULT_DESCRIPTION = "useful for when you need to use AI to answer questions. " \
18
19
  "You should ask targeted questions"
19
20
 
20
- # A engine is the driver for a single tool to run.
21
- # @param name [String] The name of the engine. Defaults to "OpenAI engine".
21
+ # A engine is a container for a single tool to run.
22
+ # @param name [String] The name of the engine. Defaults to "GeminiAI engine".
22
23
  # @param description [String] A description of the engine. Defaults to:
23
24
  # useful for when you need to use AI to answer questions. You should ask targeted questions".
24
25
  # @param prompts [Array<String>] The prompts to use when asking the engine. Defaults to [].
25
- def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], **kwargs)
26
- @llm_params = DEFAULT_PARAMS.merge(kwargs)
26
+ # @param batch_size [Integer] The number of prompts to send to the engine at once. Defaults to 20.
27
+ def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs)
28
+ @llm_parmas = DEFAULT_PARAMS.merge(kwargs)
27
29
  @prompts = prompts
28
- @batch_size = 20
30
+ @batch_size = batch_size
29
31
  super(description: description, name: name)
30
32
  end
31
33
 
32
- def conversation_model?(_model)
33
- true
34
+ # Get the OpenAI API client
35
+ # @param gemini_api_key [String] The access token to use when asking the engine.
36
+ # Defaults to Boxcars.configuration.gemini_api_key
37
+ # @return [OpenAI::Client] The OpenAI API gem client.
38
+ def self.open_ai_client(gemini_api_key: nil)
39
+ access_token = Boxcars.configuration.gemini_api_key(gemini_api_key: gemini_api_key)
40
+ ::OpenAI::Client.new(access_token: access_token, uri_base: "https://generativelanguage.googleapis.com/v1beta/openai/")
34
41
  end
35
42
 
36
- def chat(params, gemini_api_key)
37
- raise Boxcars::ConfigurationError('Google AI API key not set') if gemini_api_key.blank?
38
-
39
- model_string = params.delete(:model_string)
40
- raise Boxcars::ConfigurationError('Google AI API key not set') if model_string.blank?
41
-
42
- # Define the API endpoint and parameters
43
- api_endpoint = "https://generativelanguage.googleapis.com/v1beta/models/#{model_string}:generateContent?key=#{gemini_api_key}"
44
-
45
- connection = Faraday.new(api_endpoint) do |faraday|
46
- faraday.request :url_encoded
47
- faraday.headers['Content-Type'] = 'application/json'
48
- end
49
-
50
- # Make the API call
51
- response = connection.post { |req| req.body = params.to_json }
52
-
53
- JSON.parse(response.body, symbolize_names: true)
43
+ def conversation_model?(_model)
44
+ true
54
45
  end
55
46
 
56
47
  # Get an answer from the engine.
57
48
  # @param prompt [String] The prompt to use when asking the engine.
58
- # @param gemini_api_key [String] Optional api key to use when asking the engine.
49
+ # @param gemini_api_key [String] The access token to use when asking the engine.
59
50
  # Defaults to Boxcars.configuration.gemini_api_key.
60
51
  # @param kwargs [Hash] Additional parameters to pass to the engine if wanted.
61
- def client(prompt:, inputs: {}, **kwargs)
62
- api_key = Boxcars.configuration.gemini_api_key(**kwargs)
63
- option_params = llm_params.merge(kwargs)
64
- model_string = option_params.delete(:model) || DEFAULT_PARAMS[:model]
65
- convo = prompt.as_messages(inputs: inputs)
66
- # Convert conversation to Google Gemini format
67
- params = to_google_gemini_format(convo[:messages], option_params)
68
- params[:model_string] = model_string
69
- Boxcars.debug("Prompt after formatting:#{params[:message]}", :cyan) if Boxcars.configuration.log_prompts
70
- chat(params, api_key)
52
+ def client(prompt:, inputs: {}, gemini_api_key: nil, **kwargs)
53
+ clnt = GeminiAi.open_ai_client(gemini_api_key: gemini_api_key)
54
+ params = llm_parmas.merge(kwargs)
55
+ prompt = prompt.first if prompt.is_a?(Array)
56
+ params = prompt.as_messages(inputs).merge(params)
57
+ if Boxcars.configuration.log_prompts
58
+ Boxcars.debug(params[:messages].last(2).map { |p| ">>>>>> Role: #{p[:role]} <<<<<<\n#{p[:content]}" }.join("\n"), :cyan)
59
+ end
60
+ clnt.chat(parameters: params)
61
+ rescue => e
62
+ Boxcars.error(e, :red)
63
+ raise
71
64
  end
72
65
 
73
66
  # get an answer from the engine for a question.
@@ -76,13 +69,10 @@ module Boxcars
76
69
  def run(question, **kwargs)
77
70
  prompt = Prompt.new(template: question)
78
71
  response = client(prompt: prompt, **kwargs)
79
-
80
72
  raise Error, "GeminiAI: No response from API" unless response
81
- raise Error, "GeminiAI: #{response[:error]}" if response[:error]
82
73
 
83
- answer = response[:candidates].first[:content][:parts].first[:text]
84
- Boxcars.debug(response, :yellow)
85
- answer
74
+ check_response(response)
75
+ response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip
86
76
  end
87
77
 
88
78
  # Get the default parameters for the engine.
@@ -95,13 +85,13 @@ module Boxcars
95
85
  # @param must_haves [Array<String>] The keys that must be in the response. Defaults to %w[choices].
96
86
  # @raise [KeyError] if there is an issue with the access token.
97
87
  # @raise [ValueError] if the response is not valid.
98
- def check_response(response, must_haves: %w[completion])
99
- if response['error']
88
+ def check_response(response, must_haves: %w[choices])
89
+ if response['error'].is_a?(Hash)
100
90
  code = response.dig('error', 'code')
101
91
  msg = response.dig('error', 'message') || 'unknown error'
102
- raise KeyError, "ANTHOPIC_API_KEY not valid" if code == 'invalid_api_key'
92
+ raise KeyError, "GEMINI_API_TOKEN not valid" if code == 'invalid_api_key'
103
93
 
104
- raise ValueError, "Gemini error: #{msg}"
94
+ raise ValueError, "GeminiAI error: #{msg}"
105
95
  end
106
96
 
107
97
  must_haves.each do |key|
@@ -111,13 +101,7 @@ module Boxcars
111
101
 
112
102
  # the engine type
113
103
  def engine_type
114
- "claude"
115
- end
116
-
117
- # lookup the context size for a model by name
118
- # @param modelname [String] The name of the model to lookup.
119
- def modelname_to_contextsize(_modelname)
120
- 100000
104
+ "gemini_ai"
121
105
  end
122
106
 
123
107
  # Calculate the maximum number of tokens possible to generate for a prompt.
@@ -127,34 +111,8 @@ module Boxcars
127
111
  num_tokens = get_num_tokens(prompt_text)
128
112
 
129
113
  # get max context size for model by name
130
- max_size = modelname_to_contextsize(model_name)
114
+ max_size = 8096
131
115
  max_size - num_tokens
132
116
  end
133
-
134
- def to_google_gemini_format(convo, option_params)
135
- instructions = convo.shift.last if convo.first && convo.first[:role] == :system
136
- system_instructions = instructions || "You are a helpful assistant."
137
-
138
- # Convert conversation history to the format expected by Google
139
- contents = convo.map { |message| { text: message[:content] } }
140
-
141
- generation_config = {}
142
- if option_params.length.positive?
143
- generation_config.merge!(option_params)
144
- generation_config[:stopSequences] = [generation_config.delete(:stop)] if generation_config[:stop].present?
145
- end
146
-
147
- rv = {
148
- system_instruction: { parts: { text: system_instructions } }, # System instructions or context
149
- contents: { parts: contents } # The chat messages
150
- }
151
-
152
- rv[:generationConfig] = generation_config if generation_config.length.positive?
153
- rv
154
- end
155
-
156
- def default_prefixes
157
- { system: "SYSTEM: ", user: "USER: ", assistant: "CHATBOT: ", history: :history }
158
- end
159
117
  end
160
118
  end
@@ -73,9 +73,7 @@ module Boxcars
73
73
  raise Error, "Groq: No response from API" unless response
74
74
 
75
75
  check_response(response)
76
- answer = response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip
77
- puts answer
78
- answer
76
+ response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip
79
77
  end
80
78
 
81
79
  # Get the default parameters for the engine.
@@ -92,7 +92,7 @@ module Boxcars
92
92
  raise Error, "OpenAI: #{response['error']}" if response["error"]
93
93
 
94
94
  answer = response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip
95
- puts answer
95
+ Boxcars.debug("Answer: #{answer}", :cyan)
96
96
  answer
97
97
  end
98
98
 
@@ -78,7 +78,7 @@ module Boxcars
78
78
  raise Error, "PerplexityAI: #{response['error']}" if response["error"]
79
79
 
80
80
  answer = response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip
81
- puts answer
81
+ Boxcars.debug("Answer: #{answer}", :cyan)
82
82
  answer
83
83
  end
84
84
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Boxcars
4
4
  # The current version of the gem.
5
- VERSION = "0.6.8"
5
+ VERSION = "0.6.9"
6
6
  end
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.8
4
+ version: 0.6.9
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-07 00:00:00.000000000 Z
12
+ date: 2024-12-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: anthropic