fix: 修复apikey最后使用查找问题

This commit is contained in:
shaw
2025-10-17 22:36:31 +08:00
parent b0e6ac3923
commit 17311f2d3b

View File

@@ -5,25 +5,35 @@ const redis = require('../models/redis')
const logger = require('../utils/logger') const logger = require('../utils/logger')
const ACCOUNT_TYPE_CONFIG = { const ACCOUNT_TYPE_CONFIG = {
claude: { prefix: 'claude_account:', category: 'claude' }, claude: { prefix: 'claude_account:' },
'claude-console': { prefix: 'claude_console_account:', category: 'claude' }, 'claude-console': { prefix: 'claude_console_account:' },
openai: { prefix: 'openai:account:', category: 'openai' }, openai: { prefix: 'openai:account:' },
'openai-responses': { prefix: 'openai_responses_account:', category: 'openai' }, 'openai-responses': { prefix: 'openai_responses_account:' },
'azure-openai': { prefix: 'azure_openai:account:', category: 'openai' }, 'azure-openai': { prefix: 'azure_openai:account:' },
gemini: { prefix: 'gemini_account:', category: 'gemini' }, gemini: { prefix: 'gemini_account:' },
droid: { prefix: 'droid:account:', category: 'droid' } droid: { prefix: 'droid:account:' }
} }
const DEFAULT_LAST_USAGE_TYPES = [ const ACCOUNT_TYPE_PRIORITY = [
'claude',
'claude-console',
'openai', 'openai',
'openai-responses', 'openai-responses',
'azure-openai', 'azure-openai',
'claude',
'claude-console',
'gemini', 'gemini',
'droid' 'droid'
] ]
const ACCOUNT_CATEGORY_MAP = {
claude: 'claude',
'claude-console': 'claude',
openai: 'openai',
'openai-responses': 'openai',
'azure-openai': 'openai',
gemini: 'gemini',
droid: 'droid'
}
function normalizeAccountTypeKey(type) { function normalizeAccountTypeKey(type) {
if (!type) { if (!type) {
return null return null
@@ -1293,61 +1303,60 @@ class ApiKeyService {
return null return null
} }
async _resolveLastUsageAccount(apiKey, usageRecord, cache, client) { async _resolveAccountByUsageRecord(usageRecord, cache, client) {
if (!client || !usageRecord) { if (!usageRecord || !client) {
return null
}
const rawAccountId = usageRecord.accountId || null
const rawAccountType = normalizeAccountTypeKey(usageRecord.accountType)
const modelName = usageRecord.model || usageRecord.actualModel || usageRecord.service || null
if (!rawAccountId && !rawAccountType) {
return null return null
} }
const candidateIds = new Set() const candidateIds = new Set()
const addId = (value) => { if (rawAccountId) {
if (!value) { candidateIds.add(rawAccountId)
return if (typeof rawAccountId === 'string' && rawAccountId.startsWith('responses:')) {
} candidateIds.add(rawAccountId.replace(/^responses:/, ''))
candidateIds.add(value)
if (typeof value === 'string' && value.startsWith('responses:')) {
candidateIds.add(value.replace(/^responses:/, ''))
} }
} }
addId(usageRecord.accountId) if (candidateIds.size === 0) {
addId(apiKey?.openaiAccountId) return null
addId(apiKey?.azureOpenaiAccountId) }
addId(apiKey?.claudeAccountId)
addId(apiKey?.claudeConsoleAccountId)
addId(apiKey?.geminiAccountId)
addId(apiKey?.droidAccountId)
const candidateTypes = [] const typeCandidates = []
const addType = (type) => { const pushType = (type) => {
const normalized = normalizeAccountTypeKey(type) const normalized = normalizeAccountTypeKey(type)
if (normalized && !candidateTypes.includes(normalized)) { if (normalized && ACCOUNT_TYPE_CONFIG[normalized] && !typeCandidates.includes(normalized)) {
candidateTypes.push(normalized) typeCandidates.push(normalized)
} }
} }
addType(usageRecord.accountType) pushType(rawAccountType)
if (apiKey?.claudeAccountId) {
addType('claude') if (modelName) {
} const lowerModel = modelName.toLowerCase()
if (apiKey?.claudeConsoleAccountId) { if (lowerModel.includes('gpt') || lowerModel.includes('openai')) {
addType('claude-console') pushType('openai')
} pushType('openai-responses')
if (apiKey?.geminiAccountId) { pushType('azure-openai')
addType('gemini') } else if (lowerModel.includes('gemini')) {
} pushType('gemini')
if (apiKey?.openaiAccountId) { } else if (lowerModel.includes('claude') || lowerModel.includes('anthropic')) {
addType(apiKey.openaiAccountId.startsWith('responses:') ? 'openai-responses' : 'openai') pushType('claude')
} pushType('claude-console')
if (apiKey?.azureOpenaiAccountId) { } else if (lowerModel.includes('droid')) {
addType('azure-openai') pushType('droid')
} }
if (apiKey?.droidAccountId) {
addType('droid')
} }
DEFAULT_LAST_USAGE_TYPES.forEach(addType) ACCOUNT_TYPE_PRIORITY.forEach(pushType)
for (const type of candidateTypes) { for (const type of typeCandidates) {
const accountConfig = ACCOUNT_TYPE_CONFIG[type] const accountConfig = ACCOUNT_TYPE_CONFIG[type]
if (!accountConfig) { if (!accountConfig) {
continue continue
@@ -1358,10 +1367,11 @@ class ApiKeyService {
const accountInfo = await this._fetchAccountInfo(normalizedId, type, cache, client) const accountInfo = await this._fetchAccountInfo(normalizedId, type, cache, client)
if (accountInfo) { if (accountInfo) {
return { return {
accountId: accountInfo.id, accountId: normalizedId,
accountName: accountInfo.name, accountName: accountInfo.name,
accountType: type, accountType: type,
accountCategory: accountConfig.category accountCategory: ACCOUNT_CATEGORY_MAP[type] || 'other',
rawAccountId: rawAccountId || normalizedId
} }
} }
} }
@@ -1370,6 +1380,10 @@ class ApiKeyService {
return null return null
} }
async _resolveLastUsageAccount(apiKey, usageRecord, cache, client) {
return await this._resolveAccountByUsageRecord(usageRecord, cache, client)
}
// 🔔 发布计费事件(内部方法) // 🔔 发布计费事件(内部方法)
async _publishBillingEvent(eventData) { async _publishBillingEvent(eventData) {
try { try {