@@ -309,6 +309,9 @@ func New(driver string, dsn string, schema ...string) (*DB, error) {
309309 prompt_tokens BIGINT NOT NULL DEFAULT 0,
310310 completion_tokens BIGINT NOT NULL DEFAULT 0,
311311 cached_tokens BIGINT NOT NULL DEFAULT 0,
312+ cache_hit_requests BIGINT NOT NULL DEFAULT 0,
313+ first_token_ms_sum DOUBLE PRECISION NOT NULL DEFAULT 0,
314+ first_token_samples BIGINT NOT NULL DEFAULT 0,
312315 account_billed DOUBLE PRECISION NOT NULL DEFAULT 0,
313316 user_billed DOUBLE PRECISION NOT NULL DEFAULT 0
314317 )
@@ -341,6 +344,9 @@ func (db *DB) ensureUsageStatsBaselineBillingColumns(ctx context.Context) error
341344 }{
342345 {name : "account_billed" , def : "REAL NOT NULL DEFAULT 0" },
343346 {name : "user_billed" , def : "REAL NOT NULL DEFAULT 0" },
347+ {name : "cache_hit_requests" , def : "INTEGER NOT NULL DEFAULT 0" },
348+ {name : "first_token_ms_sum" , def : "REAL NOT NULL DEFAULT 0" },
349+ {name : "first_token_samples" , def : "INTEGER NOT NULL DEFAULT 0" },
344350 } {
345351 if _ , ok := columns [column .name ]; ok {
346352 continue
@@ -354,6 +360,9 @@ func (db *DB) ensureUsageStatsBaselineBillingColumns(ctx context.Context) error
354360 _ , err := db .conn .ExecContext (ctx , `
355361 ALTER TABLE usage_stats_baseline ADD COLUMN IF NOT EXISTS account_billed DOUBLE PRECISION NOT NULL DEFAULT 0;
356362 ALTER TABLE usage_stats_baseline ADD COLUMN IF NOT EXISTS user_billed DOUBLE PRECISION NOT NULL DEFAULT 0;
363+ ALTER TABLE usage_stats_baseline ADD COLUMN IF NOT EXISTS cache_hit_requests BIGINT NOT NULL DEFAULT 0;
364+ ALTER TABLE usage_stats_baseline ADD COLUMN IF NOT EXISTS first_token_ms_sum DOUBLE PRECISION NOT NULL DEFAULT 0;
365+ ALTER TABLE usage_stats_baseline ADD COLUMN IF NOT EXISTS first_token_samples BIGINT NOT NULL DEFAULT 0;
357366 ` )
358367 return err
359368}
@@ -1833,16 +1842,20 @@ type UsageStats struct {
18331842 TotalPrompt int64 `json:"total_prompt_tokens"`
18341843 TotalCompletion int64 `json:"total_completion_tokens"`
18351844 TotalCachedTokens int64 `json:"total_cached_tokens"`
1845+ TotalCacheRate float64 `json:"total_cache_rate"`
18361846 TotalAccountBilled float64 `json:"total_account_billed"`
18371847 TotalUserBilled float64 `json:"total_user_billed"`
18381848 AvgAccountBilled float64 `json:"avg_account_billed_per_request"`
18391849 AvgUserBilled float64 `json:"avg_user_billed_per_request"`
18401850 TodayRequests int64 `json:"today_requests"`
18411851 TodayTokens int64 `json:"today_tokens"`
1852+ TodayCachedTokens int64 `json:"today_cached_tokens"`
1853+ TodayCacheRate float64 `json:"today_cache_rate"`
18421854 TodayAccountBilled float64 `json:"today_account_billed"`
18431855 TodayUserBilled float64 `json:"today_user_billed"`
18441856 RPM float64 `json:"rpm"`
18451857 TPM float64 `json:"tpm"`
1858+ AvgFirstTokenMs float64 `json:"avg_first_token_ms"`
18461859 AvgDurationMs float64 `json:"avg_duration_ms"`
18471860 ErrorRate float64 `json:"error_rate"`
18481861 FeatureStats UsageFeatureStat `json:"feature_stats"`
@@ -1918,27 +1931,32 @@ func (db *DB) GetUsageStats(ctx context.Context) (*UsageStats, error) {
19181931 SELECT
19191932 COUNT(*) AS today_requests,
19201933 COALESCE(SUM(total_tokens), 0) AS today_tokens,
1921- COALESCE(SUM(prompt_tokens), 0) AS today_prompt,
1922- COALESCE(SUM(completion_tokens), 0) AS today_completion,
1923- COALESCE(SUM(cached_tokens), 0) AS today_cached,
1924- COALESCE(SUM(account_billed), 0) AS today_account_billed,
1925- COALESCE(SUM(user_billed), 0) AS today_user_billed,
1926- COALESCE(SUM(CASE WHEN created_at >= $2 THEN 1 ELSE 0 END), 0) AS rpm,
1927- COALESCE(SUM(CASE WHEN created_at >= $2 THEN total_tokens ELSE 0 END), 0) AS tpm,
1928- COALESCE(AVG(duration_ms), 0) AS avg_duration_ms,
1934+ COALESCE(SUM(prompt_tokens), 0) AS today_prompt,
1935+ COALESCE(SUM(completion_tokens), 0) AS today_completion,
1936+ COALESCE(SUM(cached_tokens), 0) AS today_cached,
1937+ COALESCE(SUM(account_billed), 0) AS today_account_billed,
1938+ COALESCE(SUM(user_billed), 0) AS today_user_billed,
1939+ COALESCE(SUM(CASE WHEN created_at >= $2 THEN 1 ELSE 0 END), 0) AS rpm,
1940+ COALESCE(SUM(CASE WHEN created_at >= $2 THEN total_tokens ELSE 0 END), 0) AS tpm,
1941+ COALESCE(AVG(NULLIF(first_token_ms, 0)), 0) AS avg_first_token_ms,
1942+ COALESCE(AVG(duration_ms), 0) AS avg_duration_ms,
1943+ COALESCE(SUM(CASE WHEN cached_tokens > 0 THEN 1 ELSE 0 END), 0) AS today_cache_hit_requests,
19291944 COALESCE(SUM(CASE WHEN status_code >= 400 THEN 1 ELSE 0 END), 0) AS today_errors
19301945 FROM usage_logs
19311946 WHERE created_at >= $1
19321947 AND status_code <> 499
19331948 `
19341949
19351950 var todayErrors int64
1951+ var todayCacheHitRequests int64
19361952 var todayPrompt , todayCompletion , todayCached int64
19371953 err := db .conn .QueryRowContext (ctx , todayQuery , todayStart , minuteAgo ).Scan (
19381954 & stats .TodayRequests , & stats .TodayTokens , & todayPrompt , & todayCompletion , & todayCached ,
19391955 & stats .TodayAccountBilled , & stats .TodayUserBilled ,
19401956 & stats .RPM , & stats .TPM ,
1957+ & stats .AvgFirstTokenMs ,
19411958 & stats .AvgDurationMs ,
1959+ & todayCacheHitRequests ,
19421960 & todayErrors ,
19431961 )
19441962 if err != nil {
@@ -1947,7 +1965,10 @@ func (db *DB) GetUsageStats(ctx context.Context) (*UsageStats, error) {
19471965
19481966 // 统计当前可见请求总数和计费总额(排除 499,保证与使用统计列表口径一致)
19491967 var visibleTotal int64
1968+ var visibleCacheHitRequests int64
1969+ var visibleFirstTokenSamples int64
19501970 var currentTokens , currentPrompt , currentCompletion , currentCached int64
1971+ var currentFirstTokenMsSum float64
19511972 var currentAccountBilled , currentUserBilled float64
19521973 _ = db .conn .QueryRowContext (ctx , `
19531974 SELECT
@@ -1956,27 +1977,41 @@ func (db *DB) GetUsageStats(ctx context.Context) (*UsageStats, error) {
19561977 COALESCE(SUM(prompt_tokens), 0),
19571978 COALESCE(SUM(completion_tokens), 0),
19581979 COALESCE(SUM(cached_tokens), 0),
1980+ COALESCE(SUM(CASE WHEN cached_tokens > 0 THEN 1 ELSE 0 END), 0),
1981+ COALESCE(SUM(CASE WHEN first_token_ms > 0 THEN first_token_ms ELSE 0 END), 0),
1982+ COALESCE(SUM(CASE WHEN first_token_ms > 0 THEN 1 ELSE 0 END), 0),
19591983 COALESCE(SUM(account_billed), 0),
19601984 COALESCE(SUM(user_billed), 0)
19611985 FROM usage_logs
19621986 WHERE status_code <> 499
1963- ` ).Scan (& visibleTotal , & currentTokens , & currentPrompt , & currentCompletion , & currentCached , & currentAccountBilled , & currentUserBilled )
1987+ ` ).Scan (& visibleTotal , & currentTokens , & currentPrompt , & currentCompletion , & currentCached , & visibleCacheHitRequests , & currentFirstTokenMsSum , & visibleFirstTokenSamples , & currentAccountBilled , & currentUserBilled )
19641988
19651989 // 加上基线值(清空日志前保存的累计值)
1966- var bReq , bTok , bPrompt , bComp , bCached int64
1990+ var bReq , bTok , bPrompt , bComp , bCached , bCacheHitRequests , bFirstTokenSamples int64
1991+ var bFirstTokenMsSum float64
19671992 var bAccountBilled , bUserBilled float64
19681993 _ = db .conn .QueryRowContext (ctx , `
1969- SELECT total_requests, total_tokens, prompt_tokens, completion_tokens, cached_tokens, account_billed, user_billed
1994+ SELECT total_requests, total_tokens, prompt_tokens, completion_tokens, cached_tokens, cache_hit_requests, first_token_ms_sum, first_token_samples, account_billed, user_billed
19701995 FROM usage_stats_baseline WHERE id = 1
1971- ` ).Scan (& bReq , & bTok , & bPrompt , & bComp , & bCached , & bAccountBilled , & bUserBilled )
1996+ ` ).Scan (& bReq , & bTok , & bPrompt , & bComp , & bCached , & bCacheHitRequests , & bFirstTokenMsSum , & bFirstTokenSamples , & bAccountBilled , & bUserBilled )
19721997
19731998 stats .TotalRequests = visibleTotal + bReq
19741999 stats .TotalTokens = currentTokens + bTok
19752000 stats .TotalPrompt = currentPrompt + bPrompt
19762001 stats .TotalCompletion = currentCompletion + bComp
19772002 stats .TotalCachedTokens = currentCached + bCached
2003+ stats .TodayCachedTokens = todayCached
19782004 stats .TotalAccountBilled = currentAccountBilled + bAccountBilled
19792005 stats .TotalUserBilled = currentUserBilled + bUserBilled
2006+ if stats .TodayRequests > 0 {
2007+ stats .TodayCacheRate = float64 (todayCacheHitRequests ) / float64 (stats .TodayRequests ) * 100
2008+ }
2009+ if stats .TotalRequests > 0 {
2010+ stats .TotalCacheRate = float64 (visibleCacheHitRequests + bCacheHitRequests ) / float64 (stats .TotalRequests ) * 100
2011+ }
2012+ if totalFirstTokenSamples := visibleFirstTokenSamples + bFirstTokenSamples ; totalFirstTokenSamples > 0 {
2013+ stats .AvgFirstTokenMs = (currentFirstTokenMsSum + bFirstTokenMsSum ) / float64 (totalFirstTokenSamples )
2014+ }
19802015 if stats .TotalRequests > 0 {
19812016 stats .AvgAccountBilled = stats .TotalAccountBilled / float64 (stats .TotalRequests )
19822017 stats .AvgUserBilled = stats .TotalUserBilled / float64 (stats .TotalRequests )
@@ -2773,12 +2808,15 @@ func (db *DB) ClearUsageLogs(ctx context.Context) error {
27732808 _ , err := db .conn .ExecContext (ctx , `
27742809 UPDATE usage_stats_baseline SET
27752810 total_requests = total_requests + COALESCE((SELECT COUNT(*) FROM usage_logs WHERE status_code <> 499), 0),
2776- total_tokens = total_tokens + COALESCE((SELECT SUM(total_tokens) FROM usage_logs WHERE status_code <> 499), 0),
2777- prompt_tokens = prompt_tokens + COALESCE((SELECT SUM(prompt_tokens) FROM usage_logs WHERE status_code <> 499), 0),
2778- completion_tokens = completion_tokens + COALESCE((SELECT SUM(completion_tokens) FROM usage_logs WHERE status_code <> 499), 0),
2779- cached_tokens = cached_tokens + COALESCE((SELECT SUM(cached_tokens) FROM usage_logs WHERE status_code <> 499), 0),
2780- account_billed = account_billed + COALESCE((SELECT SUM(account_billed) FROM usage_logs WHERE status_code <> 499), 0),
2781- user_billed = user_billed + COALESCE((SELECT SUM(user_billed) FROM usage_logs WHERE status_code <> 499), 0)
2811+ total_tokens = total_tokens + COALESCE((SELECT SUM(total_tokens) FROM usage_logs WHERE status_code <> 499), 0),
2812+ prompt_tokens = prompt_tokens + COALESCE((SELECT SUM(prompt_tokens) FROM usage_logs WHERE status_code <> 499), 0),
2813+ completion_tokens = completion_tokens + COALESCE((SELECT SUM(completion_tokens) FROM usage_logs WHERE status_code <> 499), 0),
2814+ cached_tokens = cached_tokens + COALESCE((SELECT SUM(cached_tokens) FROM usage_logs WHERE status_code <> 499), 0),
2815+ cache_hit_requests = cache_hit_requests + COALESCE((SELECT SUM(CASE WHEN cached_tokens > 0 THEN 1 ELSE 0 END) FROM usage_logs WHERE status_code <> 499), 0),
2816+ first_token_ms_sum = first_token_ms_sum + COALESCE((SELECT SUM(CASE WHEN first_token_ms > 0 THEN first_token_ms ELSE 0 END) FROM usage_logs WHERE status_code <> 499), 0),
2817+ first_token_samples = first_token_samples + COALESCE((SELECT SUM(CASE WHEN first_token_ms > 0 THEN 1 ELSE 0 END) FROM usage_logs WHERE status_code <> 499), 0),
2818+ account_billed = account_billed + COALESCE((SELECT SUM(account_billed) FROM usage_logs WHERE status_code <> 499), 0),
2819+ user_billed = user_billed + COALESCE((SELECT SUM(user_billed) FROM usage_logs WHERE status_code <> 499), 0)
27822820 WHERE id = 1
27832821 ` )
27842822 if err != nil {
0 commit comments