Class: OpenRouter::UsageTracker

Inherits:
Object
  • Object
show all
Defined in:
lib/open_router/usage_tracker.rb

Overview

Tracks token usage and costs across API calls

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeUsageTracker

Returns a new instance of UsageTracker.



9
10
11
# File 'lib/open_router/usage_tracker.rb', line 9

def initialize
  reset!
end

Instance Attribute Details

#model_usageObject (readonly)

Returns the value of attribute model_usage.



6
7
8
# File 'lib/open_router/usage_tracker.rb', line 6

def model_usage
  @model_usage
end

#request_countObject (readonly)

Returns the value of attribute request_count.



6
7
8
# File 'lib/open_router/usage_tracker.rb', line 6

def request_count
  @request_count
end

#session_startObject (readonly)

Returns the value of attribute session_start.



6
7
8
# File 'lib/open_router/usage_tracker.rb', line 6

def session_start
  @session_start
end

#total_cached_tokensObject (readonly)

Returns the value of attribute total_cached_tokens.



6
7
8
# File 'lib/open_router/usage_tracker.rb', line 6

def total_cached_tokens
  @total_cached_tokens
end

#total_completion_tokensObject (readonly)

Returns the value of attribute total_completion_tokens.



6
7
8
# File 'lib/open_router/usage_tracker.rb', line 6

def total_completion_tokens
  @total_completion_tokens
end

#total_costObject (readonly)

Returns the value of attribute total_cost.



6
7
8
# File 'lib/open_router/usage_tracker.rb', line 6

def total_cost
  @total_cost
end

#total_prompt_tokensObject (readonly)

Returns the value of attribute total_prompt_tokens.



6
7
8
# File 'lib/open_router/usage_tracker.rb', line 6

def total_prompt_tokens
  @total_prompt_tokens
end

Instance Method Details

#average_cost_per_requestObject

Get average cost per request



81
82
83
84
85
# File 'lib/open_router/usage_tracker.rb', line 81

def average_cost_per_request
  return 0 if @request_count.zero?

  @total_cost / @request_count
end

#average_tokens_per_requestObject

Get average tokens per request



74
75
76
77
78
# File 'lib/open_router/usage_tracker.rb', line 74

def average_tokens_per_request
  return 0 if @request_count.zero?

  total_tokens.to_f / @request_count
end

#cache_hit_rateObject

Get cache hit rate



115
116
117
118
119
# File 'lib/open_router/usage_tracker.rb', line 115

def cache_hit_rate
  return 0 if @total_prompt_tokens.zero?

  (@total_cached_tokens.to_f / @total_prompt_tokens) * 100
end

#export_csvObject

Export usage history as CSV



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/open_router/usage_tracker.rb', line 165

def export_csv
  require "csv"

  CSV.generate do |csv|
    csv << ["Timestamp", "Model", "Prompt Tokens", "Completion Tokens", "Cached Tokens", "Cost", "Response ID"]
    @request_history.each do |entry|
      csv << [
        entry[:timestamp].iso8601,
        entry[:model],
        entry[:prompt_tokens],
        entry[:completion_tokens],
        entry[:cached_tokens],
        entry[:cost]&.round(4),
        entry[:response_id]
      ]
    end
  end
end

#history(limit: nil) ⇒ Object

Get request history



185
186
187
# File 'lib/open_router/usage_tracker.rb', line 185

def history(limit: nil)
  limit ? @request_history.last(limit) : @request_history
end

#model_breakdownObject

Get model usage breakdown



153
154
155
156
157
158
159
160
161
162
# File 'lib/open_router/usage_tracker.rb', line 153

def model_breakdown
  @model_usage.transform_values do |stats|
    {
      requests: stats[:requests],
      tokens: stats[:prompt_tokens] + stats[:completion_tokens],
      cost: stats[:cost].round(4),
      cached_tokens: stats[:cached_tokens]
    }
  end
end

#most_expensive_modelObject

Get most expensive model



108
109
110
111
112
# File 'lib/open_router/usage_tracker.rb', line 108

def most_expensive_model
  return nil if @model_usage.empty?

  @model_usage.max_by { |_, stats| stats[:cost] }&.first
end

#most_used_modelObject

Get most used model



101
102
103
104
105
# File 'lib/open_router/usage_tracker.rb', line 101

def most_used_model
  return nil if @model_usage.empty?

  @model_usage.max_by { |_, stats| stats[:requests] }&.first
end

Pretty print summary to console



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/open_router/usage_tracker.rb', line 190

