llm_cost_tracker 0.13.0 → 0.14.0

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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +53 -16
  3. data/README.md +16 -28
  4. data/app/controllers/llm_cost_tracker/application_controller.rb +3 -2
  5. data/app/controllers/llm_cost_tracker/data_quality_controller.rb +1 -0
  6. data/app/controllers/llm_cost_tracker/models_controller.rb +3 -1
  7. data/app/helpers/llm_cost_tracker/dashboard_query_helper.rb +11 -0
  8. data/app/models/llm_cost_tracker/call.rb +9 -3
  9. data/app/models/llm_cost_tracker/call_rollup.rb +19 -3
  10. data/app/services/llm_cost_tracker/dashboard/data_quality.rb +13 -0
  11. data/app/services/llm_cost_tracker/dashboard/monthly_budget.rb +1 -1
  12. data/app/services/llm_cost_tracker/dashboard/pagination.rb +2 -1
  13. data/app/services/llm_cost_tracker/dashboard/pricing_overview.rb +3 -3
  14. data/app/services/llm_cost_tracker/dashboard/setup_state.rb +5 -3
  15. data/app/views/llm_cost_tracker/calls/show.html.erb +6 -8
  16. data/app/views/llm_cost_tracker/data_quality/index.html.erb +11 -0
  17. data/app/views/llm_cost_tracker/shared/_filter_pill_date.html.erb +1 -3
  18. data/app/views/llm_cost_tracker/shared/_filter_pill_model.html.erb +1 -3
  19. data/app/views/llm_cost_tracker/shared/_filter_pill_provider.html.erb +1 -3
  20. data/app/views/llm_cost_tracker/shared/_filter_pill_stream.html.erb +1 -3
  21. data/lib/llm_cost_tracker/budget/per_tag.rb +159 -0
  22. data/lib/llm_cost_tracker/budget.rb +120 -32
  23. data/lib/llm_cost_tracker/charges/cost_status.rb +4 -3
  24. data/lib/llm_cost_tracker/configuration/budgets.rb +93 -0
  25. data/lib/llm_cost_tracker/configuration/capture.rb +42 -0
  26. data/lib/llm_cost_tracker/configuration/ingestion.rb +20 -0
  27. data/lib/llm_cost_tracker/configuration/mutability.rb +33 -0
  28. data/lib/llm_cost_tracker/configuration/pricing.rb +36 -0
  29. data/lib/llm_cost_tracker/configuration/section.rb +59 -0
  30. data/lib/llm_cost_tracker/configuration/tags.rb +52 -0
  31. data/lib/llm_cost_tracker/configuration.rb +69 -125
  32. data/lib/llm_cost_tracker/deprecator.rb +9 -0
  33. data/lib/llm_cost_tracker/doctor/ingestion_check.rb +17 -8
  34. data/lib/llm_cost_tracker/doctor/price_check.rb +1 -1
  35. data/lib/llm_cost_tracker/doctor.rb +4 -4
  36. data/lib/llm_cost_tracker/engine.rb +4 -0
  37. data/lib/llm_cost_tracker/errors.rb +12 -3
  38. data/lib/llm_cost_tracker/generators/llm_cost_tracker/async_ingestion_generator.rb +2 -2
  39. data/lib/llm_cost_tracker/generators/llm_cost_tracker/call_rollups_generator.rb +2 -2
  40. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/create_llm_cost_tracker_async_ingestion.rb.erb +0 -1
  41. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/create_llm_cost_tracker_calls.rb.erb +8 -4
  42. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/initializer.rb.erb +50 -30
  43. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_indexes.rb.erb +40 -0
  44. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_per_tag_budgets.rb.erb +41 -0
  45. data/lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_indexes_generator.rb +30 -0
  46. data/lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_per_tag_budgets_generator.rb +30 -0
  47. data/lib/llm_cost_tracker/ingestion/batch.rb +3 -1
  48. data/lib/llm_cost_tracker/ingestion/pool.rb +9 -2
  49. data/lib/llm_cost_tracker/ingestion.rb +3 -7
  50. data/lib/llm_cost_tracker/integrations/openai/batch_capture.rb +10 -12
  51. data/lib/llm_cost_tracker/ledger/period/totals.rb +1 -1
  52. data/lib/llm_cost_tracker/ledger/rollups.rb +34 -4
  53. data/lib/llm_cost_tracker/ledger/store.rb +9 -2
  54. data/lib/llm_cost_tracker/ledger/tags/encoding.rb +15 -5
  55. data/lib/llm_cost_tracker/logging.rb +3 -5
  56. data/lib/llm_cost_tracker/middleware/faraday.rb +1 -1
  57. data/lib/llm_cost_tracker/prices.json +1291 -313
  58. data/lib/llm_cost_tracker/pricing/backfill.rb +11 -1
  59. data/lib/llm_cost_tracker/pricing/calculation.rb +4 -4
  60. data/lib/llm_cost_tracker/pricing/effective_prices.rb +26 -15
  61. data/lib/llm_cost_tracker/pricing/matcher.rb +7 -0
  62. data/lib/llm_cost_tracker/pricing/rate.rb +1 -2
  63. data/lib/llm_cost_tracker/pricing/registry.rb +5 -5
  64. data/lib/llm_cost_tracker/pricing/sync.rb +1 -1
  65. data/lib/llm_cost_tracker/pricing/unknown.rb +11 -8
  66. data/lib/llm_cost_tracker/providers/anthropic/usage_extractor.rb +3 -2
  67. data/lib/llm_cost_tracker/providers/openai/model_families.rb +0 -7
  68. data/lib/llm_cost_tracker/providers/openai/response_parser.rb +5 -2
  69. data/lib/llm_cost_tracker/providers/openai/usage_extractor.rb +5 -4
  70. data/lib/llm_cost_tracker/providers/openai_compatible/parser.rb +2 -2
  71. data/lib/llm_cost_tracker/railtie.rb +3 -7
  72. data/lib/llm_cost_tracker/report/data.rb +2 -2
  73. data/lib/llm_cost_tracker/retention.rb +22 -10
  74. data/lib/llm_cost_tracker/tags/context.rb +3 -3
  75. data/lib/llm_cost_tracker/tags/sanitizer.rb +4 -4
  76. data/lib/llm_cost_tracker/tracker.rb +14 -23
  77. data/lib/llm_cost_tracker/usage/catalog.rb +1 -2
  78. data/lib/llm_cost_tracker/version.rb +1 -1
  79. data/lib/llm_cost_tracker.rb +6 -1
  80. data/lib/tasks/llm_cost_tracker.rake +23 -10
  81. metadata +22 -9
