Class: Llmemory::LLM::OpenAI

Inherits:
Base
  • Object
show all
Defined in:
lib/llmemory/llm/openai.rb

Constant Summary collapse

DEFAULT_BASE_URL =
"https://api.openai.com/v1"

Instance Method Summary collapse

Constructor Details

#initialize(api_key: nil, model: nil, base_url: nil) ⇒ OpenAI

Returns a new instance of OpenAI.



12
13
14
15
16
# File 'lib/llmemory/llm/openai.rb', line 12

def initialize(api_key: nil, model: nil, base_url: nil)
  @api_key = api_key || config.llm_api_key
  @model = model || config.llm_model
  @base_url = base_url || config.llm_base_url || DEFAULT_BASE_URL
end

Instance Method Details

#invoke(prompt) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/llmemory/llm/openai.rb', line 18

def invoke(prompt)
  result = nil
  Llmemory::Instrumentation.instrument(:llm_invoke, provider: :openai, model: @model, prompt_chars: prompt.to_s.length) do
    response = connection.post("chat/completions") do |req|
      req.body = {
        model: @model,
        messages: [{ role: "user", content: prompt }],
        temperature: 0.3
      }.to_json
      req.headers["Content-Type"] = "application/json"
      req.headers["Authorization"] = "Bearer #{@api_key}"
    end

    raise Llmemory::LLMError, "OpenAI API error: #{response.body}" unless response.success?

    body = response.body.is_a?(Hash) ? response.body : JSON.parse(response.body.to_s)
    result = body.dig("choices", 0, "message", "content")&.strip || ""
  end
  result
end

#invoke_with_json_schema(prompt, json_schema) ⇒ Object

Calls the model with response_format json_schema (Structured Outputs). Returns the parsed JSON hash. Use when the model supports structured outputs (e.g. gpt-4o, gpt-4o-mini 2024-08-06 and later).



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
# File 'lib/llmemory/llm/openai.rb', line 42

def invoke_with_json_schema(prompt, json_schema)
  payload = {
    model: @model,
    messages: [{ role: "user", content: prompt }],
    temperature: 0,
    response_format: {
      type: "json_schema",
      json_schema: {
        strict: true,
        name: json_schema[:name] || "extraction",
        schema: json_schema[:schema] || json_schema["schema"]
      }
    }
  }
  response = connection.post("chat/completions") do |req|
    req.body = payload.to_json
    req.headers["Content-Type"] = "application/json"
    req.headers["Authorization"] = "Bearer #{@api_key}"
  end

  raise Llmemory::LLMError, "OpenAI API error: #{response.body}" unless response.success?

  body = response.body.is_a?(Hash) ? response.body : JSON.parse(response.body.to_s)
  content = body.dig("choices", 0, "message", "content")&.strip
  return {} if content.nil? || content.empty?
  JSON.parse(content)
rescue JSON::ParserError => e
  raise Llmemory::LLMError, "Failed to parse JSON response: #{e.message}"
end