mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-23 04:09:49 +00:00
feat: add GLM Coding (China) provider and Usage by API Keys statistics
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
decolua
co-authored by
Cursor
parent
bd23ab41ee
commit
1ae4e311b7
+82
-4
@@ -139,7 +139,7 @@ export async function getUsageDb() {
|
||||
|
||||
/**
|
||||
* Save request usage
|
||||
* @param {object} entry - Usage entry { provider, model, tokens: { prompt_tokens, completion_tokens, ... }, connectionId? }
|
||||
* @param {object} entry - Usage entry { provider, model, tokens: { prompt_tokens, completion_tokens, ... }, connectionId?, apiKey? }
|
||||
*/
|
||||
export async function saveRequestUsage(entry) {
|
||||
if (isCloud) return; // Skip saving in Workers
|
||||
@@ -349,8 +349,8 @@ export async function getUsageStats() {
|
||||
const db = await getUsageDb();
|
||||
const history = db.data.history || [];
|
||||
|
||||
// Import localDb to get provider connection names
|
||||
const { getProviderConnections } = await import("@/lib/localDb.js");
|
||||
// Import localDb to get provider connection names and API keys
|
||||
const { getProviderConnections, getApiKeys } = await import("@/lib/localDb.js");
|
||||
|
||||
// Fetch all provider connections to get account names
|
||||
let allConnections = [];
|
||||
@@ -367,14 +367,33 @@ export async function getUsageStats() {
|
||||
connectionMap[conn.id] = conn.name || conn.email || conn.id;
|
||||
}
|
||||
|
||||
// Fetch all API keys to get key names
|
||||
let allApiKeys = [];
|
||||
try {
|
||||
allApiKeys = await getApiKeys();
|
||||
} catch (error) {
|
||||
console.warn("Could not fetch API keys for usage stats:", error.message);
|
||||
}
|
||||
|
||||
// Create a map from API key to key info
|
||||
const apiKeyMap = {};
|
||||
for (const key of allApiKeys) {
|
||||
apiKeyMap[key.key] = {
|
||||
name: key.name,
|
||||
id: key.id,
|
||||
createdAt: key.createdAt
|
||||
};
|
||||
}
|
||||
|
||||
const stats = {
|
||||
totalRequests: history.length,
|
||||
totalPromptTokens: 0,
|
||||
totalCompletionTokens: 0,
|
||||
totalCost: 0, // NEW
|
||||
totalCost: 0,
|
||||
byProvider: {},
|
||||
byModel: {},
|
||||
byAccount: {},
|
||||
byApiKey: {},
|
||||
last10Minutes: [],
|
||||
pending: pendingRequests,
|
||||
activeRequests: []
|
||||
@@ -507,6 +526,65 @@ export async function getUsageStats() {
|
||||
stats.byAccount[accountKey].lastUsed = entry.timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle requests with API key
|
||||
if (entry.apiKey && typeof entry.apiKey === "string") {
|
||||
const keyInfo = apiKeyMap[entry.apiKey];
|
||||
const keyName = keyInfo?.name || entry.apiKey.slice(0, 8) + "...";
|
||||
// Use full API key to avoid collisions (keys with same prefix)
|
||||
const apiKeyKey = entry.apiKey;
|
||||
// Group by API Key + Model + Provider combination to track different models used with the same key
|
||||
const apiKeyModelKey = `${apiKeyKey}|${entry.model}|${entry.provider || 'unknown'}`;
|
||||
|
||||
if (!stats.byApiKey[apiKeyModelKey]) {
|
||||
stats.byApiKey[apiKeyModelKey] = {
|
||||
requests: 0,
|
||||
promptTokens: 0,
|
||||
completionTokens: 0,
|
||||
cost: 0,
|
||||
rawModel: entry.model,
|
||||
provider: entry.provider,
|
||||
apiKey: entry.apiKey,
|
||||
keyName: keyName,
|
||||
apiKeyKey: apiKeyKey,
|
||||
lastUsed: entry.timestamp
|
||||
};
|
||||
}
|
||||
const apiKeyEntry = stats.byApiKey[apiKeyModelKey];
|
||||
apiKeyEntry.requests++;
|
||||
apiKeyEntry.promptTokens += promptTokens;
|
||||
apiKeyEntry.completionTokens += completionTokens;
|
||||
apiKeyEntry.cost += entryCost;
|
||||
if (new Date(entry.timestamp) > new Date(apiKeyEntry.lastUsed)) {
|
||||
apiKeyEntry.lastUsed = entry.timestamp;
|
||||
}
|
||||
} else {
|
||||
const apiKeyKey = "local-no-key";
|
||||
const keyName = "Local (No API Key)";
|
||||
|
||||
if (!stats.byApiKey[apiKeyKey]) {
|
||||
stats.byApiKey[apiKeyKey] = {
|
||||
requests: 0,
|
||||
promptTokens: 0,
|
||||
completionTokens: 0,
|
||||
cost: 0,
|
||||
rawModel: entry.model,
|
||||
provider: entry.provider,
|
||||
apiKey: null,
|
||||
keyName: keyName,
|
||||
apiKeyKey: apiKeyKey,
|
||||
lastUsed: entry.timestamp
|
||||
};
|
||||
}
|
||||
const apiKeyEntry = stats.byApiKey[apiKeyKey];
|
||||
apiKeyEntry.requests++;
|
||||
apiKeyEntry.promptTokens += promptTokens;
|
||||
apiKeyEntry.completionTokens += completionTokens;
|
||||
apiKeyEntry.cost += entryCost;
|
||||
if (new Date(entry.timestamp) > new Date(apiKeyEntry.lastUsed)) {
|
||||
apiKeyEntry.lastUsed = entry.timestamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
|
||||
Reference in New Issue
Block a user