@@ -6,7 +6,15 @@ require "rails/generators"
6
6
  require_relative "../llm_cost_tracker/generators/llm_cost_tracker/install_generator"
7
7
  require_relative "../llm_cost_tracker/pricing/sync/change_printer"
8
8
 
9
- # rubocop:disable Metrics/BlockLength
9
+ module LlmCostTrackerTasks
10
+ def self.price_refresh_output_path
11
+ path = LlmCostTracker::Pricing::Sync.configured_output_path
12
+ FileUtils.mkdir_p(File.dirname(path))
13
+ path
14
+ end
15
+ end
16
+
17
+ # rubocop:disable-next Metrics/BlockLength
10
18
  namespace :llm_cost_tracker do
11
19
  desc "Install LLM Cost Tracker with dashboard and prices, migrate, and run doctor"
12
20
  task :setup do
@@ -75,6 +83,18 @@ namespace :llm_cost_tracker do
75
83
  puts "llm_cost_tracker: rebuilt #{rows} rollup rows from the calls ledger"
76
84
  end
77
85
 
86
+ desc "Copy call cost and time onto existing llm_cost_tracker_call_tags rows so per-tag " \
87
+ "budgets count history recorded before the upgrade. Use BATCH_SIZE=N to tune."
88
+ task backfill_tag_costs: :environment do
89
+ unless LlmCostTracker::Budget::PerTag.columns?
90
+ abort("llm_cost_tracker: llm_cost_tracker_call_tags is missing the cost columns; " \
91
+ "run the upgrade_per_tag_budgets generator and migrate first")
92
+ end
93
+ batch_size = (ENV["BATCH_SIZE"] || LlmCostTracker::Budget::PerTag::DEFAULT_BACKFILL_BATCH).to_i
94
+ filled = LlmCostTracker::Budget::PerTag.backfill(batch_size: batch_size)
95
+ puts "llm_cost_tracker: filled cost and time on #{filled} tag rows"
96
+ end
97
+
78
98
  namespace :prices do
