Class: RubyLLM::Cost

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_llm/cost.rb

Overview

Represents the cost of token usage for a model response.

Constant Summary collapse

COMPONENTS =
%i[input output cache_read cache_write thinking].freeze
PER_MILLION =
1_000_000.0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tokens: nil, model: nil, amounts: nil, missing: [], has_tokens: nil, category: :text_tokens, input_details: nil) ⇒ Cost

rubocop:disable Metrics/ParameterLists



27
28
29
30
31
32
33
34
35
36
# File 'lib/ruby_llm/cost.rb', line 27

def initialize(tokens: nil, model: nil, amounts: nil, missing: [], has_tokens: nil, category: :text_tokens,
               input_details: nil)
  @tokens = tokens
  @model = normalize_model(model)
  @amounts = amounts
  @missing = missing
  @has_tokens = has_tokens
  @category = category.to_sym
  @input_details = input_details
end

Instance Attribute Details

#categoryObject (readonly)

Returns the value of attribute category.



9
10
11
# File 'lib/ruby_llm/cost.rb', line 9

def category
  @category
end

#modelObject (readonly)

Returns the value of attribute model.



9
10
11
# File 'lib/ruby_llm/cost.rb', line 9

def model
  @model
end

#tokensObject (readonly)

Returns the value of attribute tokens.



9
10
11
# File 'lib/ruby_llm/cost.rb', line 9

def tokens
  @tokens
end

Class Method Details

.aggregate(costs) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/ruby_llm/cost.rb', line 11

def self.aggregate(costs)
  costs = costs.compact.select(&:tokens?)
  return new(amounts: {}, has_tokens: false) if costs.empty?

  missing = COMPONENTS.select do |component|
    costs.any? { |cost| cost.missing?(component) }
  end

  amounts = COMPONENTS.to_h do |component|
    [component, missing.include?(component) ? nil : aggregate_component(costs, component)]
  end

  new(amounts:, missing:, has_tokens: true)
end

Instance Method Details

#cache_readObject Also known as: cached_input



47
48
49
# File 'lib/ruby_llm/cost.rb', line 47

def cache_read
  amount_for(:cache_read)
end

#cache_writeObject Also known as: cache_creation



51
52
53
# File 'lib/ruby_llm/cost.rb', line 51

def cache_write
  amount_for(:cache_write)
end

#inputObject

rubocop:enable Metrics/ParameterLists



39
40
41
# File 'lib/ruby_llm/cost.rb', line 39

def input
  amount_for(:input)
end

#missing?(component) ⇒ Boolean

Returns:

  • (Boolean)


91
92
93
94
95
96
97
98
# File 'lib/ruby_llm/cost.rb', line 91

def missing?(component)
  return @missing.include?(component) if aggregate?
  return image_input_missing? if component == :input && detailed_image_input?
  return false if component == :thinking && !thinking_priced_separately?

  tokens = tokens_for(component)
  tokens.to_i.positive? && price_for(component).nil?
end

#outputObject



43
44
45
# File 'lib/ruby_llm/cost.rb', line 43

def output
  amount_for(:output)
end

#thinkingObject Also known as: reasoning



55
56
57
# File 'lib/ruby_llm/cost.rb', line 55

def thinking
  amount_for(:thinking)
end

#to_hObject



74
75
76
77
78
79
80
81
82
83
# File 'lib/ruby_llm/cost.rb', line 74

def to_h
  {
    input: input,
    output: output,
    cache_read: cache_read,
    cache_write: cache_write,
    thinking: thinking,
    total: total
  }.compact
end

#tokens?Boolean

Returns:

  • (Boolean)


85
86
87
88
89
# File 'lib/ruby_llm/cost.rb', line 85

def tokens?
  return @has_tokens unless @has_tokens.nil?

  COMPONENTS.any? { |component| !tokens_for(component).nil? }
end

#totalObject



64
65
66
67
68
69
70
71
72
# File 'lib/ruby_llm/cost.rb', line 64

def total
  return nil unless tokens?
  return nil if COMPONENTS.any? { |component| missing?(component) }

  costs = COMPONENTS.filter_map { |component| public_send(component) }
  return nil if costs.empty?

  costs.sum
end