mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
fix(dashboard): 使用有效输入口径展示今日 Token (#294)
将仪表盘“今日 Token”卡片中的输入项改为有效输入口径。 对 OpenAI/Gemini 从 input_tokens 中扣除 cache_read_tokens, Claude 保持原始输入口径不变。 同步更新 dashboard 集成测试,覆盖 OpenAI 与 Claude 的差异化行为。
This commit is contained in:
@@ -2,7 +2,9 @@ use super::{
|
||||
build_auth_error_response, query_param_value, resolve_authenticated_local_user, AppState,
|
||||
GatewayError, GatewayPublicRequestContext,
|
||||
};
|
||||
use aether_billing::normalize_total_input_context_for_cache_hit_rate;
|
||||
use aether_billing::{
|
||||
normalize_input_tokens_for_billing, normalize_total_input_context_for_cache_hit_rate,
|
||||
};
|
||||
use aether_data_contracts::repository::usage::{StoredRequestUsageAudit, UsageAuditListQuery};
|
||||
use axum::{
|
||||
body::Body,
|
||||
@@ -25,6 +27,7 @@ struct DashboardDateRange {
|
||||
struct DashboardUsageTotals {
|
||||
requests: u64,
|
||||
input_tokens: u64,
|
||||
effective_input_tokens: u64,
|
||||
output_tokens: u64,
|
||||
total_tokens: u64,
|
||||
cache_creation_tokens: u64,
|
||||
@@ -74,6 +77,7 @@ impl DashboardUsageTotals {
|
||||
let cache_creation_tokens = dashboard_cache_creation_tokens(item);
|
||||
self.requests += 1;
|
||||
self.input_tokens += item.input_tokens;
|
||||
self.effective_input_tokens += dashboard_effective_input_tokens(item);
|
||||
self.output_tokens += item.output_tokens;
|
||||
self.total_tokens += item.total_tokens;
|
||||
self.cache_creation_tokens += cache_creation_tokens;
|
||||
@@ -150,6 +154,16 @@ fn dashboard_total_input_context(item: &StoredRequestUsageAudit) -> u64 {
|
||||
) as u64
|
||||
}
|
||||
|
||||
fn dashboard_effective_input_tokens(item: &StoredRequestUsageAudit) -> u64 {
|
||||
let api_format = item
|
||||
.endpoint_api_format
|
||||
.as_deref()
|
||||
.or(item.api_format.as_deref());
|
||||
let input_tokens = i64::try_from(item.input_tokens).unwrap_or(i64::MAX);
|
||||
let cache_read_tokens = i64::try_from(item.cache_read_input_tokens).unwrap_or(i64::MAX);
|
||||
normalize_input_tokens_for_billing(api_format, input_tokens, cache_read_tokens) as u64
|
||||
}
|
||||
|
||||
fn dashboard_round_f64(value: f64, decimals: u32) -> f64 {
|
||||
let factor = 10_f64.powi(i32::try_from(decimals).unwrap_or_default());
|
||||
(value * factor).round() / factor
|
||||
@@ -219,7 +233,7 @@ fn dashboard_format_token_subvalue(totals: &DashboardUsageTotals) -> String {
|
||||
fn dashboard_format_today_token_subvalue(totals: &DashboardUsageTotals) -> String {
|
||||
format!(
|
||||
"输入 {} / 输出 {} · 写缓存 {} / 读缓存 {}",
|
||||
dashboard_format_token_compact(totals.input_tokens),
|
||||
dashboard_format_token_compact(totals.effective_input_tokens),
|
||||
dashboard_format_token_compact(totals.output_tokens),
|
||||
dashboard_format_token_compact(totals.cache_creation_tokens),
|
||||
dashboard_format_token_compact(totals.cache_read_tokens)
|
||||
@@ -602,7 +616,7 @@ pub(super) async fn handle_dashboard_stats_get(
|
||||
http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("dashboard api key stats lookup failed: {err:?}"),
|
||||
false,
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -638,7 +652,7 @@ pub(super) async fn handle_dashboard_stats_get(
|
||||
http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("dashboard user stats lookup failed: {err:?}"),
|
||||
false,
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
let success_rate = if today_totals.requests == 0 {
|
||||
@@ -725,7 +739,7 @@ pub(super) async fn handle_dashboard_stats_get(
|
||||
http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("dashboard wallet lookup failed: {err:?}"),
|
||||
false,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1049,7 +1063,7 @@ pub(super) async fn handle_dashboard_recent_requests_get(
|
||||
http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("dashboard recent requests lookup failed: {err:?}"),
|
||||
false,
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1067,7 +1081,7 @@ pub(super) async fn handle_dashboard_recent_requests_get(
|
||||
http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("dashboard user lookup failed: {err:?}"),
|
||||
false,
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
let mut usernames_by_id: BTreeMap<String, String> = users_by_id
|
||||
@@ -1127,7 +1141,7 @@ pub(super) async fn handle_dashboard_provider_status_get(
|
||||
http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("dashboard provider catalog lookup failed: {err:?}"),
|
||||
false,
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
let since_unix_secs = u64::try_from(chrono::Utc::now().timestamp())
|
||||
@@ -1149,7 +1163,7 @@ pub(super) async fn handle_dashboard_provider_status_get(
|
||||
http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("dashboard provider usage lookup failed: {err:?}"),
|
||||
false,
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -158,6 +158,7 @@ async fn gateway_handles_dashboard_stats_locally_without_proxying_upstream() {
|
||||
assert_eq!(payload["today"]["tokens"], 150);
|
||||
assert_eq!(payload["api_keys"]["total"], 2);
|
||||
assert_eq!(payload["api_keys"]["active"], 1);
|
||||
assert_eq!(payload["stats"][3]["subValue"], json!("输入 240 / 输出 60"));
|
||||
assert_eq!(payload["token_breakdown"]["input"], 240);
|
||||
assert_eq!(payload["token_breakdown"]["output"], 60);
|
||||
assert_eq!(payload["token_breakdown"]["cache_creation"], 20);
|
||||
@@ -242,6 +243,8 @@ async fn gateway_handles_admin_dashboard_stats_locally_without_proxying_upstream
|
||||
claude_usage.input_tokens = 900;
|
||||
claude_usage.output_tokens = 100;
|
||||
claude_usage.total_tokens = 1_000;
|
||||
claude_usage.api_format = Some("claude:chat".to_string());
|
||||
claude_usage.endpoint_api_format = Some("claude:chat".to_string());
|
||||
claude_usage.cache_creation_input_tokens = 50;
|
||||
claude_usage.cache_creation_ephemeral_5m_input_tokens = 20;
|
||||
claude_usage.cache_creation_ephemeral_1h_input_tokens = 30;
|
||||
@@ -403,7 +406,7 @@ async fn gateway_handles_admin_dashboard_stats_locally_without_proxying_upstream
|
||||
assert_eq!(payload["stats"][1]["value"], json!("16K"));
|
||||
assert_eq!(
|
||||
payload["stats"][1]["subValue"],
|
||||
json!("输入 12.9K / 输出 3.1K · 写缓存 1.25K / 读缓存 1K")
|
||||
json!("输入 12.1K / 输出 3.1K · 写缓存 1.25K / 读缓存 1K")
|
||||
);
|
||||
assert_eq!(payload["users"]["total"], 2);
|
||||
assert_eq!(payload["users"]["active"], 1);
|
||||
|
||||
Reference in New Issue
Block a user