Module: Legion::Extensions::Llm::Gateway::Runners::UsageReporter

Defined in:
lib/legion/extensions/llm/gateway/runners/usage_reporter.rb

Constant Summary collapse

DEFAULT_BUDGET_USD =
100.0
DEFAULT_ALERT_THRESHOLD =
0.8

Class Method Summary collapse

Class Method Details

.budget_check(budget_usd: nil, threshold: nil, period: :month) ⇒ Object



32
33
34
35
36
37
38
39
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 32

def budget_check(budget_usd: nil, threshold: nil, period: :month)
  return unavailable_result unless data_connected?

  budget = budget_usd || configured_budget
  alert_at = threshold || configured_threshold
  spent = queries.metering_since(queries.period_start(period)).sum(:cost_usd).to_f
  build_budget_result(budget, spent, alert_at, period)
end

.budget_status(ratio, alert_at) ⇒ Object



86
87
88
89
90
91
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 86

def budget_status(ratio, alert_at)
  return :exceeded if ratio >= 1.0
  return :warning if ratio >= alert_at

  :ok
end

.build_budget_result(budget, spent, alert_at, period) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 74

def build_budget_result(budget, spent, alert_at, period)
  ratio = budget.positive? ? (spent / budget) : 0.0
  {
    period:    period.to_s,
    budget:    budget.round(2),
    spent:     spent.round(4),
    remaining: [(budget - spent), 0.0].max.round(4),
    ratio:     ratio.round(4),
    status:    budget_status(ratio, alert_at)
  }
end

.build_summary(dataset, period, since) ⇒ Object



56
57
58
59
60
61
62
63
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 56

def build_summary(dataset, period, since)
  queries.aggregate_totals(dataset).merge(
    period:      period.to_s,
    since:       since.iso8601,
    by_provider: queries.grouped_rows(dataset, :provider),
    by_model:    queries.grouped_rows(dataset, :model_id)
  )
end

.build_worker_summary(dataset, worker_id, period, since) ⇒ Object



65
66
67
68
69
70
71
72
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 65

def build_worker_summary(dataset, worker_id, period, since)
  queries.aggregate_totals(dataset).merge(
    worker_id: worker_id,
    period:    period.to_s,
    since:     since.iso8601,
    by_model:  queries.grouped_rows(dataset, :model_id)
  )
end

.configured_budgetObject



93
94
95
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 93

def configured_budget
  llm_setting(:budget, :monthly_usd)&.to_f || DEFAULT_BUDGET_USD
end

.configured_thresholdObject



97
98
99
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 97

def configured_threshold
  llm_setting(:budget, :alert_threshold)&.to_f || DEFAULT_ALERT_THRESHOLD
end

.data_connected?Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 52

def data_connected?
  MeteringWriter.data_connected?
end

.llm_setting(*keys) ⇒ Object



101
102
103
104
105
106
107
108
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 101

def llm_setting(*keys)
  return nil unless defined?(Legion::Settings)

  settings = Legion::Settings[:llm] rescue nil # rubocop:disable Style/RescueModifier
  return nil unless settings.is_a?(Hash)

  settings.dig(*keys)
end

.queriesObject



48
49
50
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 48

def queries
  Helpers::UsageQueries
end

.summary(since: nil, period: :day) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 16

def summary(since: nil, period: :day)
  return unavailable_result unless data_connected?

  since ||= queries.period_start(period)
  dataset = queries.metering_since(since)
  build_summary(dataset, period, since)
end

.top_consumers(since: nil, period: :day, limit: 10, group_by: :worker_id) ⇒ Object



41
42
43
44
45
46
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 41

def top_consumers(since: nil, period: :day, limit: 10, group_by: :worker_id)
  return unavailable_result unless data_connected?

  since ||= queries.period_start(period)
  queries.aggregate_by_column(queries.metering_since(since), group_by.to_sym, limit)
end

.unavailable_resultObject



110
111
112
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 110

def unavailable_result
  { success: false, error: 'data_not_connected' }
end

.worker_usage(worker_id:, since: nil, period: :day) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/legion/extensions/llm/gateway/runners/usage_reporter.rb', line 24

def worker_usage(worker_id:, since: nil, period: :day)
  return unavailable_result unless data_connected?

  since ||= queries.period_start(period)
  dataset = queries.metering_since(since).where(worker_id: worker_id)
  build_worker_summary(dataset, worker_id, period, since)
end