Class: Boxcars::Gpt4allEng

Inherits:
Engine
  • Object
show all
Includes:
UnifiedObservability
Defined in:
lib/boxcars/engine/gpt4all_eng.rb

Overview

A engine that uses local GPT4All API.

Constant Summary collapse

DEFAULT_NAME =
"Gpt4all engine"
DEFAULT_DESCRIPTION =
"useful for when you need to use local AI to answer questions. " \
"You should ask targeted questions"
DEFAULT_PARAMS =

GPT4All doesn’t have typical API params like temperature or model selection via params in the same way. Model is usually pre-loaded. We can add a placeholder for model_name if needed for tracking.

{
  model_name: "gpt4all-j-v1.3-groovy" # Example, actual model depends on local setup
}.freeze

Instance Attribute Summary collapse

Attributes inherited from Engine

#user_id

Instance Method Summary collapse

Methods inherited from Engine

#extract_answer, #generate, #generation_info, #get_num_tokens, #validate_response!

Constructor Details

#initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 2, **kwargs) ⇒ Gpt4allEng

Returns a new instance of Gpt4allEng.



22
23
24
25
26
27
28
# File 'lib/boxcars/engine/gpt4all_eng.rb', line 22

def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 2, **kwargs)
  user_id = kwargs.delete(:user_id)
  @gpt4all_params = DEFAULT_PARAMS.merge(kwargs) # Store merged params
  @prompts = prompts
  @batch_size = batch_size # Retain if used by other methods
  super(description:, name:, user_id:)
end

Instance Attribute Details

#batch_sizeObject (readonly)

Added gpt4all_params



11
12
13
# File 'lib/boxcars/engine/gpt4all_eng.rb', line 11

def batch_size
  @batch_size
end

#gpt4all_paramsObject (readonly)

Added gpt4all_params



11
12
13
# File 'lib/boxcars/engine/gpt4all_eng.rb', line 11

def gpt4all_params
  @gpt4all_params
end

#model_kwargsObject (readonly)

Added gpt4all_params



11
12
13
# File 'lib/boxcars/engine/gpt4all_eng.rb', line 11

def model_kwargs
  @model_kwargs
end

#promptsObject (readonly)

Added gpt4all_params



11
12
13
# File 'lib/boxcars/engine/gpt4all_eng.rb', line 11

def prompts
  @prompts
end

Instance Method Details

#client(prompt:, inputs: {}, **kwargs) ⇒ Object



30
31
32
33
34
35
36
37
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
# File 'lib/boxcars/engine/gpt4all_eng.rb', line 30

def client(prompt:, inputs: {}, **kwargs)
  start_time = Time.now
  response_data = { response_obj: nil, parsed_json: nil, success: false, error: nil, status_code: nil }
  # current_params are the effective parameters for this call, including defaults and overrides
  current_params = @gpt4all_params.merge(kwargs)
  # api_request_params for GPT4All is just the input text.
  api_request_params, gpt4all_instance = nil
  current_prompt_object = prompt.is_a?(Array) ? prompt.first : prompt
  begin
    gpt4all_instance = Gpt4all::ConversationalAI.new
    # prepare_resources might download models, could take time.
    # Consider if this setup should be outside the timed/tracked client call for long-running setup.
    # For now, including it as it's part of the interaction.
    gpt4all_instance.prepare_resources(force_download: false)
    gpt4all_instance.start_bot

    # GPT4All gem's prompt method takes a string.
    prompt_text_for_api = current_prompt_object.as_prompt(inputs:)
    prompt_text_for_api = prompt_text_for_api[:prompt] if prompt_text_for_api.is_a?(Hash) && prompt_text_for_api.key?(:prompt)
    api_request_params = { prompt: prompt_text_for_api } # Store what's sent

    Boxcars.debug("Prompt after formatting:\n#{prompt_text_for_api}", :cyan) if Boxcars.configuration.log_prompts

    raw_response_text = gpt4all_instance.prompt(prompt_text_for_api) # Actual call

    # GPT4All gem returns a string directly, or raises error.
    response_data[:response_obj] = raw_response_text # Store the raw string
    response_data[:parsed_json] = { "text" => raw_response_text } # Create a simple hash for consistency
    response_data[:success] = true
    response_data[:status_code] = 200 # Inferred for local success
  rescue StandardError => e
    response_data[:error] = e
    response_data[:success] = false
    # No HTTP status code for local errors typically, unless the gem provides one.
  ensure
    gpt4all_instance&.stop_bot # Ensure bot is stopped even if errors occur

    duration_ms = ((Time.now - start_time) * 1000).round
    request_context = {
      prompt: current_prompt_object,
      inputs:,
      conversation_for_api: api_request_params&.dig(:prompt),
      user_id:
    }

    track_ai_generation(
      duration_ms:,
      current_params:,
      request_context:,
      response_data:,
      provider: :gpt4all
    )
  end

  _gpt4all_handle_call_outcome(response_data:)
end

#default_paramsObject

Added for consistency



95
96
97
# File 'lib/boxcars/engine/gpt4all_eng.rb', line 95

def default_params
  @gpt4all_params
end

#run(question) ⇒ Object



87
88
89
90
91
92
# File 'lib/boxcars/engine/gpt4all_eng.rb', line 87

def run(question, **)
  prompt = Prompt.new(template: question)
  answer = client(prompt:, inputs: {}, **)
  Boxcars.debug("Answer: #{answer}", :cyan)
  answer
end