重构 TokenUtils: 从类改为对象,添加新的 pricing 和 usage 处理方法
- 将 TokenUtils 从类重构为对象 - 添加 getPricing 方法,支持 channel-specific 和 global pricing - 添加 processUsage 方法,集中处理使用量计算和记录 - 在 providers/index.ts 中简化 usage 处理逻辑 - 添加 API key 掩码功能以保护敏感信息
This commit is contained in:
1 parent
3b6c5b37c1
commit
8d4af1b895
2 files changed
+46
-37
No files matched your search
@@ -1,8 +1,11 @@
|
||||
import { Context } from "hono";
|
||||
|
||||
// Token 工具类
|
||||
export class TokenUtils {
|
||||
static async updateUsage(c: Context<HonoCustomType>, key: string, usageAmount: number): Promise<boolean> {
|
||||
import { CONSTANTS } from "../constants";
|
||||
import utils from "../utils";
|
||||
|
||||
// Token 工具对象
|
||||
export const TokenUtils = {
|
||||
async updateUsage(c: Context<HonoCustomType>, key: string, usageAmount: number): Promise<boolean> {
|
||||
try {
|
||||
const result = await c.env.DB.prepare(
|
||||
`UPDATE api_token SET usage = usage + ?, updated_at = datetime('now') WHERE key = ?`
|
||||
@@ -13,5 +16,40 @@ export class TokenUtils {
|
||||
console.error('Error updating token usage:', error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
async getPricing(c: Context<HonoCustomType>, model: string, channelConfig: ChannelConfig): Promise<ModelPricing | null> {
|
||||
// Check channel-specific pricing first
|
||||
if (channelConfig?.model_pricing?.[model]) {
|
||||
return channelConfig.model_pricing[model];
|
||||
}
|
||||
|
||||
// Fallback to global pricing
|
||||
const globalPricingMap = await utils.getJsonSetting(c, CONSTANTS.MODEL_PRICING_KEY);
|
||||
return globalPricingMap?.[model] || null;
|
||||
},
|
||||
|
||||
async processUsage(c: Context<HonoCustomType>, apiKey: string, model: string, targetChannelKey: string, targetChannelConfig: ChannelConfig, usage: Usage): Promise<void> {
|
||||
console.log("Usage data:", usage);
|
||||
|
||||
// Get pricing and calculate cost
|
||||
const pricing = await this.getPricing(c, model, targetChannelConfig);
|
||||
const hasTokens = usage.prompt_tokens && usage.completion_tokens;
|
||||
|
||||
if (pricing && hasTokens) {
|
||||
const inputCost = usage.prompt_tokens! * pricing.input;
|
||||
const outputCost = usage.completion_tokens! * pricing.output;
|
||||
const totalCost = inputCost + outputCost;
|
||||
// Update token usage and log data
|
||||
await this.updateUsage(c, apiKey, totalCost);
|
||||
// 长度不够直接显示 *
|
||||
var maskedApiKey = apiKey.length < 3 ? '*'.repeat(apiKey.length) : (
|
||||
apiKey.slice(0, apiKey.length / 3)
|
||||
+ '*'.repeat(apiKey.length / 3)
|
||||
+ apiKey.slice((2 * apiKey.length) / 3)
|
||||
);
|
||||
console.log(`Model: ${model}, Channel: ${targetChannelKey}, apiKey: ${maskedApiKey}, Cost: ${totalCost}`);
|
||||
} else {
|
||||
console.warn(`No pricing found for model: ${model} in channel: ${targetChannelKey}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
+4
-33
@@ -123,39 +123,10 @@ class ProxyEndpoint extends OpenAPIRoute {
|
||||
|
||||
return proxyFetch(c, targetChannelConfig,
|
||||
async (usage: Usage) => {
|
||||
console.log("Usage data:", usage);
|
||||
|
||||
// Calculate cost based on usage and model pricing
|
||||
// Model was already extracted above
|
||||
|
||||
// Get global pricing as base configuration
|
||||
let pricing = null;
|
||||
const globalPricing = await utils.getSetting(c, CONSTANTS.MODEL_PRICING_KEY);
|
||||
if (globalPricing) {
|
||||
const globalPricingMap = JSON.parse(globalPricing);
|
||||
pricing = globalPricingMap[model];
|
||||
}
|
||||
|
||||
// Override with channel-specific pricing if available
|
||||
if (targetChannelConfig.model_pricing?.[model]) {
|
||||
pricing = targetChannelConfig.model_pricing[model];
|
||||
}
|
||||
|
||||
if (pricing && usage.prompt_tokens && usage.completion_tokens) {
|
||||
const inputCost = usage.prompt_tokens * pricing.input;
|
||||
const outputCost = usage.completion_tokens * pricing.output;
|
||||
const totalCost = inputCost + outputCost;
|
||||
|
||||
// Update token usage using TokenUtils
|
||||
const updated = await TokenUtils.updateUsage(c, apiKey, totalCost);
|
||||
if (!updated) {
|
||||
console.error("Failed to update token usage");
|
||||
}
|
||||
|
||||
console.log(`Model: ${model}, Channel: ${targetChannelKey}, Channel pricing: ${!!targetChannelConfig.model_pricing?.[model]}, Cost: ${totalCost}, Updated: ${updated}`);
|
||||
}
|
||||
else {
|
||||
console.warn(`No pricing found for model: ${model} in channel: ${targetChannelKey}`);
|
||||
try {
|
||||
await TokenUtils.processUsage(c, apiKey, model, targetChannelKey, targetChannelConfig, usage);
|
||||
} catch (error) {
|
||||
console.error('Error processing usage:', error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user