feat(api-keys): 添加模型筛选功能

This commit is contained in:
SunSeekerX
2025-12-05 13:44:09 +08:00
parent 94aca4dc22
commit 2429bad2b7
4 changed files with 215 additions and 14 deletions

View File

@@ -284,7 +284,8 @@ class RedisClient {
isActive = '',
sortBy = 'createdAt',
sortOrder = 'desc',
excludeDeleted = true // 默认排除已删除的 API Keys
excludeDeleted = true, // 默认排除已删除的 API Keys
modelFilter = []
} = options
// 1. 使用 SCAN 获取所有 apikey:* 的 ID 列表(避免阻塞)
@@ -332,6 +333,15 @@ class RedisClient {
}
}
// 模型筛选
if (modelFilter.length > 0) {
const keyIdsWithModels = await this.getKeyIdsWithModels(
filteredKeys.map((k) => k.id),
modelFilter
)
filteredKeys = filteredKeys.filter((k) => keyIdsWithModels.has(k.id))
}
// 4. 排序
filteredKeys.sort((a, b) => {
// status 排序实际上使用 isActive 字段API Key 没有 status 字段)
@@ -781,6 +791,56 @@ class RedisClient {
await Promise.all(operations)
}
/**
* 获取使用了指定模型的 Key IDsOR 逻辑)
*/
async getKeyIdsWithModels(keyIds, models) {
if (!keyIds.length || !models.length) return new Set()
const client = this.getClientSafe()
const result = new Set()
// 批量检查每个 keyId 是否使用过任意一个指定模型
for (const keyId of keyIds) {
for (const model of models) {
// 检查是否有该模型的使用记录daily 或 monthly
const pattern = `usage:${keyId}:model:*:${model}:*`
const keys = await client.keys(pattern)
if (keys.length > 0) {
result.add(keyId)
break // 找到一个就够了OR 逻辑)
}
}
}
return result
}
/**
* 获取所有被使用过的模型列表
*/
async getAllUsedModels() {
const client = this.getClientSafe()
const models = new Set()
// 扫描所有模型使用记录
const pattern = 'usage:*:model:daily:*'
let cursor = '0'
do {
const [nextCursor, keys] = await client.scan(cursor, 'MATCH', pattern, 'COUNT', 1000)
cursor = nextCursor
for (const key of keys) {
// 从 key 中提取模型名: usage:{keyId}:model:daily:{model}:{date}
const match = key.match(/usage:[^:]+:model:daily:([^:]+):/)
if (match) {
models.add(match[1])
}
}
} while (cursor !== '0')
return [...models].sort()
}
async getUsageStats(keyId) {
const totalKey = `usage:${keyId}`
const today = getDateStringInTimezone()