Class: LlmCostTracker::LlmApiCall
Constant Summary
Constants included
from TagsColumn
TagsColumn::USAGE_BREAKDOWN_COLUMNS, TagsColumn::USAGE_BREAKDOWN_COST_COLUMNS
Class Method Summary
collapse
daily_costs, group_by_period
Methods included from TagsColumn
latency_column?, pricing_mode_column?, provider_response_id_column?, reset_column_information, stream_column?, tags_json_column?, tags_jsonb_column?, tags_mysql_json_column?, usage_breakdown_columns?, usage_breakdown_cost_columns?, usage_source_column?
#parsed_tags
Class Method Details
.average_latency_ms ⇒ Object
89
90
91
92
93
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 89
def self.average_latency_ms
return nil unless latency_column?
average(:latency_ms)&.to_f
end
|
.by_tag(key, value) ⇒ Object
51
52
53
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 51
def self.by_tag(key, value)
by_tags(key => value)
end
|
55
56
57
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 55
def self.by_tags(tags)
TagQuery.apply(self, tags)
end
|
.cost_by_model ⇒ Object
67
68
69
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 67
def self.cost_by_model
group(:model).sum(:total_cost)
end
|
.cost_by_provider ⇒ Object
71
72
73
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 71
def self.cost_by_provider
group(:provider).sum(:total_cost)
end
|
.cost_by_tag(key, limit: nil) ⇒ Object
79
80
81
82
83
84
85
86
87
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 79
def self.cost_by_tag(key, limit: nil)
relation = group_by_tag(key).order(Arel.sql("COALESCE(SUM(total_cost), 0) DESC"))
relation = relation.limit(limit) if limit
costs = relation.sum(:total_cost).each_with_object(Hash.new(0.0)) do |(tag_value, cost), grouped|
grouped[tag_value_label(tag_value)] += cost.to_f
end
costs.sort_by { |_label, cost| -cost }.to_h
end
|
.group_by_tag(key) ⇒ Object
75
76
77
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 75
def self.group_by_tag(key)
group(Arel.sql(tag_value_expression(key)))
end
|
.latency_by_model ⇒ Object
95
96
97
98
99
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 95
def self.latency_by_model
return {} unless latency_column?
group(:model).average(:latency_ms).transform_values(&:to_f)
end
|
.latency_by_provider ⇒ Object
101
102
103
104
105
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 101
def self.latency_by_provider
return {} unless latency_column?
group(:provider).average(:latency_ms).transform_values(&:to_f)
end
|
.tag_value_expression(key, table_name: quoted_table_name) ⇒ Object
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 111
def self.tag_value_expression(key, table_name: quoted_table_name)
key = validated_tag_key(key)
column = "#{table_name}.#{connection.quote_column_name('tags')}"
case connection.adapter_name
when /postgres/i
json_column = tags_jsonb_column? ? column : "(#{column})::jsonb"
"#{json_column}->>#{connection.quote(key)}"
when /mysql/i
"JSON_UNQUOTE(JSON_EXTRACT(#{column}, #{connection.quote(json_path(key))}))"
else
"json_extract(#{column}, #{connection.quote(json_path(key))})"
end
end
|
.tag_value_label(value) ⇒ Object
107
108
109
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 107
def self.tag_value_label(value)
value.nil? || value == "" ? "(untagged)" : value.to_s
end
|
.total_cost ⇒ Object
59
60
61
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 59
def self.total_cost
sum(:total_cost).to_f
end
|
.total_tokens ⇒ Object
63
64
65
|
# File 'lib/llm_cost_tracker/llm_api_call.rb', line 63
def self.total_tokens
sum(:total_tokens).to_i
end
|