Class: Boxcars::Perplexityai
- Includes:
- UnifiedObservability
- Defined in:
- lib/boxcars/engine/perplexityai.rb
Overview
A engine that uses PerplexityAI’s API.
Constant Summary collapse
- DEFAULT_PARAMS =
Renamed from DEFAULT_PER_PARAMS for consistency
{ # Renamed from DEFAULT_PER_PARAMS for consistency model: "llama-3-sonar-large-32k-online", # Removed extra quotes temperature: 0.1 # max_tokens can be part of kwargs if needed }.freeze
- DEFAULT_NAME =
max_tokens can be part of kwargs if needed
"PerplexityAI engine"- DEFAULT_DESCRIPTION =
Renamed from DEFAULT_PER_NAME
"useful for when you need to use Perplexity AI to answer questions. " \ "You should ask targeted questions"
Instance Attribute Summary collapse
-
#batch_size ⇒ Object
readonly
Returns the value of attribute batch_size.
-
#model_kwargs ⇒ Object
readonly
Returns the value of attribute model_kwargs.
-
#perplexity_params ⇒ Object
readonly
Returns the value of attribute perplexity_params.
-
#prompts ⇒ Object
readonly
Returns the value of attribute prompts.
Attributes inherited from Engine
Instance Method Summary collapse
-
#client(prompt:, inputs: {}, perplexity_api_key: nil, **kwargs) ⇒ Object
Main client method for interacting with the Perplexity API rubocop:disable Metrics/MethodLength.
-
#conversation_model?(_model_name) ⇒ Boolean
Perplexity models are conversational.
- #default_params ⇒ Object
-
#extract_answer(response) ⇒ Object
Extract answer content from the API response.
-
#initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs) ⇒ Perplexityai
constructor
A new instance of Perplexityai.
-
#run(question) ⇒ Object
rubocop:enable Metrics/MethodLength.
-
#validate_response!(response, must_haves: %w[choices])) ⇒ Object
validate_response! method uses the base implementation.
Methods inherited from Engine
#generate, #generation_info, #get_num_tokens
Constructor Details
#initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs) ⇒ Perplexityai
Returns a new instance of Perplexityai.
23 24 25 26 27 28 29 |
# File 'lib/boxcars/engine/perplexityai.rb', line 23 def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs) user_id = kwargs.delete(:user_id) @perplexity_params = DEFAULT_PARAMS.merge(kwargs) @prompts = prompts @batch_size = batch_size # Retain if used by generate super(description:, name:, user_id:) end |
Instance Attribute Details
#batch_size ⇒ Object (readonly)
Returns the value of attribute batch_size.
12 13 14 |
# File 'lib/boxcars/engine/perplexityai.rb', line 12 def batch_size @batch_size end |
#model_kwargs ⇒ Object (readonly)
Returns the value of attribute model_kwargs.
12 13 14 |
# File 'lib/boxcars/engine/perplexityai.rb', line 12 def model_kwargs @model_kwargs end |
#perplexity_params ⇒ Object (readonly)
Returns the value of attribute perplexity_params.
12 13 14 |
# File 'lib/boxcars/engine/perplexityai.rb', line 12 def perplexity_params @perplexity_params end |
#prompts ⇒ Object (readonly)
Returns the value of attribute prompts.
12 13 14 |
# File 'lib/boxcars/engine/perplexityai.rb', line 12 def prompts @prompts end |
Instance Method Details
#client(prompt:, inputs: {}, perplexity_api_key: nil, **kwargs) ⇒ Object
Main client method for interacting with the Perplexity API rubocop:disable Metrics/MethodLength
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/boxcars/engine/perplexityai.rb', line 38 def client(prompt:, inputs: {}, perplexity_api_key: nil, **kwargs) start_time = Time.now response_data = { response_obj: nil, parsed_json: nil, success: false, error: nil, status_code: nil } current_params = @perplexity_params.merge(kwargs) api_request_params = nil # Parameters actually sent to Perplexity API current_prompt_object = prompt.is_a?(Array) ? prompt.first : prompt begin api_key = perplexity_api_key || Boxcars.configuration.perplexity_api_key(**current_params.slice(:perplexity_api_key)) raise Boxcars::ConfigurationError, "Perplexity API key not set" if api_key.nil? || api_key.strip.empty? conn = Faraday.new(url: "https://api.perplexity.ai") do |faraday| faraday.request :json faraday.response :json # Parse JSON response faraday.response :raise_error # Raise exceptions on 4xx/5xx faraday.adapter Faraday.default_adapter end = current_prompt_object.(inputs)[:messages] # Perplexity expects a 'model' and 'messages' structure. # Other params like temperature, max_tokens are top-level. # Filter out parameters that Perplexity doesn't support supported_params = filter_supported_params(current_params) api_request_params = { model: supported_params[:model], messages: }.merge(supported_params.except(:model, :messages, :perplexity_api_key)) (api_request_params[:messages]) if Boxcars.configuration.log_prompts && api_request_params[:messages] response = conn.post('/chat/completions') do |req| req.headers['Authorization'] = "Bearer #{api_key}" req.body = api_request_params end response_data[:response_obj] = response # Faraday response object response_data[:parsed_json] = response.body # Faraday with :json middleware parses body response_data[:status_code] = response.status if response.success? && response.body && response.body["choices"] response_data[:success] = true else response_data[:success] = false err_details = response.body["error"] if response.body.is_a?(Hash) msg = if err_details "#{err_details['type']}: #{err_details['message']}" else "Unknown Perplexity API Error (status: #{response.status})" end response_data[:error] = StandardError.new(msg) end rescue Faraday::Error => e # Catch Faraday specific errors (includes connection, timeout, 4xx/5xx) response_data[:error] = e response_data[:success] = false response_data[:status_code] = e.response_status if e.respond_to?(:response_status) response_data[:response_obj] = e.response if e.respond_to?(:response) # Store Faraday response if available response_data[:parsed_json] = e.response[:body] if e.respond_to?(:response) && e.response[:body].is_a?(Hash) rescue StandardError => e # Catch other unexpected errors response_data[:error] = e response_data[:success] = false ensure duration_ms = ((Time.now - start_time) * 1000).round request_context = { prompt: current_prompt_object, inputs:, user_id:, conversation_for_api: api_request_params&.dig(:messages) } track_ai_generation( duration_ms:, current_params:, request_context:, response_data:, provider: :perplexity_ai ) end _perplexity_handle_call_outcome(response_data:) end |
#conversation_model?(_model_name) ⇒ Boolean
Perplexity models are conversational.
32 33 34 |
# File 'lib/boxcars/engine/perplexityai.rb', line 32 def conversation_model?(_model_name) true end |
#default_params ⇒ Object
137 138 139 |
# File 'lib/boxcars/engine/perplexityai.rb', line 137 def default_params @perplexity_params end |
#extract_answer(response) ⇒ Object
Extract answer content from the API response
129 130 131 132 133 134 135 |
# File 'lib/boxcars/engine/perplexityai.rb', line 129 def extract_answer(response) if response.is_a?(Hash) && response["choices"] response["choices"].map { |c| c.dig("message", "content") }.join("\n").strip else response.to_s end end |
#run(question) ⇒ Object
rubocop:enable Metrics/MethodLength
119 120 121 122 123 124 125 126 |
# File 'lib/boxcars/engine/perplexityai.rb', line 119 def run(question, **) prompt = Prompt.new(template: question) response = client(prompt:, inputs: {}, **) # Extract the content from the response for the run method answer = extract_answer(response) Boxcars.debug("Answer: #{answer}", :cyan) answer end |
#validate_response!(response, must_haves: %w[choices])) ⇒ Object
validate_response! method uses the base implementation
142 143 144 |
# File 'lib/boxcars/engine/perplexityai.rb', line 142 def validate_response!(response, must_haves: %w[choices]) super end |