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"
DEFAULT_MODEL =
"gpt-4"

Instance Attribute Summary

Attributes inherited from Base

#last_usage

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of OpenAI.



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

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

Instance Method Details

#invoke(prompt) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/llmemory/llm/openai.rb', line 20

def invoke(prompt)
  result = nil
  payload = { provider: :openai, model: @model, prompt_chars: prompt.to_s.length }
  Llmemory::Instrumentation.instrument(:llm_invoke, payload) 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)
    content = body.dig("choices", 0, "message", "content")&.strip || ""
    usage = parse_openai_chat_usage(body["usage"])
    record_usage(usage)
    payload.merge!(instrumentation_payload(usage, content))
    result = Response.new(content, usage: usage)
  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).



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

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"]
      }
    }
  }
  parsed = nil
  instrument_payload = { provider: :openai, model: @model, prompt_chars: prompt.to_s.length }
  Llmemory::Instrumentation.instrument(:llm_invoke, instrument_payload) do
    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
    usage = parse_openai_chat_usage(body["usage"])
    record_usage(usage)
    instrument_payload.merge!(instrumentation_payload(usage, content.to_s))
    return {} if content.nil? || content.empty?

    parsed = JSON.parse(content)
  end
  parsed
rescue JSON::ParserError => e
  raise Llmemory::LLMError, "Failed to parse JSON response: #{e.message}"
end