feat: 实现基于费用的速率限制功能

- 新增 rateLimitCost 字段,支持按费用进行速率限制
- 新增 weeklyOpusCostLimit 字段,支持 Opus 模型周费用限制
- 优化速率限制逻辑,支持费用、请求数、token多维度控制
- 更新前端界面,添加费用限制配置选项
- 增强账户管理功能,支持费用统计和限制
- 改进 Redis 数据模型,支持费用计数器
- 优化价格计算服务,支持更精确的成本核算

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-08-31 17:27:37 +08:00
parent a54622e3d7
commit e84c6a5555
21 changed files with 1662 additions and 161 deletions

View File

@@ -69,9 +69,57 @@ class CostCalculator {
* @returns {Object} 费用详情
*/
static calculateCost(usage, model = 'unknown') {
// 如果 usage 包含详细的 cache_creation 对象,使用 pricingService 来处理
if (usage.cache_creation && typeof usage.cache_creation === 'object') {
return pricingService.calculateCost(usage, model)
// 如果 usage 包含详细的 cache_creation 对象或是 1M 模型,使用 pricingService 来处理
if (
(usage.cache_creation && typeof usage.cache_creation === 'object') ||
(model && model.includes('[1m]'))
) {
const result = pricingService.calculateCost(usage, model)
// 转换 pricingService 返回的格式到 costCalculator 的格式
return {
model,
pricing: {
input: result.pricing.input * 1000000, // 转换为 per 1M tokens
output: result.pricing.output * 1000000,
cacheWrite: result.pricing.cacheCreate * 1000000,
cacheRead: result.pricing.cacheRead * 1000000
},
usingDynamicPricing: true,
isLongContextRequest: result.isLongContextRequest || false,
usage: {
inputTokens: usage.input_tokens || 0,
outputTokens: usage.output_tokens || 0,
cacheCreateTokens: usage.cache_creation_input_tokens || 0,
cacheReadTokens: usage.cache_read_input_tokens || 0,
totalTokens:
(usage.input_tokens || 0) +
(usage.output_tokens || 0) +
(usage.cache_creation_input_tokens || 0) +
(usage.cache_read_input_tokens || 0)
},
costs: {
input: result.inputCost,
output: result.outputCost,
cacheWrite: result.cacheCreateCost,
cacheRead: result.cacheReadCost,
total: result.totalCost
},
formatted: {
input: this.formatCost(result.inputCost),
output: this.formatCost(result.outputCost),
cacheWrite: this.formatCost(result.cacheCreateCost),
cacheRead: this.formatCost(result.cacheReadCost),
total: this.formatCost(result.totalCost)
},
debug: {
isOpenAIModel: model.includes('gpt') || model.includes('o1'),
hasCacheCreatePrice: !!result.pricing.cacheCreate,
cacheCreateTokens: usage.cache_creation_input_tokens || 0,
cacheWritePriceUsed: result.pricing.cacheCreate * 1000000,
isLongContextModel: model && model.includes('[1m]'),
isLongContextRequest: result.isLongContextRequest || false
}
}
}
// 否则使用旧的逻辑(向后兼容)