def print_summary
  summary_data = summary

  puts "\n#{"=" * 60}"
  puts " OpenRouter Usage Summary"
  puts "=" * 60

  puts "\nšŸ“Š Session"
  puts "  Started: #{summary_data[:session][:start].strftime("%Y-%m-%d %H:%M:%S")}"
  puts "  Duration: #{format_duration(summary_data[:session][:duration_seconds])}"
  puts "  Requests: #{summary_data[:session][:requests]}"

  puts "\nšŸ”¤ Tokens"
  puts "  Total: #{format_number(summary_data[:tokens][:total])}"
  puts "  Prompt: #{format_number(summary_data[:tokens][:prompt])}"
  puts "  Completion: #{format_number(summary_data[:tokens][:completion])}"
  puts "  Cached: #{format_number(summary_data[:tokens][:cached])} (#{summary_data[:tokens][:cache_hit_rate]})"

  puts "\nšŸ’° Cost"
  puts "  Total: $#{summary_data[:cost][:total]}"
  puts "  Average/Request: $#{summary_data[:cost][:average_per_request]}"

  puts "\n⚔ Performance"
  puts "  Tokens/Second: #{summary_data[:performance][:tokens_per_second]}"
  puts "  Average Tokens/Request: #{summary_data[:performance][:average_tokens_per_request]}"

  if summary_data[:models][:breakdown].any?
    puts "\nšŸ¤– Models Used"
    summary_data[:models][:breakdown].each do |model, stats|
      puts "  #{model}:"
      puts "    Requests: #{stats[:requests]}"
      puts "    Tokens: #{format_number(stats[:tokens])}"
      puts "    Cost: $#{stats[:cost]}"
    end
  end

  puts "\n#{"=" * 60}"
end

#reset!Object

Reset all tracking counters



14
15
16
17
18
19
20
21
22
23
# File 'lib/open_router/usage_tracker.rb', line 14

def reset!
  @total_prompt_tokens = 0
  @total_completion_tokens = 0
  @total_cached_tokens = 0
  @total_cost = 0.0
  @request_count = 0
  @model_usage = Hash.new { |h, k| h[k] = create_model_stats }
  @session_start = Time.now
  @request_history = []
end

#session_durationObject

Get session duration in seconds



88
89
90
# File 'lib/open_router/usage_tracker.rb', line 88

def session_duration
  Time.now - @session_start
end

#summaryObject

Get usage summary



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/open_router/usage_tracker.rb', line 122

def summary
  {
    session: {
      start: @session_start,
      duration_seconds: session_duration,
      requests: @request_count
    },
    tokens: {
      total: total_tokens,
      prompt: @total_prompt_tokens,
      completion: @total_completion_tokens,
      cached: @total_cached_tokens,
      cache_hit_rate: "#{cache_hit_rate.round(2)}%"
    },
    cost: {
      total: @total_cost.round(4),
      average_per_request: average_cost_per_request.round(4)
    },
    performance: {
      tokens_per_second: tokens_per_second.round(2),
      average_tokens_per_request: average_tokens_per_request.round(0)
    },
    models: {
      most_used: most_used_model,
      most_expensive: most_expensive_model,
      breakdown: model_breakdown
    }
  }
end

#tokens_per_secondObject

Get tokens per second



93
94
95
96
97
98
# File 'lib/open_router/usage_tracker.rb', line 93

def tokens_per_second
  duration = session_duration
  return 0 if duration.zero?

  total_tokens.to_f / duration
end

#total_tokensObject

Get total tokens used



69
70
71
# File 'lib/open_router/usage_tracker.rb', line 69

def total_tokens
  @total_prompt_tokens + @total_completion_tokens
end

#track(response, model: nil) ⇒ Object

Track usage from a response

Parameters:

  • response (Response)

    The response object to track

  • model (String) (defaults to: nil)

    The model used (optional, will try to get from response)



29
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
# File 'lib/open_router/usage_tracker.rb', line 29

def track(response, model: nil)
  return unless response

  model ||= response.model
  prompt_tokens = response.prompt_tokens
  completion_tokens = response.completion_tokens
  cached_tokens = response.cached_tokens
  cost = response.cost_estimate || estimate_cost(model, prompt_tokens, completion_tokens)

  # Update totals
  @total_prompt_tokens += prompt_tokens
  @total_completion_tokens += completion_tokens
  @total_cached_tokens += cached_tokens
  @total_cost += cost if cost
  @request_count += 1

  # Update per-model stats
  if model
    @model_usage[model][:prompt_tokens] += prompt_tokens
    @model_usage[model][:completion_tokens] += completion_tokens
    @model_usage[model][:cached_tokens] += cached_tokens
    @model_usage[model][:cost] += cost if cost
    @model_usage[model][:requests] += 1
  end

  # Store in history
  @request_history << {
    timestamp: Time.now,
    model: model,
    prompt_tokens: prompt_tokens,
    completion_tokens: completion_tokens,
    cached_tokens: cached_tokens,
    cost: cost,
    response_id: response.id
  }

  self
end