# frozen_string_literal: true require 'google_search_results' require 'boxcars/boxcar' require 'boxcars/result' class GoogleAnswerBox < Boxcars::Boxcar # The description of this boxcar. Used in the prompt to inform the engine what # this boxcar can do. ANSWERBOXDESC = "useful for when you need to answer questions that require realtime data." \ "You should ask targeted questions" # implements a boxcar that uses the Google SerpAPI to get the answer box data from search results. # @param name [String] The name of the boxcar. Defaults to classname. # @param description [String] A description of the boxcar. Defaults to SERPDESC. # @param serpapi_api_key [String] The API key to use for the SerpAPI. Defaults to Boxcars.configuration.serpapi_api_key. def initialize(name: "AnswerBox", description: ANSWERBOXDESC, serpapi_api_key: nil) super(name: name, description: description) api_key = Boxcars.configuration.serpapi_api_key(serpapi_api_key: serpapi_api_key) ::GoogleSearch.api_key = api_key end # Get an answer from Google using the SerpAPI. # @param question [String] The question to ask Google. # @return [String] The answer to the question. def run(question) search = ::GoogleSearch.new(q: question) Boxcars::Result.from_text(find_answer(search.get_hash)) end private def find_answer(res) # :answer_box=>{:type=>"local_time", :result=>"8:02 AM", :extensions=>["Sunday, May 7, 2023 (MDT)", "Time in Denver, CO"]} raise Error, "Got error from SerpAPI: {res[:error]}" if res[:error] # might be sending results outside of the answer box ... # see a result for {"type":"organic_result" return "No answer found" unless res[:answer_box] return res.dig(:answer_box).to_json[0..1000].gsub("%","%%") end end