fix(usage): 修正 input_tokens 统计与显示

- SQL 查询不再用 settlement snapshot 的 billing_input_tokens 覆盖原始 input_tokens
- usage_mapper 针对 OpenAI 格式在 input_tokens 缺失时从 total_tokens - output_tokens 推导
- 前端轮询合并优先采用最新 record 的 input_tokens / effective_input_tokens
This commit is contained in:
fawney19
2026-04-24 20:59:12 +08:00
parent 343345529d
commit e265475c17
7 changed files with 81 additions and 8 deletions

View File

@@ -20,7 +20,7 @@ SELECT
"usage".provider_endpoint_kind,
COALESCE("usage".has_format_conversion, FALSE) AS has_format_conversion,
COALESCE("usage".is_stream, FALSE) AS is_stream,
CAST(COALESCE(usage_settlement_snapshots.billing_input_tokens, "usage".input_tokens) AS INTEGER) AS input_tokens,
CAST("usage".input_tokens AS INTEGER) AS input_tokens,
CAST(COALESCE(usage_settlement_snapshots.billing_output_tokens, "usage".output_tokens) AS INTEGER) AS output_tokens,
CAST(COALESCE(
CASE

View File

@@ -20,7 +20,7 @@ SELECT
"usage".provider_endpoint_kind,
COALESCE("usage".has_format_conversion, FALSE) AS has_format_conversion,
COALESCE("usage".is_stream, FALSE) AS is_stream,
CAST(COALESCE(usage_settlement_snapshots.billing_input_tokens, "usage".input_tokens) AS INTEGER) AS input_tokens,
CAST("usage".input_tokens AS INTEGER) AS input_tokens,
CAST(COALESCE(usage_settlement_snapshots.billing_output_tokens, "usage".output_tokens) AS INTEGER) AS output_tokens,
CAST(COALESCE(
CASE

View File

@@ -20,7 +20,7 @@ SELECT
"usage".provider_endpoint_kind,
COALESCE("usage".has_format_conversion, FALSE) AS has_format_conversion,
COALESCE("usage".is_stream, FALSE) AS is_stream,
CAST(COALESCE(usage_settlement_snapshots.billing_input_tokens, "usage".input_tokens) AS INTEGER) AS input_tokens,
CAST("usage".input_tokens AS INTEGER) AS input_tokens,
CAST(COALESCE(usage_settlement_snapshots.billing_output_tokens, "usage".output_tokens) AS INTEGER) AS output_tokens,
CAST(COALESCE(
CASE

View File

@@ -20,7 +20,7 @@ SELECT
"usage".provider_endpoint_kind,
COALESCE("usage".has_format_conversion, FALSE) AS has_format_conversion,
COALESCE("usage".is_stream, FALSE) AS is_stream,
CAST(COALESCE(usage_settlement_snapshots.billing_input_tokens, "usage".input_tokens) AS INTEGER) AS input_tokens,
CAST("usage".input_tokens AS INTEGER) AS input_tokens,
CAST(COALESCE(usage_settlement_snapshots.billing_output_tokens, "usage".output_tokens) AS INTEGER) AS output_tokens,
CAST(COALESCE(
CASE

View File

@@ -452,8 +452,9 @@ fn usage_sql_reads_settlement_snapshots_for_single_record_fetches() {
assert!(super::FIND_BY_REQUEST_ID_SQL.contains("settlement_billing_snapshot_schema_version"));
assert!(super::FIND_BY_ID_SQL.contains("settlement_price_per_request"));
for sql in [super::FIND_BY_REQUEST_ID_SQL, super::FIND_BY_ID_SQL] {
assert!(sql.contains("CAST(\"usage\".input_tokens AS INTEGER) AS input_tokens"));
assert!(sql.contains(
"COALESCE(usage_settlement_snapshots.billing_input_tokens, \"usage\".input_tokens)"
"usage_settlement_snapshots.billing_input_tokens AS settlement_billing_input_tokens"
));
assert!(sql.contains("usage_settlement_snapshots.billing_cache_creation_5m_tokens"));
assert!(sql.contains(
@@ -523,8 +524,9 @@ fn usage_sql_uses_json_null_placeholders_for_usage_payload_columns() {
super::LIST_USAGE_AUDITS_PREFIX,
super::LIST_RECENT_USAGE_AUDITS_PREFIX,
] {
assert!(sql.contains("CAST(\"usage\".input_tokens AS INTEGER) AS input_tokens"));
assert!(sql.contains(
"COALESCE(usage_settlement_snapshots.billing_input_tokens, \"usage\".input_tokens)"
"usage_settlement_snapshots.billing_input_tokens AS settlement_billing_input_tokens"
));
assert!(sql.contains("usage_settlement_snapshots.billing_cache_creation_1h_tokens"));
assert!(sql.contains(