first commit

This commit is contained in:
shaw
2025-07-14 18:14:13 +08:00
parent a96a372011
commit b1ca3f307e
31 changed files with 20046 additions and 21 deletions

224
src/utils/costCalculator.js Normal file
View File

@@ -0,0 +1,224 @@
const pricingService = require('../services/pricingService');
// Claude模型价格配置 (USD per 1M tokens) - 备用定价
const MODEL_PRICING = {
// Claude 3.5 Sonnet
'claude-3-5-sonnet-20241022': {
input: 3.00,
output: 15.00,
cacheWrite: 3.75,
cacheRead: 0.30
},
'claude-sonnet-4-20250514': {
input: 3.00,
output: 15.00,
cacheWrite: 3.75,
cacheRead: 0.30
},
// Claude 3.5 Haiku
'claude-3-5-haiku-20241022': {
input: 0.25,
output: 1.25,
cacheWrite: 0.30,
cacheRead: 0.03
},
// Claude 3 Opus
'claude-3-opus-20240229': {
input: 15.00,
output: 75.00,
cacheWrite: 18.75,
cacheRead: 1.50
},
// Claude 3 Sonnet
'claude-3-sonnet-20240229': {
input: 3.00,
output: 15.00,
cacheWrite: 3.75,
cacheRead: 0.30
},
// Claude 3 Haiku
'claude-3-haiku-20240307': {
input: 0.25,
output: 1.25,
cacheWrite: 0.30,
cacheRead: 0.03
},
// 默认定价(用于未知模型)
'unknown': {
input: 3.00,
output: 15.00,
cacheWrite: 3.75,
cacheRead: 0.30
}
};
class CostCalculator {
/**
* 计算单次请求的费用
* @param {Object} usage - 使用量数据
* @param {number} usage.input_tokens - 输入token数量
* @param {number} usage.output_tokens - 输出token数量
* @param {number} usage.cache_creation_input_tokens - 缓存创建token数量
* @param {number} usage.cache_read_input_tokens - 缓存读取token数量
* @param {string} model - 模型名称
* @returns {Object} 费用详情
*/
static calculateCost(usage, model = 'unknown') {
const inputTokens = usage.input_tokens || 0;
const outputTokens = usage.output_tokens || 0;
const cacheCreateTokens = usage.cache_creation_input_tokens || 0;
const cacheReadTokens = usage.cache_read_input_tokens || 0;
// 优先使用动态价格服务
const pricingData = pricingService.getModelPricing(model);
let pricing;
let usingDynamicPricing = false;
if (pricingData) {
// 转换动态价格格式为内部格式
pricing = {
input: (pricingData.input_cost_per_token || 0) * 1000000, // 转换为per 1M tokens
output: (pricingData.output_cost_per_token || 0) * 1000000,
cacheWrite: (pricingData.cache_creation_input_token_cost || 0) * 1000000,
cacheRead: (pricingData.cache_read_input_token_cost || 0) * 1000000
};
usingDynamicPricing = true;
} else {
// 回退到静态价格
pricing = MODEL_PRICING[model] || MODEL_PRICING['unknown'];
}
// 计算各类型token的费用 (USD)
const inputCost = (inputTokens / 1000000) * pricing.input;
const outputCost = (outputTokens / 1000000) * pricing.output;
const cacheWriteCost = (cacheCreateTokens / 1000000) * pricing.cacheWrite;
const cacheReadCost = (cacheReadTokens / 1000000) * pricing.cacheRead;
const totalCost = inputCost + outputCost + cacheWriteCost + cacheReadCost;
return {
model,
pricing,
usingDynamicPricing,
usage: {
inputTokens,
outputTokens,
cacheCreateTokens,
cacheReadTokens,
totalTokens: inputTokens + outputTokens + cacheCreateTokens + cacheReadTokens
},
costs: {
input: inputCost,
output: outputCost,
cacheWrite: cacheWriteCost,
cacheRead: cacheReadCost,
total: totalCost
},
// 格式化的费用字符串
formatted: {
input: this.formatCost(inputCost),
output: this.formatCost(outputCost),
cacheWrite: this.formatCost(cacheWriteCost),
cacheRead: this.formatCost(cacheReadCost),
total: this.formatCost(totalCost)
}
};
}
/**
* 计算聚合使用量的费用
* @param {Object} aggregatedUsage - 聚合使用量数据
* @param {string} model - 模型名称
* @returns {Object} 费用详情
*/
static calculateAggregatedCost(aggregatedUsage, model = 'unknown') {
const usage = {
input_tokens: aggregatedUsage.inputTokens || aggregatedUsage.totalInputTokens || 0,
output_tokens: aggregatedUsage.outputTokens || aggregatedUsage.totalOutputTokens || 0,
cache_creation_input_tokens: aggregatedUsage.cacheCreateTokens || aggregatedUsage.totalCacheCreateTokens || 0,
cache_read_input_tokens: aggregatedUsage.cacheReadTokens || aggregatedUsage.totalCacheReadTokens || 0
};
return this.calculateCost(usage, model);
}
/**
* 获取模型定价信息
* @param {string} model - 模型名称
* @returns {Object} 定价信息
*/
static getModelPricing(model = 'unknown') {
return MODEL_PRICING[model] || MODEL_PRICING['unknown'];
}
/**
* 获取所有支持的模型和定价
* @returns {Object} 所有模型定价
*/
static getAllModelPricing() {
return { ...MODEL_PRICING };
}
/**
* 验证模型是否支持
* @param {string} model - 模型名称
* @returns {boolean} 是否支持
*/
static isModelSupported(model) {
return !!MODEL_PRICING[model];
}
/**
* 格式化费用显示
* @param {number} cost - 费用金额
* @param {number} decimals - 小数位数
* @returns {string} 格式化的费用字符串
*/
static formatCost(cost, decimals = 6) {
if (cost >= 1) {
return `$${cost.toFixed(2)}`;
} else if (cost >= 0.001) {
return `$${cost.toFixed(4)}`;
} else {
return `$${cost.toFixed(decimals)}`;
}
}
/**
* 计算费用节省(使用缓存的节省)
* @param {Object} usage - 使用量数据
* @param {string} model - 模型名称
* @returns {Object} 节省信息
*/
static calculateCacheSavings(usage, model = 'unknown') {
const pricing = this.getModelPricing(model);
const cacheReadTokens = usage.cache_read_input_tokens || 0;
// 如果这些token不使用缓存需要按正常input价格计费
const normalCost = (cacheReadTokens / 1000000) * pricing.input;
const cacheCost = (cacheReadTokens / 1000000) * pricing.cacheRead;
const savings = normalCost - cacheCost;
const savingsPercentage = normalCost > 0 ? (savings / normalCost) * 100 : 0;
return {
normalCost,
cacheCost,
savings,
savingsPercentage,
formatted: {
normalCost: this.formatCost(normalCost),
cacheCost: this.formatCost(cacheCost),
savings: this.formatCost(savings),
savingsPercentage: `${savingsPercentage.toFixed(1)}%`
}
};
}
}
module.exports = CostCalculator;