Module: LlmCostTracker::Reconciliation
- Defined in:
- lib/llm_cost_tracker/reconciliation.rb,
lib/llm_cost_tracker/reconciliation/diff.rb,
lib/llm_cost_tracker/reconciliation/importer.rb,
lib/llm_cost_tracker/reconciliation/diff_result.rb,
lib/llm_cost_tracker/reconciliation/import_result.rb,
lib/llm_cost_tracker/reconciliation/sources/coercion.rb,
lib/llm_cost_tracker/reconciliation/sources/fingerprint.rb,
lib/llm_cost_tracker/reconciliation/sources/openai_usage.rb,
lib/llm_cost_tracker/reconciliation/sources/anthropic_usage.rb
Defined Under Namespace
Modules: Sources
Classes: Diff, DiffResult, ImportResult, Importer
Constant Summary
collapse
- SUPPORTED_SOURCES =
%i[openai anthropic gemini csv].freeze
- DEFAULT_THRESHOLD_PERCENT =
5.0
- INVOICE_FRESHNESS_DAYS =
14
- SOURCE_TO_PROVIDER =
{
"openai" => "openai",
"openai_usage" => "openai",
"anthropic" => "anthropic",
"anthropic_usage" => "anthropic",
"gemini" => "gemini"
}.freeze
- SCHEMA_TABLES =
{
Ledger::Schema::ProviderInvoices => "llm_cost_tracker_provider_invoices",
Ledger::Schema::ProviderInvoiceImports => "llm_cost_tracker_provider_invoice_imports"
}.freeze
Class Method Summary
collapse
-
.diff(source:, period_start:, period_end:, provider: nil, scope: {}, currency: nil, drilldown_limit: Diff::DEFAULT_DRILLDOWN_LIMIT) ⇒ Object
-
.enabled? ⇒ Boolean
-
.ensure_enabled! ⇒ Object
-
.ensure_source_present!(source) ⇒ Object
-
.import(source:, rows:, provider: nil, imported_at: nil, window: nil, strict_metadata: nil, cursor: nil) ⇒ Object
-
.metadata_provider_value(metadata) ⇒ Object
-
.recorded_provider_for(source) ⇒ Object
-
.resolve_provider(source:, provider:) ⇒ Object
Class Method Details
.diff(source:, period_start:, period_end:, provider: nil, scope: {}, currency: nil, drilldown_limit: Diff::DEFAULT_DRILLDOWN_LIMIT) ⇒ Object
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
# File 'lib/llm_cost_tracker/reconciliation.rb', line 48
def diff(source:, period_start:, period_end:, provider: nil, scope: {}, currency: nil,
drilldown_limit: Diff::DEFAULT_DRILLDOWN_LIMIT)
ensure_enabled!
ensure_source_present!(source)
Diff.new(
source: source,
provider: resolve_provider(source: source, provider: provider),
period_start: period_start,
period_end: period_end,
scope: scope,
currency: currency,
drilldown_limit: drilldown_limit
).call
end
|
.enabled? ⇒ Boolean
105
106
107
|
# File 'lib/llm_cost_tracker/reconciliation.rb', line 105
def enabled?
LlmCostTracker.configuration.reconciliation_enabled
end
|
.ensure_enabled! ⇒ Object
109
110
111
112
113
114
115
|
# File 'lib/llm_cost_tracker/reconciliation.rb', line 109
def ensure_enabled!
return if enabled?
raise Error,
"reconciliation is disabled; set `config.reconciliation_enabled = true` in your initializer " \
"(requires admin/org-level provider API keys; see docs/upgrading.md)"
end
|
.ensure_source_present!(source) ⇒ Object
63
64
65
66
67
|
# File 'lib/llm_cost_tracker/reconciliation.rb', line 63
def ensure_source_present!(source)
return unless source.to_s.empty?
raise ArgumentError, "source must be present"
end
|
.import(source:, rows:, provider: nil, imported_at: nil, window: nil, strict_metadata: nil, cursor: nil) ⇒ Object
34
35
36
37
38
39
40
41
42
43
44
45
46
|
# File 'lib/llm_cost_tracker/reconciliation.rb', line 34
def import(source:, rows:, provider: nil, imported_at: nil, window: nil,
strict_metadata: nil, cursor: nil)
ensure_enabled!
ensure_source_present!(source)
Importer.new(
source: source,
provider: resolve_provider(source: source, provider: provider),
imported_at: imported_at,
window: window,
strict_metadata: strict_metadata,
cursor: cursor
).call(rows)
end
|
96
97
98
99
100
101
102
103
|
# File 'lib/llm_cost_tracker/reconciliation.rb', line 96
def metadata_provider_value(metadata)
case metadata
when Hash then metadata["provider"]
when String
parsed = JSON.parse(metadata) rescue nil parsed.is_a?(Hash) ? parsed["provider"] : nil
end
end
|
.recorded_provider_for(source) ⇒ Object
84
85
86
87
88
89
90
91
92
93
94
|
# File 'lib/llm_cost_tracker/reconciliation.rb', line 84
def recorded_provider_for(source)
return nil unless LlmCostTracker::ProviderInvoice.table_exists?
metadata = LlmCostTracker::ProviderInvoice
.where(source: source.to_s)
.order(imported_at: :desc)
.limit(1)
.pick(:metadata)
value = metadata_provider_value(metadata)
value if value.is_a?(String) && !value.empty?
end
|
.resolve_provider(source:, provider:) ⇒ Object
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
# File 'lib/llm_cost_tracker/reconciliation.rb', line 69
def resolve_provider(source:, provider:)
return provider.to_s if provider
mapped = SOURCE_TO_PROVIDER[source.to_s]
return mapped if mapped
recorded = recorded_provider_for(source)
return recorded if recorded
known = SOURCE_TO_PROVIDER.keys.join(", ")
raise ArgumentError,
"provider: must be specified for reconciliation source #{source.inspect}; " \
"sources with a default provider mapping: #{known}"
end
|