feat: 添加缓存 Token 独立展示(cache_creation / cache_read)
从 logs 表 other JSON 字段提取 cache_creation_tokens 和 cache_tokens, 在排名、日志、聚合、详情页分别展示,total_tokens 包含缓存部分。
This commit is contained in:
@@ -6,6 +6,16 @@ const REAL_MODEL = `COALESCE(
|
||||
THEN other::jsonb->>'upstream_model_name' END,
|
||||
model_name)`;
|
||||
|
||||
const CACHE_CREATION = `COALESCE(
|
||||
CASE WHEN other IS NOT NULL AND other != '' AND other::jsonb ? 'cache_creation_tokens'
|
||||
THEN (other::jsonb->>'cache_creation_tokens')::bigint END,
|
||||
0)`;
|
||||
|
||||
const CACHE_READ = `COALESCE(
|
||||
CASE WHEN other IS NOT NULL AND other != '' AND other::jsonb ? 'cache_tokens'
|
||||
THEN (other::jsonb->>'cache_tokens')::bigint END,
|
||||
0)`;
|
||||
|
||||
// ── 数据时间边界 ────────────────────────────────────────────────
|
||||
|
||||
export async function getDateRange(): Promise<{ minDate: string; maxDate: string }> {
|
||||
@@ -43,6 +53,8 @@ export interface OverviewData {
|
||||
total_tokens: number;
|
||||
total_prompt: number;
|
||||
total_completion: number;
|
||||
total_cache_creation: number;
|
||||
total_cache_read: number;
|
||||
total_quota: number;
|
||||
active_users: number;
|
||||
active_models: number;
|
||||
@@ -62,6 +74,8 @@ export async function getOverview(
|
||||
COALESCE(SUM(prompt_tokens + completion_tokens), 0)::bigint as total_tokens,
|
||||
COALESCE(SUM(prompt_tokens), 0)::bigint as total_prompt,
|
||||
COALESCE(SUM(completion_tokens), 0)::bigint as total_completion,
|
||||
COALESCE(SUM(${CACHE_CREATION}), 0)::bigint as total_cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}), 0)::bigint as total_cache_read,
|
||||
COALESCE(SUM(quota), 0)::bigint as total_quota,
|
||||
COUNT(DISTINCT user_id)::int as active_users,
|
||||
COUNT(DISTINCT ${REAL_MODEL})::int as active_models,
|
||||
@@ -72,9 +86,11 @@ export async function getOverview(
|
||||
const r = rows[0];
|
||||
return {
|
||||
total_calls: Number(r.total_calls),
|
||||
total_tokens: Number(r.total_tokens),
|
||||
total_tokens: Number(r.total_tokens) + Number(r.total_cache_creation) + Number(r.total_cache_read),
|
||||
total_prompt: Number(r.total_prompt),
|
||||
total_completion: Number(r.total_completion),
|
||||
total_cache_creation: Number(r.total_cache_creation),
|
||||
total_cache_read: Number(r.total_cache_read),
|
||||
total_quota: Number(r.total_quota),
|
||||
active_users: Number(r.active_users),
|
||||
active_models: Number(r.active_models),
|
||||
@@ -89,6 +105,8 @@ export interface TrendPoint {
|
||||
calls: number;
|
||||
prompt_tokens: number;
|
||||
completion_tokens: number;
|
||||
cache_creation_tokens: number;
|
||||
cache_read_tokens: number;
|
||||
total_tokens: number;
|
||||
quota: number;
|
||||
}
|
||||
@@ -112,6 +130,8 @@ export async function getTrends(
|
||||
COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens), 0)::bigint as prompt_tokens,
|
||||
COALESCE(SUM(completion_tokens), 0)::bigint as completion_tokens,
|
||||
COALESCE(SUM(${CACHE_CREATION}), 0)::bigint as cache_creation_tokens,
|
||||
COALESCE(SUM(${CACHE_READ}), 0)::bigint as cache_read_tokens,
|
||||
COALESCE(SUM(quota), 0)::bigint as quota
|
||||
FROM logs WHERE ${where}
|
||||
GROUP BY date ORDER BY date`,
|
||||
@@ -123,7 +143,9 @@ export async function getTrends(
|
||||
calls: Number(r.calls),
|
||||
prompt_tokens: Number(r.prompt_tokens),
|
||||
completion_tokens: Number(r.completion_tokens),
|
||||
total_tokens: Number(r.prompt_tokens) + Number(r.completion_tokens),
|
||||
cache_creation_tokens: Number(r.cache_creation_tokens),
|
||||
cache_read_tokens: Number(r.cache_read_tokens),
|
||||
total_tokens: Number(r.prompt_tokens) + Number(r.completion_tokens) + Number(r.cache_creation_tokens) + Number(r.cache_read_tokens),
|
||||
quota: Number(r.quota),
|
||||
}));
|
||||
}
|
||||
@@ -137,6 +159,8 @@ export interface RankingItem {
|
||||
calls: number;
|
||||
prompt_tokens: number;
|
||||
completion_tokens: number;
|
||||
cache_creation_tokens: number;
|
||||
cache_read_tokens: number;
|
||||
total_tokens: number;
|
||||
quota: number;
|
||||
quota_usd: number;
|
||||
@@ -172,10 +196,12 @@ export async function getUserRanking(
|
||||
COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens), 0)::bigint as prompt,
|
||||
COALESCE(SUM(completion_tokens), 0)::bigint as completion,
|
||||
COALESCE(SUM(${CACHE_CREATION}), 0)::bigint as cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}), 0)::bigint as cache_read,
|
||||
COALESCE(SUM(quota), 0)::bigint as quota
|
||||
FROM logs WHERE ${where}
|
||||
GROUP BY user_id, username
|
||||
ORDER BY COALESCE(SUM(prompt_tokens),0) + COALESCE(SUM(completion_tokens),0) DESC
|
||||
ORDER BY COALESCE(SUM(prompt_tokens),0) + COALESCE(SUM(completion_tokens),0) + COALESCE(SUM(${CACHE_CREATION}),0) + COALESCE(SUM(${CACHE_READ}),0) DESC
|
||||
LIMIT $${params.length}`,
|
||||
params
|
||||
);
|
||||
@@ -188,7 +214,9 @@ export async function getUserRanking(
|
||||
calls: Number(r.calls),
|
||||
prompt_tokens: Number(r.prompt),
|
||||
completion_tokens: Number(r.completion),
|
||||
total_tokens: Number(r.prompt) + Number(r.completion),
|
||||
cache_creation_tokens: Number(r.cache_creation),
|
||||
cache_read_tokens: Number(r.cache_read),
|
||||
total_tokens: Number(r.prompt) + Number(r.completion) + Number(r.cache_creation) + Number(r.cache_read),
|
||||
quota: Number(r.quota),
|
||||
quota_usd: Number(r.quota) / 500000,
|
||||
}));
|
||||
@@ -208,10 +236,12 @@ export async function getModelRanking(
|
||||
COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens), 0)::bigint as prompt,
|
||||
COALESCE(SUM(completion_tokens), 0)::bigint as completion,
|
||||
COALESCE(SUM(${CACHE_CREATION}), 0)::bigint as cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}), 0)::bigint as cache_read,
|
||||
COALESCE(SUM(quota), 0)::bigint as quota
|
||||
FROM logs WHERE ${where}
|
||||
GROUP BY model
|
||||
ORDER BY COALESCE(SUM(prompt_tokens),0) + COALESCE(SUM(completion_tokens),0) DESC
|
||||
ORDER BY COALESCE(SUM(prompt_tokens),0) + COALESCE(SUM(completion_tokens),0) + COALESCE(SUM(${CACHE_CREATION}),0) + COALESCE(SUM(${CACHE_READ}),0) DESC
|
||||
LIMIT $${params.length}`,
|
||||
params
|
||||
);
|
||||
@@ -222,7 +252,9 @@ export async function getModelRanking(
|
||||
calls: Number(r.calls),
|
||||
prompt_tokens: Number(r.prompt),
|
||||
completion_tokens: Number(r.completion),
|
||||
total_tokens: Number(r.prompt) + Number(r.completion),
|
||||
cache_creation_tokens: Number(r.cache_creation),
|
||||
cache_read_tokens: Number(r.cache_read),
|
||||
total_tokens: Number(r.prompt) + Number(r.completion) + Number(r.cache_creation) + Number(r.cache_read),
|
||||
quota: Number(r.quota),
|
||||
quota_usd: Number(r.quota) / 500000,
|
||||
}));
|
||||
@@ -244,10 +276,12 @@ export async function getChannelRanking(
|
||||
COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens), 0)::bigint as prompt,
|
||||
COALESCE(SUM(completion_tokens), 0)::bigint as completion,
|
||||
COALESCE(SUM(${CACHE_CREATION}), 0)::bigint as cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}), 0)::bigint as cache_read,
|
||||
COALESCE(SUM(quota), 0)::bigint as quota
|
||||
FROM logs WHERE ${where}
|
||||
GROUP BY channel_id
|
||||
ORDER BY COALESCE(SUM(prompt_tokens),0) + COALESCE(SUM(completion_tokens),0) DESC
|
||||
ORDER BY COALESCE(SUM(prompt_tokens),0) + COALESCE(SUM(completion_tokens),0) + COALESCE(SUM(${CACHE_CREATION}),0) + COALESCE(SUM(${CACHE_READ}),0) DESC
|
||||
LIMIT $${params.length}`,
|
||||
params
|
||||
);
|
||||
@@ -259,7 +293,9 @@ export async function getChannelRanking(
|
||||
calls: Number(r.calls),
|
||||
prompt_tokens: Number(r.prompt),
|
||||
completion_tokens: Number(r.completion),
|
||||
total_tokens: Number(r.prompt) + Number(r.completion),
|
||||
cache_creation_tokens: Number(r.cache_creation),
|
||||
cache_read_tokens: Number(r.cache_read),
|
||||
total_tokens: Number(r.prompt) + Number(r.completion) + Number(r.cache_creation) + Number(r.cache_read),
|
||||
quota: Number(r.quota),
|
||||
quota_usd: Number(r.quota) / 500000,
|
||||
}));
|
||||
@@ -288,6 +324,8 @@ export async function getUserDetail(
|
||||
`SELECT COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens),0)::bigint as prompt,
|
||||
COALESCE(SUM(completion_tokens),0)::bigint as completion,
|
||||
COALESCE(SUM(${CACHE_CREATION}),0)::bigint as cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}),0)::bigint as cache_read,
|
||||
COALESCE(SUM(quota),0)::bigint as quota
|
||||
FROM logs WHERE ${where} AND username = $${params.length}`,
|
||||
params
|
||||
@@ -302,6 +340,8 @@ export async function getUserDetail(
|
||||
`SELECT ${REAL_MODEL} as model,
|
||||
COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens + completion_tokens),0)::bigint as tokens,
|
||||
COALESCE(SUM(${CACHE_CREATION}),0)::bigint as cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}),0)::bigint as cache_read,
|
||||
COALESCE(SUM(quota),0)::bigint as quota
|
||||
FROM logs WHERE ${where2} AND username = $${params2.length}
|
||||
GROUP BY model
|
||||
@@ -323,12 +363,14 @@ export async function getUserDetail(
|
||||
calls: Number(o.calls),
|
||||
prompt_tokens: Number(o.prompt),
|
||||
completion_tokens: Number(o.completion),
|
||||
total_tokens: Number(o.prompt) + Number(o.completion),
|
||||
cache_creation_tokens: Number(o.cache_creation),
|
||||
cache_read_tokens: Number(o.cache_read),
|
||||
total_tokens: Number(o.prompt) + Number(o.completion) + Number(o.cache_creation) + Number(o.cache_read),
|
||||
quota: Number(o.quota),
|
||||
models: models.map((m) => ({
|
||||
name: m.model,
|
||||
calls: Number(m.calls),
|
||||
total_tokens: Number(m.tokens),
|
||||
total_tokens: Number(m.tokens) + Number(m.cache_creation) + Number(m.cache_read),
|
||||
quota: Number(m.quota),
|
||||
})),
|
||||
};
|
||||
@@ -347,6 +389,8 @@ export async function getModelDetail(
|
||||
`SELECT COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens),0)::bigint as prompt,
|
||||
COALESCE(SUM(completion_tokens),0)::bigint as completion,
|
||||
COALESCE(SUM(${CACHE_CREATION}),0)::bigint as cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}),0)::bigint as cache_read,
|
||||
COALESCE(SUM(quota),0)::bigint as quota
|
||||
FROM logs WHERE ${where} AND ${REAL_MODEL} = $${params.length}`,
|
||||
params
|
||||
@@ -361,6 +405,8 @@ export async function getModelDetail(
|
||||
`SELECT user_id, username,
|
||||
COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens + completion_tokens),0)::bigint as tokens,
|
||||
COALESCE(SUM(${CACHE_CREATION}),0)::bigint as cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}),0)::bigint as cache_read,
|
||||
COALESCE(SUM(quota),0)::bigint as quota
|
||||
FROM logs WHERE ${where2} AND ${REAL_MODEL} = $${params2.length}
|
||||
GROUP BY user_id, username
|
||||
@@ -373,12 +419,14 @@ export async function getModelDetail(
|
||||
calls: Number(o.calls),
|
||||
prompt_tokens: Number(o.prompt),
|
||||
completion_tokens: Number(o.completion),
|
||||
total_tokens: Number(o.prompt) + Number(o.completion),
|
||||
cache_creation_tokens: Number(o.cache_creation),
|
||||
cache_read_tokens: Number(o.cache_read),
|
||||
total_tokens: Number(o.prompt) + Number(o.completion) + Number(o.cache_creation) + Number(o.cache_read),
|
||||
quota: Number(o.quota),
|
||||
users: users.map((u) => ({
|
||||
name: displayNames[u.user_id] || u.username,
|
||||
calls: Number(u.calls),
|
||||
total_tokens: Number(u.tokens),
|
||||
total_tokens: Number(u.tokens) + Number(u.cache_creation) + Number(u.cache_read),
|
||||
quota: Number(u.quota),
|
||||
})),
|
||||
};
|
||||
@@ -399,6 +447,8 @@ export async function getChannelDetail(
|
||||
`SELECT COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens),0)::bigint as prompt,
|
||||
COALESCE(SUM(completion_tokens),0)::bigint as completion,
|
||||
COALESCE(SUM(${CACHE_CREATION}),0)::bigint as cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}),0)::bigint as cache_read,
|
||||
COALESCE(SUM(quota),0)::bigint as quota
|
||||
FROM logs WHERE ${where} AND channel_id = $${params.length}`,
|
||||
params
|
||||
@@ -412,6 +462,8 @@ export async function getChannelDetail(
|
||||
`SELECT ${REAL_MODEL} as model,
|
||||
COUNT(*)::int as calls,
|
||||
COALESCE(SUM(prompt_tokens + completion_tokens),0)::bigint as tokens,
|
||||
COALESCE(SUM(${CACHE_CREATION}),0)::bigint as cache_creation,
|
||||
COALESCE(SUM(${CACHE_READ}),0)::bigint as cache_read,
|
||||
COALESCE(SUM(quota),0)::bigint as quota
|
||||
FROM logs WHERE ${where2} AND channel_id = $${params2.length}
|
||||
GROUP BY model
|
||||
@@ -425,12 +477,14 @@ export async function getChannelDetail(
|
||||
calls: Number(o.calls),
|
||||
prompt_tokens: Number(o.prompt),
|
||||
completion_tokens: Number(o.completion),
|
||||
total_tokens: Number(o.prompt) + Number(o.completion),
|
||||
cache_creation_tokens: Number(o.cache_creation),
|
||||
cache_read_tokens: Number(o.cache_read),
|
||||
total_tokens: Number(o.prompt) + Number(o.completion) + Number(o.cache_creation) + Number(o.cache_read),
|
||||
quota: Number(o.quota),
|
||||
models: models.map((m) => ({
|
||||
name: m.model,
|
||||
calls: Number(m.calls),
|
||||
total_tokens: Number(m.tokens),
|
||||
total_tokens: Number(m.tokens) + Number(m.cache_creation) + Number(m.cache_read),
|
||||
quota: Number(m.quota),
|
||||
})),
|
||||
};
|
||||
@@ -449,6 +503,8 @@ export interface LogEntry {
|
||||
channel_id: number;
|
||||
prompt_tokens: number;
|
||||
completion_tokens: number;
|
||||
cache_creation_tokens: number;
|
||||
cache_read_tokens: number;
|
||||
total_tokens: number;
|
||||
quota: number;
|
||||
quota_usd: number;
|
||||
@@ -513,6 +569,8 @@ export async function getLogs(options: {
|
||||
`SELECT id, created_at, user_id, username, model_name,
|
||||
${REAL_MODEL} as real_model,
|
||||
channel_id, prompt_tokens, completion_tokens, quota,
|
||||
${CACHE_CREATION} as cache_creation,
|
||||
${CACHE_READ} as cache_read,
|
||||
use_time, is_stream, token_name
|
||||
FROM logs WHERE ${where}
|
||||
ORDER BY id DESC
|
||||
@@ -535,7 +593,9 @@ export async function getLogs(options: {
|
||||
channel_id: Number(r.channel_id),
|
||||
prompt_tokens: Number(r.prompt_tokens),
|
||||
completion_tokens: Number(r.completion_tokens),
|
||||
total_tokens: Number(r.prompt_tokens) + Number(r.completion_tokens),
|
||||
cache_creation_tokens: Number(r.cache_creation),
|
||||
cache_read_tokens: Number(r.cache_read),
|
||||
total_tokens: Number(r.prompt_tokens) + Number(r.completion_tokens) + Number(r.cache_creation) + Number(r.cache_read),
|
||||
quota: Number(r.quota),
|
||||
quota_usd: Number(r.quota) / 500000,
|
||||
use_time: Number(r.use_time),
|
||||
|
||||
Reference in New Issue
Block a user