boxcars 0.7.2 → 0.7.3
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/boxcars/boxcar/json_engine_boxcar.rb +1 -1
- data/lib/boxcars/boxcar.rb +1 -1
- data/lib/boxcars/engine/cerebras.rb +12 -85
- data/lib/boxcars/engine/google.rb +36 -0
- data/lib/boxcars/engine/intelligence_base.rb +103 -0
- data/lib/boxcars/engine.rb +10 -2
- data/lib/boxcars/version.rb +1 -1
- metadata +4 -4
- data/lib/boxcars/engine/intelligence.rb +0 -141
- data/perplexity_example.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32da67348d02e7e369d6b7ae465679220134c2abbfd7fbf8ff952bf51151e1bf
|
4
|
+
data.tar.gz: 23658aa847e993e68d5bfc71ba40a686b764478e8d21b8c313b4f8bf6a6023f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4cf6bbc8b99d96fa3dc20bf15b07d3a04f6d8ceee9e7a224c67f5ba7ca114f7a58acf3d00b973ab2243b8d09c0d5b5959e90ec7dc67ed819443d140f63c7660
|
7
|
+
data.tar.gz: 11691020363325c0567e812dbde560290ec69f0d213aa585b71f76492ee09656f005f49661c32be8a96cf78435ee8ef8a66596ebf1896239a4cca9da7b592854
|
data/Gemfile.lock
CHANGED
@@ -35,7 +35,7 @@ module Boxcars
|
|
35
35
|
%<wanted_data>s
|
36
36
|
}
|
37
37
|
SYSPR
|
38
|
-
stock_prompt += "\n\nImportant:\n#{important}\n"
|
38
|
+
stock_prompt += "\n\nImportant:\n#{important}\n" unless important.to_s.empty?
|
39
39
|
|
40
40
|
sprompt = format(stock_prompt, wanted_data: wanted_data, data_description: data_description)
|
41
41
|
ctemplate = [
|
data/lib/boxcars/boxcar.rb
CHANGED
@@ -166,7 +166,7 @@ module Boxcars
|
|
166
166
|
output = call(inputs: inputs)
|
167
167
|
rescue StandardError => e
|
168
168
|
Boxcars.error "Error in #{name} boxcar#call: #{e}\nbt:#{e.backtrace[0..5].join("\n ")}", :red
|
169
|
-
Boxcars.error("Response Body: #{e.response[:body]}", :red) if e.respond_to?(:response) && e.response.
|
169
|
+
Boxcars.error("Response Body: #{e.response[:body]}", :red) if e.respond_to?(:response) && !e.response.nil?
|
170
170
|
raise e
|
171
171
|
end
|
172
172
|
validate_outputs(outputs: output.keys)
|
@@ -1,11 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "intelligence"
|
4
3
|
module Boxcars
|
5
4
|
# A engine that uses Cerebras's API
|
6
|
-
class Cerebras <
|
7
|
-
attr_reader :prompts, :cerebras_params, :model_kwargs, :batch_size
|
8
|
-
|
5
|
+
class Cerebras < IntelligenceBase
|
9
6
|
# The default parameters to use when asking the engine
|
10
7
|
DEFAULT_PARAMS = {
|
11
8
|
model: "llama-3.3-70b",
|
@@ -18,92 +15,22 @@ module Boxcars
|
|
18
15
|
DEFAULT_DESCRIPTION = "useful for when you need to use Cerebras to process complex content. " \
|
19
16
|
"Supports text, images, and other content types"
|
20
17
|
|
18
|
+
# A Cerebras Engine is used by Boxcars to generate output from prompts
|
19
|
+
# @param name [String] The name of the Engine. Defaults to classname.
|
20
|
+
# @param description [String] A description of the Engine.
|
21
|
+
# @param prompts [Array<Prompt>] The prompts to use for the Engine.
|
22
|
+
# @param batch_size [Integer] The number of prompts to send to the Engine at a time.
|
23
|
+
# @param kwargs [Hash] Additional parameters to pass to the Engine.
|
21
24
|
def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs)
|
22
|
-
|
23
|
-
@prompts = prompts
|
24
|
-
@batch_size = batch_size
|
25
|
-
super(description: description, name: name)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Get the Cerebras API client
|
29
|
-
def self.adapter(params:, api_key: nil)
|
30
|
-
api_key = Boxcars.configuration.cerebras_api_key(**params) if api_key.nil?
|
31
|
-
raise ArgumentError, "Cerebras API key not configured" unless api_key
|
32
|
-
|
33
|
-
Intelligence::Adapter[:cerebras].new(
|
34
|
-
{ key: api_key, chat_options: params }
|
35
|
-
)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Process different content types
|
39
|
-
def process_content(content)
|
40
|
-
case content
|
41
|
-
when String
|
42
|
-
{ type: "text", text: content }
|
43
|
-
when Hash
|
44
|
-
validate_content(content)
|
45
|
-
when Array
|
46
|
-
content.map { |c| process_content(c) }
|
47
|
-
else
|
48
|
-
raise ArgumentError, "Unsupported content type: #{content.class}"
|
49
|
-
end
|
25
|
+
super(provider: :cerebras, description: description, name: name, prompts: prompts, batch_size: batch_size, **kwargs)
|
50
26
|
end
|
51
27
|
|
52
|
-
|
53
|
-
|
54
|
-
raise ArgumentError, "Content must have type and text fields" unless content[:type] && content[:text]
|
55
|
-
|
56
|
-
content
|
57
|
-
end
|
58
|
-
|
59
|
-
# Get an answer from the engine
|
60
|
-
def client(prompt:, inputs: {}, api_key: nil, **kwargs)
|
61
|
-
params = cerebras_params.merge(kwargs)
|
62
|
-
adapter = Cerebras.adapter(api_key: api_key, params: params)
|
63
|
-
raise Error, "Cerebras: No response from API" unless adapter
|
64
|
-
|
65
|
-
convo = prompt.as_intelligence_conversation(inputs: inputs)
|
66
|
-
raise Error, "Cerebras: No conversation" unless convo
|
67
|
-
|
68
|
-
# Make API call
|
69
|
-
request = Intelligence::ChatRequest.new(adapter: adapter)
|
70
|
-
response = request.chat(convo)
|
71
|
-
return JSON.parse(response.body) if response.success?
|
72
|
-
|
73
|
-
raise Error, "Cerebras: #{response.reason_phrase}"
|
74
|
-
rescue StandardError => e
|
75
|
-
Boxcars.error("Cerebras Error: #{e.message}", :red)
|
76
|
-
raise
|
77
|
-
end
|
78
|
-
|
79
|
-
# Run the engine with a question
|
80
|
-
def run(question, **kwargs)
|
81
|
-
prompt = Prompt.new(template: question)
|
82
|
-
response = client(prompt: prompt, **kwargs)
|
83
|
-
extract_answer(response)
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
def extract_answer(response)
|
89
|
-
# Handle different response formats
|
90
|
-
if response["choices"]
|
91
|
-
response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip
|
92
|
-
else
|
93
|
-
response["output"] || response.to_s
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def check_response(response)
|
98
|
-
return if response.present? && response.key?("choices")
|
99
|
-
|
100
|
-
raise KeyError, "CEREBRAS_API_KEY not valid" if response&.reason_phrase == "Unauthorized"
|
101
|
-
|
102
|
-
raise ValueError, "Cerebras error: #{response&.reason_phrase&.present? ? response.reason_phrase : response}"
|
28
|
+
def default_model_params
|
29
|
+
DEFAULT_PARAMS
|
103
30
|
end
|
104
31
|
|
105
|
-
def
|
106
|
-
|
32
|
+
def lookup_provider_api_key(params:)
|
33
|
+
Boxcars.configuration.cerebras_api_key(**params)
|
107
34
|
end
|
108
35
|
end
|
109
36
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Boxcars
|
4
|
+
# A engine that uses Google's API
|
5
|
+
class Google < IntelligenceBase
|
6
|
+
# The default parameters to use when asking the engine
|
7
|
+
DEFAULT_PARAMS = {
|
8
|
+
model: "gemini-1.5-flash-latest",
|
9
|
+
temperature: 0.1
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
# the default name of the engine
|
13
|
+
DEFAULT_NAME = "Google Vertex AI engine"
|
14
|
+
# the default description of the engine
|
15
|
+
DEFAULT_DESCRIPTION = "useful for when you need to use Google Vertex AI to process complex content. " \
|
16
|
+
"Supports text, images, and other content types"
|
17
|
+
|
18
|
+
# A Google Engine is used by Boxcars to generate output from prompts
|
19
|
+
# @param name [String] The name of the Engine. Defaults to classname.
|
20
|
+
# @param description [String] A description of the Engine.
|
21
|
+
# @param prompts [Array<Prompt>] The prompts to use for the Engine.
|
22
|
+
# @param batch_size [Integer] The number of prompts to send to the Engine at a time.
|
23
|
+
# @param kwargs [Hash] Additional parameters to pass to the Engine.
|
24
|
+
def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs)
|
25
|
+
super(provider: :google, description: description, name: name, prompts: prompts, batch_size: batch_size, **kwargs)
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_model_params
|
29
|
+
DEFAULT_PARAMS
|
30
|
+
end
|
31
|
+
|
32
|
+
def lookup_provider_api_key(params:)
|
33
|
+
Boxcars.configuration.gemini_api_key(**params)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'intelligence'
|
4
|
+
|
5
|
+
module Boxcars
|
6
|
+
# A Base class for all Intelligence Engines
|
7
|
+
class IntelligenceBase < Engine
|
8
|
+
attr_reader :provider, :all_params
|
9
|
+
|
10
|
+
# The base Intelligence Engine is used by other engines to generate output from prompts
|
11
|
+
# @param provider [String] The provider of the Engine implemented by the Intelligence gem.
|
12
|
+
# @param name [String] The name of the Engine. Defaults to classname.
|
13
|
+
# @param description [String] A description of the Engine.
|
14
|
+
# @param prompts [Array<Prompt>] The prompts to use for the Engine.
|
15
|
+
# @param batch_size [Integer] The number of prompts to send to the Engine at a time.
|
16
|
+
# @param kwargs [Hash] Additional parameters to pass to the Engine.
|
17
|
+
def initialize(provider:, description:, name:, prompts: [], batch_size: 20, **kwargs)
|
18
|
+
@provider = provider
|
19
|
+
@all_params = default_model_params.merge(kwargs)
|
20
|
+
super(description: description, name: name, prompts: prompts, batch_size: batch_size)
|
21
|
+
end
|
22
|
+
|
23
|
+
# can be overridden by provider subclass
|
24
|
+
def default_model_params
|
25
|
+
{}
|
26
|
+
end
|
27
|
+
|
28
|
+
def lookup_provider_api_key(params:)
|
29
|
+
raise NotImplementedError, "lookup_provider_api_key method must be implemented by subclass"
|
30
|
+
end
|
31
|
+
|
32
|
+
def adapter(params:, api_key:)
|
33
|
+
Intelligence::Adapter[provider].new(
|
34
|
+
{ key: api_key, chat_options: params }
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Process different content types
|
39
|
+
def process_content(content)
|
40
|
+
case content
|
41
|
+
when String
|
42
|
+
{ type: "text", text: content }
|
43
|
+
when Hash
|
44
|
+
validate_content(content)
|
45
|
+
when Array
|
46
|
+
content.map { |c| process_content(c) }
|
47
|
+
else
|
48
|
+
raise ArgumentError, "Unsupported content type: #{content.class}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Validate content structure
|
53
|
+
def validate_content(content)
|
54
|
+
raise ArgumentError, "Content must have type and text fields" unless content[:type] && content[:text]
|
55
|
+
|
56
|
+
content
|
57
|
+
end
|
58
|
+
|
59
|
+
# Get an answer from the engine
|
60
|
+
def client(prompt:, inputs: {}, api_key: nil, **kwargs)
|
61
|
+
params = all_params.merge(kwargs)
|
62
|
+
api_key ||= lookup_provider_api_key(params: params)
|
63
|
+
raise Error, "No API key found for #{provider}" unless api_key
|
64
|
+
|
65
|
+
adapter = adapter(api_key: api_key, params: params)
|
66
|
+
convo = prompt.as_intelligence_conversation(inputs: inputs)
|
67
|
+
request = Intelligence::ChatRequest.new(adapter: adapter)
|
68
|
+
response = request.chat(convo)
|
69
|
+
return JSON.parse(response.body) if response.success?
|
70
|
+
|
71
|
+
raise Error, (response&.reason_phrase || "No response from API #{provider}")
|
72
|
+
rescue StandardError => e
|
73
|
+
Boxcars.error("#{provider} Error: #{e.message}", :red)
|
74
|
+
raise
|
75
|
+
end
|
76
|
+
|
77
|
+
# Run the engine with a question
|
78
|
+
def run(question, **kwargs)
|
79
|
+
prompt = Prompt.new(template: question)
|
80
|
+
response = client(prompt: prompt, **kwargs)
|
81
|
+
extract_answer(response)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def extract_answer(response)
|
87
|
+
# Handle different response formats
|
88
|
+
if response["choices"]
|
89
|
+
response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip
|
90
|
+
elsif response["candidates"]
|
91
|
+
response["candidates"].map { |c| c.dig("content", "parts", 0, "text") }.join("\n").strip
|
92
|
+
else
|
93
|
+
response["output"] || response.to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def check_response(response)
|
98
|
+
return if response.is_a?(Hash) && response.key?("choices")
|
99
|
+
|
100
|
+
raise Error, "Invalid response from #{provider}: #{response}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/boxcars/engine.rb
CHANGED
@@ -3,12 +3,18 @@
|
|
3
3
|
module Boxcars
|
4
4
|
# @abstract
|
5
5
|
class Engine
|
6
|
+
attr_reader :prompts, :batch_size
|
7
|
+
|
6
8
|
# An Engine is used by Boxcars to generate output from prompts
|
7
9
|
# @param name [String] The name of the Engine. Defaults to classname.
|
8
10
|
# @param description [String] A description of the Engine.
|
9
|
-
|
11
|
+
# @param prompts [Array<Prompt>] The prompts to use for the Engine.
|
12
|
+
# @param batch_size [Integer] The number of prompts to send to the Engine at a time.
|
13
|
+
def initialize(description: 'Engine', name: nil, prompts: [], batch_size: 20)
|
10
14
|
@name = name || self.class.name
|
11
15
|
@description = description
|
16
|
+
@prompts = prompts
|
17
|
+
@batch_size = batch_size
|
12
18
|
end
|
13
19
|
|
14
20
|
# Get an answer from the Engine.
|
@@ -37,7 +43,7 @@ module Boxcars
|
|
37
43
|
end
|
38
44
|
end
|
39
45
|
|
40
|
-
# Call out to
|
46
|
+
# Call out to LLM's endpoint with k unique prompts.
|
41
47
|
# @param prompts [Array<String>] The prompts to pass into the model.
|
42
48
|
# @param inputs [Array<String>] The inputs to subsitite into the prompt.
|
43
49
|
# @param stop [Array<String>] Optional list of stop words to use when generating.
|
@@ -80,4 +86,6 @@ require "boxcars/engine/openai"
|
|
80
86
|
require "boxcars/engine/perplexityai"
|
81
87
|
require "boxcars/engine/gpt4all_eng"
|
82
88
|
require "boxcars/engine/gemini_ai"
|
89
|
+
require "boxcars/engine/intelligence_base"
|
83
90
|
require "boxcars/engine/cerebras"
|
91
|
+
require "boxcars/engine/google"
|
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.7.
|
4
|
+
version: 0.7.3
|
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: 2025-01-
|
12
|
+
date: 2025-01-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: anthropic
|
@@ -169,9 +169,10 @@ files:
|
|
169
169
|
- lib/boxcars/engine/cohere.rb
|
170
170
|
- lib/boxcars/engine/engine_result.rb
|
171
171
|
- lib/boxcars/engine/gemini_ai.rb
|
172
|
+
- lib/boxcars/engine/google.rb
|
172
173
|
- lib/boxcars/engine/gpt4all_eng.rb
|
173
174
|
- lib/boxcars/engine/groq.rb
|
174
|
-
- lib/boxcars/engine/
|
175
|
+
- lib/boxcars/engine/intelligence_base.rb
|
175
176
|
- lib/boxcars/engine/ollama.rb
|
176
177
|
- lib/boxcars/engine/openai.rb
|
177
178
|
- lib/boxcars/engine/perplexityai.rb
|
@@ -205,7 +206,6 @@ files:
|
|
205
206
|
- lib/boxcars/vector_store/split_text.rb
|
206
207
|
- lib/boxcars/version.rb
|
207
208
|
- lib/boxcars/x_node.rb
|
208
|
-
- perplexity_example.rb
|
209
209
|
- run.json
|
210
210
|
homepage: https://github.com/BoxcarsAI/boxcars
|
211
211
|
licenses:
|
@@ -1,141 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Boxcars
|
4
|
-
# A engine that uses Intelligence's API
|
5
|
-
class Intelligence < Engine
|
6
|
-
attr_reader :prompts, :intelligence_params, :model_kwargs, :batch_size
|
7
|
-
|
8
|
-
# The default parameters to use when asking the engine
|
9
|
-
DEFAULT_PARAMS = {
|
10
|
-
model: "intelligence-1.0",
|
11
|
-
temperature: 0.1
|
12
|
-
}.freeze
|
13
|
-
|
14
|
-
# the default name of the engine
|
15
|
-
DEFAULT_NAME = "Intelligence engine"
|
16
|
-
# the default description of the engine
|
17
|
-
DEFAULT_DESCRIPTION = "useful for when you need to use Intelligence to process complex content. " \
|
18
|
-
"Supports text, images, and other content types"
|
19
|
-
|
20
|
-
def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs)
|
21
|
-
begin
|
22
|
-
require 'intelligence'
|
23
|
-
rescue LoadError => _e
|
24
|
-
raise LoadError,
|
25
|
-
"The intelligence gem is required. Please add 'gem \"intelligence\"' to your Gemfile and run bundle install"
|
26
|
-
end
|
27
|
-
|
28
|
-
@intelligence_params = DEFAULT_PARAMS.merge(kwargs)
|
29
|
-
@prompts = prompts
|
30
|
-
@batch_size = batch_size
|
31
|
-
super(description: description, name: name)
|
32
|
-
end
|
33
|
-
|
34
|
-
# Get the Intelligence API client
|
35
|
-
def self.intelligence_client(api_key: nil)
|
36
|
-
api_key ||= Boxcars.configuration.intelligence_api_key
|
37
|
-
raise ArgumentError, "Intelligence API key not configured" unless api_key
|
38
|
-
|
39
|
-
Client.new(api_key: api_key)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Stream responses from the Intelligence API
|
43
|
-
def stream(prompt:, inputs: {}, api_key: nil, &block)
|
44
|
-
client = Intelligence.intelligence_client(api_key: api_key)
|
45
|
-
params = intelligence_params.merge(stream: true)
|
46
|
-
|
47
|
-
processed_prompt = if conversation_model?(params[:model])
|
48
|
-
prompt.as_messages(inputs)
|
49
|
-
else
|
50
|
-
{ prompt: prompt.as_prompt(inputs: inputs) }
|
51
|
-
end
|
52
|
-
|
53
|
-
processed_prompt[:content] = process_content(processed_prompt[:content]) if processed_prompt[:content]
|
54
|
-
|
55
|
-
client.stream(parameters: params.merge(processed_prompt), &block)
|
56
|
-
end
|
57
|
-
|
58
|
-
# Process different content types
|
59
|
-
def process_content(content)
|
60
|
-
case content
|
61
|
-
when String
|
62
|
-
{ type: "text", text: content }
|
63
|
-
when Hash
|
64
|
-
validate_content(content)
|
65
|
-
when Array
|
66
|
-
content.map { |c| process_content(c) }
|
67
|
-
else
|
68
|
-
raise ArgumentError, "Unsupported content type: #{content.class}"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Validate content structure
|
73
|
-
def validate_content(content)
|
74
|
-
raise ArgumentError, "Content must have type and text fields" unless content[:type] && content[:text]
|
75
|
-
|
76
|
-
content
|
77
|
-
end
|
78
|
-
|
79
|
-
# Get an answer from the engine
|
80
|
-
def client(prompt:, inputs: {}, api_key: nil, **kwargs)
|
81
|
-
client = Intelligence.intelligence_client(api_key: api_key)
|
82
|
-
params = intelligence_params.merge(kwargs)
|
83
|
-
|
84
|
-
processed_prompt = if conversation_model?(params[:model])
|
85
|
-
prompt.as_messages(inputs)
|
86
|
-
else
|
87
|
-
{ prompt: prompt.as_prompt(inputs: inputs) }
|
88
|
-
end
|
89
|
-
|
90
|
-
# Add content processing
|
91
|
-
processed_prompt[:content] = process_content(processed_prompt[:content]) if processed_prompt[:content]
|
92
|
-
|
93
|
-
Boxcars.debug("Sending to Intelligence:\n#{processed_prompt}", :cyan) if Boxcars.configuration.log_prompts
|
94
|
-
|
95
|
-
# Make API call
|
96
|
-
response = client.generate(parameters: params.merge(processed_prompt))
|
97
|
-
check_response(response)
|
98
|
-
response
|
99
|
-
rescue StandardError => e
|
100
|
-
Boxcars.error("Intelligence Error: #{e.message}", :red)
|
101
|
-
raise
|
102
|
-
end
|
103
|
-
|
104
|
-
# Run the engine with a question
|
105
|
-
def run(question, **kwargs)
|
106
|
-
prompt = Prompt.new(template: question)
|
107
|
-
response = client(prompt: prompt, **kwargs)
|
108
|
-
extract_answer(response)
|
109
|
-
end
|
110
|
-
|
111
|
-
private
|
112
|
-
|
113
|
-
def extract_answer(response)
|
114
|
-
# Handle different response formats
|
115
|
-
if response["choices"]
|
116
|
-
response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip
|
117
|
-
else
|
118
|
-
response["output"] || response.to_s
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def check_response(response)
|
123
|
-
if response["error"]
|
124
|
-
code = response.dig("error", "code")
|
125
|
-
msg = response.dig("error", "message") || "unknown error"
|
126
|
-
raise KeyError, "INTELLIGENCE_API_KEY not valid" if code == "invalid_api_key"
|
127
|
-
|
128
|
-
raise ValueError, "Intelligence error: #{msg}"
|
129
|
-
end
|
130
|
-
|
131
|
-
# Validate response structure
|
132
|
-
return if response["choices"] || response["output"]
|
133
|
-
|
134
|
-
raise Error, "Invalid response format from Intelligence API"
|
135
|
-
end
|
136
|
-
|
137
|
-
def conversation_model?(_model)
|
138
|
-
true
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
data/perplexity_example.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require "debug"
|
2
|
-
require "dotenv/load"
|
3
|
-
require "boxcars"
|
4
|
-
|
5
|
-
# Boxcars.configuration.logger = Logger.new($stdout)
|
6
|
-
|
7
|
-
eng = Boxcars::Perplexityai.new
|
8
|
-
# eng = Boxcars::Openai.new(model: "gpt-4")
|
9
|
-
ctemplate = [
|
10
|
-
Boxcars::Boxcar.syst("The user will type in a city name. Your job is to evaluate if the given city is a good place to live. " \
|
11
|
-
"Build a comprehensive report about livability, weather, cost of living, crime rate, drivability, " \
|
12
|
-
"walkability, and bike ability, and direct flights. In the final answer, for the first paragraph, " \
|
13
|
-
"summarize the pros and cons of living in the city followed by the background information and links " \
|
14
|
-
"for the research. Finalize your answer with an overall grade from A to F on the city."),
|
15
|
-
Boxcars::Boxcar.user("%<input>s")
|
16
|
-
]
|
17
|
-
conv = Boxcars::Conversation.new(lines: ctemplate)
|
18
|
-
|
19
|
-
conversation_prompt = Boxcars::ConversationPrompt.new(conversation: conv, input_variables: [:input], other_inputs: [],
|
20
|
-
output_variables: [:answer])
|
21
|
-
|
22
|
-
boxcar = Boxcars::EngineBoxcar.new(engine: eng, name: "City Helper", prompt: conversation_prompt,
|
23
|
-
description: "Evaluate if a city is a good place to live.")
|
24
|
-
data = boxcar.run(ARGV.fetch(0, "San Francisco"))
|
25
|
-
# train = Boxcars.train.new(boxcars: [boxcar])
|
26
|
-
# data = train.run()
|
27
|
-
# debugger
|
28
|
-
puts data
|