79
99
  desc(
80
100
  "Refresh the configured pricing file from the maintained LLM Cost Tracker price snapshot. " \
@@ -84,7 +104,7 @@ namespace :llm_cost_tracker do
84
104
  Rake::Task["environment"].invoke if Rake::Task.task_defined?("environment")
85
105
  require_relative "../llm_cost_tracker"
86
106
 
87
- output_path = price_refresh_output_path
107
+ output_path = LlmCostTrackerTasks.price_refresh_output_path
88
108
  source_url = LlmCostTracker::Pricing::Sync.configured_remote_url
89
109
  preview = ENV["PREVIEW"] == "1"
90
110
  result = LlmCostTracker::Pricing::Sync.refresh(
@@ -112,7 +132,7 @@ namespace :llm_cost_tracker do
112
132
  Rake::Task["environment"].invoke if Rake::Task.task_defined?("environment")
113
133
  require_relative "../llm_cost_tracker"
114
134
 
115
- output_path = price_refresh_output_path
135
+ output_path = LlmCostTrackerTasks.price_refresh_output_path
116
136
  source_url = LlmCostTracker::Pricing::Sync.configured_remote_url
117
137
  result = LlmCostTracker::Pricing::Sync.check(path: output_path, url: source_url)
118
138
 
@@ -125,10 +145,3 @@ namespace :llm_cost_tracker do
125
145
  end
126
146
  end
127
147
  end
128
- # rubocop:enable Metrics/BlockLength
129
-
130
- def price_refresh_output_path
131
- path = LlmCostTracker::Pricing::Sync.configured_output_path
132
- FileUtils.mkdir_p(File.dirname(path))
133
- path
134
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: llm_cost_tracker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergii Khomenko
@@ -109,42 +109,42 @@ dependencies:
109
109
  requirements:
110
110
  - - "~>"
111
111
  - !ruby/object:Gem::Version
112
- version: '1.42'
112
+ version: '1.61'
113
113
  type: :development
114
114
  prerelease: false
115
115
  version_requirements: !ruby/object:Gem::Requirement
116
116
  requirements:
117
117
  - - "~>"
118
118
  - !ruby/object:Gem::Version
119
- version: '1.42'
119
+ version: '1.61'
120
120
  - !ruby/object:Gem::Dependency
121
121
  name: nokogiri
122
122
  requirement: !ruby/object:Gem::Requirement
123
123
  requirements:
124
124
  - - "~>"
125
125
  - !ruby/object:Gem::Version
126
- version: '1.16'
126
+ version: '1.19'
127
127
  type: :development
128
128
  prerelease: false
129
129
  version_requirements: !ruby/object:Gem::Requirement
130
130
  requirements:
131
131
  - - "~>"
132
132
  - !ruby/object:Gem::Version
133
- version: '1.16'
133
+ version: '1.19'
134
134
  - !ruby/object:Gem::Dependency
135
135
  name: openai
136
136
  requirement: !ruby/object:Gem::Requirement
137
137
  requirements:
138
138
  - - "~>"
139
139
  - !ruby/object:Gem::Version
140
- version: '0.63'
140
+ version: '0.80'
141
141
  type: :development
142
142
  prerelease: false
143
143
  version_requirements: !ruby/object:Gem::Requirement
144
144
  requirements:
145
145
  - - "~>"
146
146
  - !ruby/object:Gem::Version
147
- version: '0.63'
147
+ version: '0.80'
148
148
  - !ruby/object:Gem::Dependency
149
149
  name: pg
150
150
  requirement: !ruby/object:Gem::Requirement
@@ -207,14 +207,14 @@ dependencies:
207
207
  requirements:
208
208
  - - "~>"
209
209
  - !ruby/object:Gem::Version
210
- version: '1.15'
210
+ version: '1.16'
211
211
  type: :development
212
212
  prerelease: false
213
213
  version_requirements: !ruby/object:Gem::Requirement
214
214
  requirements:
215
215
  - - "~>"
216
216
  - !ruby/object:Gem::Version
217
- version: '1.15'
217
+ version: '1.16'
218
218
  - !ruby/object:Gem::Dependency
219
219
  name: simplecov
220
220
  requirement: !ruby/object:Gem::Requirement
@@ -339,6 +339,7 @@ files:
339
339
  - lib/llm_cost_tracker.rb
340
340
  - lib/llm_cost_tracker/assets.rb
341
341
  - lib/llm_cost_tracker/budget.rb
342
+ - lib/llm_cost_tracker/budget/per_tag.rb
342
343
  - lib/llm_cost_tracker/capture/sdk_payload.rb
343
344
  - lib/llm_cost_tracker/capture/sse.rb
344
345
  - lib/llm_cost_tracker/capture/stream_collector.rb
@@ -349,7 +350,15 @@ files:
349
350
  - lib/llm_cost_tracker/charges/line_item.rb
350
351
  - lib/llm_cost_tracker/check.rb
351
352
  - lib/llm_cost_tracker/configuration.rb
353
+ - lib/llm_cost_tracker/configuration/budgets.rb
354
+ - lib/llm_cost_tracker/configuration/capture.rb
355
+ - lib/llm_cost_tracker/configuration/ingestion.rb
356
+ - lib/llm_cost_tracker/configuration/mutability.rb
357
+ - lib/llm_cost_tracker/configuration/pricing.rb
358
+ - lib/llm_cost_tracker/configuration/section.rb
359
+ - lib/llm_cost_tracker/configuration/tags.rb
352
360
  - lib/llm_cost_tracker/currency.rb
361
+ - lib/llm_cost_tracker/deprecator.rb
353
362
  - lib/llm_cost_tracker/doctor.rb
354
363
  - lib/llm_cost_tracker/doctor/ingestion_check.rb
355
364
  - lib/llm_cost_tracker/doctor/price_check.rb
@@ -369,9 +378,13 @@ files:
369
378
  - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_call_rollups_provider.rb.erb
370
379
  - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_call_tags_key_value_index.rb.erb
371
380
  - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_image_tokens.rb.erb
381
+ - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_indexes.rb.erb
382
+ - lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_per_tag_budgets.rb.erb
372
383
  - lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_call_rollups_provider_generator.rb
373
384
  - lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_call_tags_key_value_index_generator.rb
374
385
  - lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_image_tokens_generator.rb
386
+ - lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_indexes_generator.rb
387
+ - lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_per_tag_budgets_generator.rb
375
388
  - lib/llm_cost_tracker/ingestion.rb
376
389
  - lib/llm_cost_tracker/ingestion/batch.rb
377
390
  - lib/llm_cost_tracker/ingestion/inbox.rb