From ff554d7c709de10f53afd7c76ad5ba356d56871a Mon Sep 17 00:00:00 2001 From: shaw Date: Sun, 20 Jul 2025 21:18:39 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=80=BBToken?= =?UTF-8?q?=E6=B6=88=E8=80=97USD=E8=AE=A1=E7=AE=97=E4=B8=8E=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E7=BB=9F=E8=AE=A1=E4=B8=8D=E4=B8=80=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修正Redis key匹配模式从 'usage:model:*:*' 到 'usage:model:*:*:*' - 更新正则表达式以支持hourly统计数据 - 确保所有模型都使用正确的价格计算费用 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/routes/admin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/admin.js b/src/routes/admin.js index c2f993b5..43a1bf4a 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -1191,7 +1191,7 @@ router.get('/usage-costs', authenticateAdmin, async (req, res) => { pattern = `usage:model:monthly:*:${currentMonth}`; } else { // 全部时间,先尝试从Redis获取所有历史模型统计数据 - const allModelKeys = await client.keys('usage:model:*:*'); + const allModelKeys = await client.keys('usage:model:*:*:*'); logger.info(`💰 Total period calculation: found ${allModelKeys.length} model keys`); if (allModelKeys.length > 0) { @@ -1200,7 +1200,7 @@ router.get('/usage-costs', authenticateAdmin, async (req, res) => { for (const key of allModelKeys) { // 解析模型名称 - let modelMatch = key.match(/usage:model:(?:daily|monthly):(.+):\d{4}-\d{2}(?:-\d{2})?$/); + let modelMatch = key.match(/usage:model:(?:daily|monthly|hourly):(.+):(\d{4}-\d{2}(?:-\d{2})?(?::\d{2})?)$/); if (!modelMatch) continue; const model = modelMatch[1]; From 4f0d8db7574b66686478a11edab7a543a3dbfdf6 Mon Sep 17 00:00:00 2001 From: shaw Date: Sun, 20 Jul 2025 21:36:51 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=80=BBToken?= =?UTF-8?q?=E6=B6=88=E8=80=97USD=E8=AE=A1=E7=AE=97=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将usage-costs的all模式改为只使用monthly数据,避免daily、monthly、hourly重复计算 - 更新正则表达式只匹配monthly格式的key - 确保总消耗与模型统计表格的USD计算保持一致 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/routes/admin.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/routes/admin.js b/src/routes/admin.js index 43a1bf4a..cf726bf2 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -1190,17 +1190,17 @@ router.get('/usage-costs', authenticateAdmin, async (req, res) => { } else if (period === 'monthly') { pattern = `usage:model:monthly:*:${currentMonth}`; } else { - // 全部时间,先尝试从Redis获取所有历史模型统计数据 - const allModelKeys = await client.keys('usage:model:*:*:*'); - logger.info(`💰 Total period calculation: found ${allModelKeys.length} model keys`); + // 全部时间,先尝试从Redis获取所有历史模型统计数据(只使用monthly数据避免重复计算) + const allModelKeys = await client.keys('usage:model:monthly:*:*'); + logger.info(`💰 Total period calculation: found ${allModelKeys.length} monthly model keys`); if (allModelKeys.length > 0) { // 如果有详细的模型统计数据,使用模型级别的计算 const modelUsageMap = new Map(); for (const key of allModelKeys) { - // 解析模型名称 - let modelMatch = key.match(/usage:model:(?:daily|monthly|hourly):(.+):(\d{4}-\d{2}(?:-\d{2})?(?::\d{2})?)$/); + // 解析模型名称(只处理monthly数据) + let modelMatch = key.match(/usage:model:monthly:(.+):(\d{4}-\d{2})$/); if (!modelMatch) continue; const model = modelMatch[1];