llm_cost_tracker 0.1.4 → 0.2.0.alpha2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -91
- data/PLAN_0.2.md +488 -0
- data/README.md +140 -320
- data/app/controllers/llm_cost_tracker/application_controller.rb +42 -0
- data/app/controllers/llm_cost_tracker/calls_controller.rb +77 -0
- data/app/controllers/llm_cost_tracker/dashboard_controller.rb +54 -0
- data/app/controllers/llm_cost_tracker/data_quality_controller.rb +10 -0
- data/app/controllers/llm_cost_tracker/models_controller.rb +12 -0
- data/app/controllers/llm_cost_tracker/tags_controller.rb +21 -0
- data/app/helpers/llm_cost_tracker/application_helper.rb +113 -0
- data/app/services/llm_cost_tracker/dashboard/data_quality.rb +38 -0
- data/app/services/llm_cost_tracker/dashboard/filter.rb +109 -0
- data/app/services/llm_cost_tracker/dashboard/overview_stats.rb +87 -0
- data/app/services/llm_cost_tracker/dashboard/provider_breakdown.rb +44 -0
- data/app/services/llm_cost_tracker/dashboard/tag_breakdown.rb +58 -0
- data/app/services/llm_cost_tracker/dashboard/tag_key_explorer.rb +125 -0
- data/app/services/llm_cost_tracker/dashboard/time_series.rb +44 -0
- data/app/services/llm_cost_tracker/dashboard/top_models.rb +89 -0
- data/app/services/llm_cost_tracker/pagination.rb +59 -0
- data/app/views/layouts/llm_cost_tracker/application.html.erb +342 -0
- data/app/views/llm_cost_tracker/calls/index.html.erb +127 -0
- data/app/views/llm_cost_tracker/calls/show.html.erb +67 -0
- data/app/views/llm_cost_tracker/dashboard/index.html.erb +145 -0
- data/app/views/llm_cost_tracker/data_quality/index.html.erb +110 -0
- data/app/views/llm_cost_tracker/errors/database.html.erb +8 -0
- data/app/views/llm_cost_tracker/errors/invalid_filter.html.erb +4 -0
- data/app/views/llm_cost_tracker/errors/not_found.html.erb +5 -0
- data/app/views/llm_cost_tracker/models/index.html.erb +95 -0
- data/app/views/llm_cost_tracker/shared/_bar.html.erb +5 -0
- data/app/views/llm_cost_tracker/shared/setup_required.html.erb +6 -0
- data/app/views/llm_cost_tracker/tags/index.html.erb +34 -0
- data/app/views/llm_cost_tracker/tags/show.html.erb +69 -0
- data/config/routes.rb +10 -0
- data/lib/llm_cost_tracker/budget.rb +16 -38
- data/lib/llm_cost_tracker/configuration.rb +3 -1
- data/lib/llm_cost_tracker/cost.rb +1 -3
- data/lib/llm_cost_tracker/engine.rb +13 -0
- data/lib/llm_cost_tracker/engine_compatibility.rb +15 -0
- data/lib/llm_cost_tracker/errors.rb +2 -0
- data/lib/llm_cost_tracker/event.rb +1 -3
- data/lib/llm_cost_tracker/event_metadata.rb +9 -18
- data/lib/llm_cost_tracker/llm_api_call.rb +4 -17
- data/lib/llm_cost_tracker/middleware/faraday.rb +4 -4
- data/lib/llm_cost_tracker/parsed_usage.rb +5 -9
- data/lib/llm_cost_tracker/parsers/anthropic.rb +4 -5
- data/lib/llm_cost_tracker/parsers/base.rb +3 -8
- data/lib/llm_cost_tracker/parsers/gemini.rb +3 -3
- data/lib/llm_cost_tracker/parsers/openai_usage.rb +3 -3
- data/lib/llm_cost_tracker/parsers/registry.rb +5 -12
- data/lib/llm_cost_tracker/period_grouping.rb +68 -0
- data/lib/llm_cost_tracker/price_registry.rb +22 -30
- data/lib/llm_cost_tracker/pricing.rb +10 -19
- data/lib/llm_cost_tracker/report.rb +4 -4
- data/lib/llm_cost_tracker/report_data.rb +21 -24
- data/lib/llm_cost_tracker/report_formatter.rb +4 -2
- data/lib/llm_cost_tracker/storage/active_record_store.rb +1 -3
- data/lib/llm_cost_tracker/tag_key.rb +16 -0
- data/lib/llm_cost_tracker/tracker.rb +35 -1
- data/lib/llm_cost_tracker/version.rb +1 -1
- data/lib/llm_cost_tracker.rb +3 -6
- data/llm_cost_tracker.gemspec +13 -9
- metadata +91 -20
- data/.rubocop.yml +0 -44
- data/lib/llm_cost_tracker/storage/active_record_backend.rb +0 -19
- data/lib/llm_cost_tracker/storage/backends.rb +0 -26
- data/lib/llm_cost_tracker/storage/custom_backend.rb +0 -16
- data/lib/llm_cost_tracker/storage/log_backend.rb +0 -28
- data/lib/llm_cost_tracker/value_object.rb +0 -45
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: llm_cost_tracker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0.alpha2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sergii Khomenko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -16,7 +16,7 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '7.
|
|
19
|
+
version: '7.1'
|
|
20
20
|
- - "<"
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
22
|
version: '9.0'
|
|
@@ -26,17 +26,31 @@ dependencies:
|
|
|
26
26
|
requirements:
|
|
27
27
|
- - ">="
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: '7.
|
|
29
|
+
version: '7.1'
|
|
30
30
|
- - "<"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: '9.0'
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: csv
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '3.0'
|
|
40
|
+
type: :runtime
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.0'
|
|
33
47
|
- !ruby/object:Gem::Dependency
|
|
34
48
|
name: faraday
|
|
35
49
|
requirement: !ruby/object:Gem::Requirement
|
|
36
50
|
requirements:
|
|
37
51
|
- - ">="
|
|
38
52
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '
|
|
53
|
+
version: '2.0'
|
|
40
54
|
- - "<"
|
|
41
55
|
- !ruby/object:Gem::Version
|
|
42
56
|
version: '3.0'
|
|
@@ -46,7 +60,7 @@ dependencies:
|
|
|
46
60
|
requirements:
|
|
47
61
|
- - ">="
|
|
48
62
|
- !ruby/object:Gem::Version
|
|
49
|
-
version: '
|
|
63
|
+
version: '2.0'
|
|
50
64
|
- - "<"
|
|
51
65
|
- !ruby/object:Gem::Version
|
|
52
66
|
version: '3.0'
|
|
@@ -56,7 +70,27 @@ dependencies:
|
|
|
56
70
|
requirements:
|
|
57
71
|
- - ">="
|
|
58
72
|
- !ruby/object:Gem::Version
|
|
59
|
-
version: '7.
|
|
73
|
+
version: '7.1'
|
|
74
|
+
- - "<"
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '9.0'
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
80
|
+
requirements:
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '7.1'
|
|
84
|
+
- - "<"
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '9.0'
|
|
87
|
+
- !ruby/object:Gem::Dependency
|
|
88
|
+
name: railties
|
|
89
|
+
requirement: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '7.1'
|
|
60
94
|
- - "<"
|
|
61
95
|
- !ruby/object:Gem::Version
|
|
62
96
|
version: '9.0'
|
|
@@ -66,7 +100,7 @@ dependencies:
|
|
|
66
100
|
requirements:
|
|
67
101
|
- - ">="
|
|
68
102
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: '7.
|
|
103
|
+
version: '7.1'
|
|
70
104
|
- - "<"
|
|
71
105
|
- !ruby/object:Gem::Version
|
|
72
106
|
version: '9.0'
|
|
@@ -116,16 +150,22 @@ dependencies:
|
|
|
116
150
|
name: sqlite3
|
|
117
151
|
requirement: !ruby/object:Gem::Requirement
|
|
118
152
|
requirements:
|
|
119
|
-
- - "
|
|
153
|
+
- - ">="
|
|
120
154
|
- !ruby/object:Gem::Version
|
|
121
|
-
version: '
|
|
155
|
+
version: '1.4'
|
|
156
|
+
- - "<"
|
|
157
|
+
- !ruby/object:Gem::Version
|
|
158
|
+
version: '3.0'
|
|
122
159
|
type: :development
|
|
123
160
|
prerelease: false
|
|
124
161
|
version_requirements: !ruby/object:Gem::Requirement
|
|
125
162
|
requirements:
|
|
126
|
-
- - "
|
|
163
|
+
- - ">="
|
|
127
164
|
- !ruby/object:Gem::Version
|
|
128
|
-
version: '
|
|
165
|
+
version: '1.4'
|
|
166
|
+
- - "<"
|
|
167
|
+
- !ruby/object:Gem::Version
|
|
168
|
+
version: '3.0'
|
|
129
169
|
- !ruby/object:Gem::Dependency
|
|
130
170
|
name: webmock
|
|
131
171
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -142,7 +182,7 @@ dependencies:
|
|
|
142
182
|
version: '3.0'
|
|
143
183
|
description: Tracks token usage and estimated costs for OpenAI, Anthropic, Google
|
|
144
184
|
Gemini, OpenRouter, DeepSeek, and OpenAI-compatible calls. Works as Faraday middleware
|
|
145
|
-
for Ruby clients, with ActiveRecord storage,
|
|
185
|
+
for Ruby clients, with ActiveRecord storage, arbitrary tag-based attribution, and
|
|
146
186
|
budget guardrails.
|
|
147
187
|
email:
|
|
148
188
|
- sergey@mm.st
|
|
@@ -151,15 +191,47 @@ extensions: []
|
|
|
151
191
|
extra_rdoc_files: []
|
|
152
192
|
files:
|
|
153
193
|
- ".rspec"
|
|
154
|
-
- ".rubocop.yml"
|
|
155
194
|
- CHANGELOG.md
|
|
156
195
|
- LICENSE.txt
|
|
196
|
+
- PLAN_0.2.md
|
|
157
197
|
- README.md
|
|
158
198
|
- Rakefile
|
|
199
|
+
- app/controllers/llm_cost_tracker/application_controller.rb
|
|
200
|
+
- app/controllers/llm_cost_tracker/calls_controller.rb
|
|
201
|
+
- app/controllers/llm_cost_tracker/dashboard_controller.rb
|
|
202
|
+
- app/controllers/llm_cost_tracker/data_quality_controller.rb
|
|
203
|
+
- app/controllers/llm_cost_tracker/models_controller.rb
|
|
204
|
+
- app/controllers/llm_cost_tracker/tags_controller.rb
|
|
205
|
+
- app/helpers/llm_cost_tracker/application_helper.rb
|
|
206
|
+
- app/services/llm_cost_tracker/dashboard/data_quality.rb
|
|
207
|
+
- app/services/llm_cost_tracker/dashboard/filter.rb
|
|
208
|
+
- app/services/llm_cost_tracker/dashboard/overview_stats.rb
|
|
209
|
+
- app/services/llm_cost_tracker/dashboard/provider_breakdown.rb
|
|
210
|
+
- app/services/llm_cost_tracker/dashboard/tag_breakdown.rb
|
|
211
|
+
- app/services/llm_cost_tracker/dashboard/tag_key_explorer.rb
|
|
212
|
+
- app/services/llm_cost_tracker/dashboard/time_series.rb
|
|
213
|
+
- app/services/llm_cost_tracker/dashboard/top_models.rb
|
|
214
|
+
- app/services/llm_cost_tracker/pagination.rb
|
|
215
|
+
- app/views/layouts/llm_cost_tracker/application.html.erb
|
|
216
|
+
- app/views/llm_cost_tracker/calls/index.html.erb
|
|
217
|
+
- app/views/llm_cost_tracker/calls/show.html.erb
|
|
218
|
+
- app/views/llm_cost_tracker/dashboard/index.html.erb
|
|
219
|
+
- app/views/llm_cost_tracker/data_quality/index.html.erb
|
|
220
|
+
- app/views/llm_cost_tracker/errors/database.html.erb
|
|
221
|
+
- app/views/llm_cost_tracker/errors/invalid_filter.html.erb
|
|
222
|
+
- app/views/llm_cost_tracker/errors/not_found.html.erb
|
|
223
|
+
- app/views/llm_cost_tracker/models/index.html.erb
|
|
224
|
+
- app/views/llm_cost_tracker/shared/_bar.html.erb
|
|
225
|
+
- app/views/llm_cost_tracker/shared/setup_required.html.erb
|
|
226
|
+
- app/views/llm_cost_tracker/tags/index.html.erb
|
|
227
|
+
- app/views/llm_cost_tracker/tags/show.html.erb
|
|
228
|
+
- config/routes.rb
|
|
159
229
|
- lib/llm_cost_tracker.rb
|
|
160
230
|
- lib/llm_cost_tracker/budget.rb
|
|
161
231
|
- lib/llm_cost_tracker/configuration.rb
|
|
162
232
|
- lib/llm_cost_tracker/cost.rb
|
|
233
|
+
- lib/llm_cost_tracker/engine.rb
|
|
234
|
+
- lib/llm_cost_tracker/engine_compatibility.rb
|
|
163
235
|
- lib/llm_cost_tracker/errors.rb
|
|
164
236
|
- lib/llm_cost_tracker/event.rb
|
|
165
237
|
- lib/llm_cost_tracker/event_metadata.rb
|
|
@@ -185,6 +257,7 @@ files:
|
|
|
185
257
|
- lib/llm_cost_tracker/parsers/openai_compatible.rb
|
|
186
258
|
- lib/llm_cost_tracker/parsers/openai_usage.rb
|
|
187
259
|
- lib/llm_cost_tracker/parsers/registry.rb
|
|
260
|
+
- lib/llm_cost_tracker/period_grouping.rb
|
|
188
261
|
- lib/llm_cost_tracker/price_registry.rb
|
|
189
262
|
- lib/llm_cost_tracker/prices.json
|
|
190
263
|
- lib/llm_cost_tracker/pricing.rb
|
|
@@ -192,17 +265,13 @@ files:
|
|
|
192
265
|
- lib/llm_cost_tracker/report.rb
|
|
193
266
|
- lib/llm_cost_tracker/report_data.rb
|
|
194
267
|
- lib/llm_cost_tracker/report_formatter.rb
|
|
195
|
-
- lib/llm_cost_tracker/storage/active_record_backend.rb
|
|
196
268
|
- lib/llm_cost_tracker/storage/active_record_store.rb
|
|
197
|
-
- lib/llm_cost_tracker/storage/backends.rb
|
|
198
|
-
- lib/llm_cost_tracker/storage/custom_backend.rb
|
|
199
|
-
- lib/llm_cost_tracker/storage/log_backend.rb
|
|
200
269
|
- lib/llm_cost_tracker/tag_accessors.rb
|
|
270
|
+
- lib/llm_cost_tracker/tag_key.rb
|
|
201
271
|
- lib/llm_cost_tracker/tag_query.rb
|
|
202
272
|
- lib/llm_cost_tracker/tags_column.rb
|
|
203
273
|
- lib/llm_cost_tracker/tracker.rb
|
|
204
274
|
- lib/llm_cost_tracker/unknown_pricing.rb
|
|
205
|
-
- lib/llm_cost_tracker/value_object.rb
|
|
206
275
|
- lib/llm_cost_tracker/version.rb
|
|
207
276
|
- lib/tasks/llm_cost_tracker.rake
|
|
208
277
|
- llm_cost_tracker.gemspec
|
|
@@ -211,6 +280,8 @@ licenses:
|
|
|
211
280
|
- MIT
|
|
212
281
|
metadata:
|
|
213
282
|
homepage_uri: https://github.com/sergey-homenko/llm_cost_tracker
|
|
283
|
+
source_code_uri: https://github.com/sergey-homenko/llm_cost_tracker
|
|
284
|
+
bug_tracker_uri: https://github.com/sergey-homenko/llm_cost_tracker/issues
|
|
214
285
|
changelog_uri: https://github.com/sergey-homenko/llm_cost_tracker/blob/main/CHANGELOG.md
|
|
215
286
|
rubygems_mfa_required: 'true'
|
|
216
287
|
post_install_message:
|
|
@@ -221,7 +292,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
221
292
|
requirements:
|
|
222
293
|
- - ">="
|
|
223
294
|
- !ruby/object:Gem::Version
|
|
224
|
-
version: 3.
|
|
295
|
+
version: 3.3.0
|
|
225
296
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
226
297
|
requirements:
|
|
227
298
|
- - ">="
|
data/.rubocop.yml
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
AllCops:
|
|
2
|
-
NewCops: enable
|
|
3
|
-
TargetRubyVersion: 3.1
|
|
4
|
-
SuggestExtensions: false
|
|
5
|
-
UseCache: false
|
|
6
|
-
Exclude:
|
|
7
|
-
- "tmp/**/*"
|
|
8
|
-
- "vendor/**/*"
|
|
9
|
-
- "pkg/**/*"
|
|
10
|
-
|
|
11
|
-
Style/Documentation:
|
|
12
|
-
Enabled: false
|
|
13
|
-
|
|
14
|
-
Style/StringLiterals:
|
|
15
|
-
EnforcedStyle: double_quotes
|
|
16
|
-
|
|
17
|
-
Metrics/BlockLength:
|
|
18
|
-
Exclude:
|
|
19
|
-
- "*.gemspec"
|
|
20
|
-
- "spec/**/*.rb"
|
|
21
|
-
|
|
22
|
-
Metrics/MethodLength:
|
|
23
|
-
Max: 25
|
|
24
|
-
|
|
25
|
-
Metrics/AbcSize:
|
|
26
|
-
Max: 45
|
|
27
|
-
|
|
28
|
-
Metrics/ClassLength:
|
|
29
|
-
Max: 130
|
|
30
|
-
|
|
31
|
-
Metrics/CyclomaticComplexity:
|
|
32
|
-
Max: 10
|
|
33
|
-
|
|
34
|
-
Metrics/ParameterLists:
|
|
35
|
-
Max: 6
|
|
36
|
-
|
|
37
|
-
Metrics/PerceivedComplexity:
|
|
38
|
-
Max: 10
|
|
39
|
-
|
|
40
|
-
Gemspec/DevelopmentDependencies:
|
|
41
|
-
Enabled: false
|
|
42
|
-
|
|
43
|
-
Layout/HashAlignment:
|
|
44
|
-
Enabled: false
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LlmCostTracker
|
|
4
|
-
module Storage
|
|
5
|
-
module ActiveRecordBackend
|
|
6
|
-
class << self
|
|
7
|
-
def save(event, **_options)
|
|
8
|
-
require_relative "../llm_api_call" unless defined?(LlmCostTracker::LlmApiCall)
|
|
9
|
-
require_relative "active_record_store" unless defined?(LlmCostTracker::Storage::ActiveRecordStore)
|
|
10
|
-
|
|
11
|
-
ActiveRecordStore.save(event)
|
|
12
|
-
event
|
|
13
|
-
rescue LoadError => e
|
|
14
|
-
raise Error, "ActiveRecord storage requires the active_record gem: #{e.message}"
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../errors"
|
|
4
|
-
require_relative "log_backend"
|
|
5
|
-
require_relative "active_record_backend"
|
|
6
|
-
require_relative "custom_backend"
|
|
7
|
-
|
|
8
|
-
module LlmCostTracker
|
|
9
|
-
module Storage
|
|
10
|
-
module Backends
|
|
11
|
-
MAP = {
|
|
12
|
-
log: LogBackend,
|
|
13
|
-
active_record: ActiveRecordBackend,
|
|
14
|
-
custom: CustomBackend
|
|
15
|
-
}.freeze
|
|
16
|
-
|
|
17
|
-
class << self
|
|
18
|
-
def fetch(name)
|
|
19
|
-
MAP.fetch(name.to_sym)
|
|
20
|
-
rescue KeyError
|
|
21
|
-
raise Error, "Unknown storage_backend: #{name.inspect}. Use one of: #{MAP.keys.join(', ')}"
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LlmCostTracker
|
|
4
|
-
module Storage
|
|
5
|
-
module CustomBackend
|
|
6
|
-
class << self
|
|
7
|
-
def save(event, config:)
|
|
8
|
-
result = config.custom_storage&.call(event)
|
|
9
|
-
return false if result == false
|
|
10
|
-
|
|
11
|
-
event
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../logging"
|
|
4
|
-
|
|
5
|
-
module LlmCostTracker
|
|
6
|
-
module Storage
|
|
7
|
-
module LogBackend
|
|
8
|
-
class << self
|
|
9
|
-
def save(event, config:)
|
|
10
|
-
message = "#{event.provider}/#{event.model} " \
|
|
11
|
-
"tokens=#{event.input_tokens}+#{event.output_tokens} " \
|
|
12
|
-
"cost=#{cost_label(event)}"
|
|
13
|
-
message += " latency=#{event.latency_ms}ms" if event.latency_ms
|
|
14
|
-
message += " tags=#{event.tags}" unless event.tags.empty?
|
|
15
|
-
|
|
16
|
-
Logging.log(config.log_level, message)
|
|
17
|
-
event
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def cost_label(event)
|
|
23
|
-
event.cost ? "$#{format('%.6f', event.cost.total_cost)}" : "unknown"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LlmCostTracker
|
|
4
|
-
module ValueObject
|
|
5
|
-
class << self
|
|
6
|
-
def define(*members, &block)
|
|
7
|
-
klass = data_class(*members)
|
|
8
|
-
add_hash_like_readers(klass)
|
|
9
|
-
klass.class_eval(&block) if block
|
|
10
|
-
klass
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
def data_class(*members)
|
|
16
|
-
return Data.define(*members) if defined?(Data)
|
|
17
|
-
|
|
18
|
-
Struct.new(*members, keyword_init: true) do
|
|
19
|
-
def initialize(**kwargs)
|
|
20
|
-
super
|
|
21
|
-
freeze
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def add_hash_like_readers(klass)
|
|
27
|
-
klass.class_eval do
|
|
28
|
-
def [](key)
|
|
29
|
-
public_send(key.to_sym)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def dig(key, *rest)
|
|
33
|
-
value = self[key]
|
|
34
|
-
rest.empty? ? value : value&.dig(*rest)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def except(*keys)
|
|
38
|
-
excluded = keys.map(&:to_sym)
|
|
39
|
-
to_h.reject { |key, _value| excluded.include?(key.to_sym) }
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|