Class: LlmCostTracker::Dashboard::TopModels

Inherits:
Object
  • Object
show all
Defined in:
app/services/llm_cost_tracker/dashboard/top_models.rb

Constant Summary collapse

DEFAULT_LIMIT =
5
SORT_OPTIONS =
%w[cost calls avg_cost latency tokens provider name].freeze
DEFAULT_SORT =
"cost"
DEFAULT_DIRECTIONS =
{
  "provider" => "asc",
  "name" => "asc",
  "calls" => "desc",
  "tokens" => "desc",
  "latency" => "desc",
  "avg_cost" => "desc",
  "cost" => "desc"
}.freeze
ORDER_NODES =
{
  %w[provider asc]  => [{ provider: :asc, model: :asc }],
  %w[provider desc] => [{ provider: :desc, model: :asc }],
  %w[name asc]      => [{ model: :asc }],
  %w[name desc]     => [{ model: :desc }],
  %w[calls asc]     => [Arel.sql("COUNT(*) ASC")],
  %w[calls desc]    => [Arel.sql("COUNT(*) DESC")],
  %w[tokens asc]    => [Arel.sql("COALESCE(SUM(total_tokens), 0) ASC")],
  %w[tokens desc]   => [Arel.sql("COALESCE(SUM(total_tokens), 0) DESC")],
  %w[avg_cost asc]  => [Arel.sql("COALESCE(SUM(total_cost), 0) / NULLIF(COUNT(*), 0) ASC")],
  %w[avg_cost desc] => [Arel.sql("COALESCE(SUM(total_cost), 0) / NULLIF(COUNT(*), 0) DESC")],
  %w[latency asc]   => [Arel.sql("CASE WHEN AVG(latency_ms) IS NULL THEN 1 ELSE 0 END ASC, " \
                                 "AVG(latency_ms) ASC")],
  %w[latency desc]  => [Arel.sql("CASE WHEN AVG(latency_ms) IS NULL THEN 1 ELSE 0 END ASC, " \
                                 "AVG(latency_ms) DESC")],
  %w[cost asc]      => [Arel.sql("COALESCE(SUM(total_cost), 0) ASC")],
  %w[cost desc]     => [Arel.sql("COALESCE(SUM(total_cost), 0) DESC")]
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(scope:, limit:, sort: DEFAULT_SORT, direction: nil) ⇒ TopModels

Returns a new instance of TopModels.



43
44
45
46
47
48
# File 'app/services/llm_cost_tracker/dashboard/top_models.rb', line 43

def initialize(scope:, limit:, sort: DEFAULT_SORT, direction: nil)
  @scope = scope
  @limit = limit
  @sort = SORT_OPTIONS.include?(sort.to_s) ? sort.to_s : DEFAULT_SORT
  @direction = Sort::DIRECTIONS.include?(direction.to_s) ? direction.to_s : DEFAULT_DIRECTIONS[@sort]
end

Class Method Details

.call(scope: LlmCostTracker::Call.all, limit: DEFAULT_LIMIT, sort: DEFAULT_SORT, direction: nil) ⇒ Object



38
39
40
# File 'app/services/llm_cost_tracker/dashboard/top_models.rb', line 38

def call(scope: LlmCostTracker::Call.all, limit: DEFAULT_LIMIT, sort: DEFAULT_SORT, direction: nil)
  new(scope: scope, limit: limit, sort: sort, direction: direction).rows
end

Instance Method Details

#rowsObject



50
51
52
53
54
55
56
# File 'app/services/llm_cost_tracker/dashboard/top_models.rb', line 50

def rows
  scope
    .group(:provider, :model)
    .select(selects)
    .order(*ORDER_NODES.fetch([sort, direction]))
    .then { |r| limit ? r.limit(limit) : r }
end