mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-07 01:47:47 +08:00
feat(stats): add user group usage views
This commit is contained in:
@@ -2388,6 +2388,7 @@ INSERT INTO public.stats_daily_api_key (
|
||||
.expect("historical stats end should be nonnegative"),
|
||||
group_by: UsageLeaderboardGroupBy::ApiKey,
|
||||
user_id: Some("leaderboard-owner".to_string()),
|
||||
user_ids: None,
|
||||
provider_name: None,
|
||||
model: None,
|
||||
};
|
||||
|
||||
@@ -493,6 +493,15 @@ fn usage_matches_summary_query(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(user_ids) = query.user_ids.as_deref() {
|
||||
if !item
|
||||
.user_id
|
||||
.as_ref()
|
||||
.is_some_and(|user_id| user_ids.contains(user_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(provider_name) = query.provider_name.as_deref() {
|
||||
if item.provider_name != provider_name {
|
||||
return false;
|
||||
@@ -520,6 +529,15 @@ fn usage_matches_time_series_query(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(user_ids) = query.user_ids.as_deref() {
|
||||
if !item
|
||||
.user_id
|
||||
.as_ref()
|
||||
.is_some_and(|user_id| user_ids.contains(user_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(provider_name) = query.provider_name.as_deref() {
|
||||
if item.provider_name != provider_name {
|
||||
return false;
|
||||
@@ -891,6 +909,15 @@ fn usage_matches_leaderboard_query(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(user_ids) = query.user_ids.as_deref() {
|
||||
if !item
|
||||
.user_id
|
||||
.as_ref()
|
||||
.is_some_and(|user_id| user_ids.contains(user_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(provider_name) = query.provider_name.as_deref() {
|
||||
if item.provider_name != provider_name {
|
||||
return false;
|
||||
|
||||
@@ -18,7 +18,7 @@ use aether_data_contracts::repository::usage::{
|
||||
UsageAuditAggregationQuery, UsageAuditKeywordSearchQuery, UsageAuditListQuery,
|
||||
UsageAuditSummaryQuery, UsageBodyCaptureState, UsageBodyField, UsageDashboardSummaryQuery,
|
||||
UsageLeaderboardGroupBy, UsageLeaderboardQuery, UsageProviderPerformanceQuery,
|
||||
UsageTimeSeriesGranularity,
|
||||
UsageTimeSeriesGranularity, UsageTimeSeriesQuery,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
@@ -2217,6 +2217,7 @@ async fn dashboard_and_leaderboard_total_tokens_use_effective_cache_aware_tokens
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
group_by: UsageLeaderboardGroupBy::User,
|
||||
user_id: None,
|
||||
user_ids: None,
|
||||
provider_name: None,
|
||||
model: None,
|
||||
})
|
||||
@@ -2226,6 +2227,64 @@ async fn dashboard_and_leaderboard_total_tokens_use_effective_cache_aware_tokens
|
||||
assert_eq!(leaderboard[0].total_tokens, 120);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn usage_analytics_filters_by_multiple_user_ids() {
|
||||
let user_one = sample_usage("req-user-1", 1_711_000_000);
|
||||
let mut user_two = sample_usage("req-user-2", 1_711_000_000);
|
||||
user_two.user_id = Some("user-2".to_string());
|
||||
let mut user_three = sample_usage("req-user-3", 1_711_000_000);
|
||||
user_three.user_id = Some("user-3".to_string());
|
||||
let repository = InMemoryUsageReadRepository::seed(vec![user_one, user_two, user_three]);
|
||||
let scoped_user_ids = vec!["user-1".to_string(), "user-2".to_string()];
|
||||
|
||||
let summary = repository
|
||||
.summarize_usage_audits(&UsageAuditSummaryQuery {
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
user_ids: Some(scoped_user_ids.clone()),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.expect("summary should filter by multiple users");
|
||||
assert_eq!(summary.total_requests, 2);
|
||||
|
||||
let buckets = repository
|
||||
.summarize_usage_time_series(&UsageTimeSeriesQuery {
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
granularity: UsageTimeSeriesGranularity::Day,
|
||||
tz_offset_minutes: 0,
|
||||
user_id: None,
|
||||
user_ids: Some(scoped_user_ids.clone()),
|
||||
provider_name: None,
|
||||
model: None,
|
||||
})
|
||||
.await
|
||||
.expect("time series should filter by multiple users");
|
||||
assert_eq!(
|
||||
buckets
|
||||
.iter()
|
||||
.map(|bucket| bucket.total_requests)
|
||||
.sum::<u64>(),
|
||||
2
|
||||
);
|
||||
|
||||
let leaderboard = repository
|
||||
.summarize_usage_leaderboard(&UsageLeaderboardQuery {
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
group_by: UsageLeaderboardGroupBy::User,
|
||||
user_id: None,
|
||||
user_ids: Some(scoped_user_ids),
|
||||
provider_name: None,
|
||||
model: None,
|
||||
})
|
||||
.await
|
||||
.expect("leaderboard should filter by multiple users");
|
||||
assert_eq!(leaderboard.len(), 2);
|
||||
assert!(leaderboard.iter().all(|item| item.group_key != "user-3"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn summarizes_provider_api_key_last_used_at_in_seconds() {
|
||||
let repository = InMemoryUsageReadRepository::seed(vec![
|
||||
|
||||
Reference in New Issue
Block a user