boxcars 0.6.8 → 0.6.9

Sign up to get free protection for your applications and to get access to all the features.
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