feat(api,ui): 新增24h错误码最高Key统计与面板

- 新增 GET /api/stats/attention-keys 接口,统计最近24小时指定
  状态码(默认429)错误次数最多的 Key,仅统计内存中的 Key,
  支持 limit 与 status_code 参数
- StatsService 新增 get_attention_keys_last_24h,按 api_key 分组计数并
  降序返回
- UI 新增“值得注意的Key”卡片:支持 429/403/400 快捷切换、自定义状态码
  与数量限制,默认展示 429 前 10
- 列表项支持验证、查看 24h 详情、复制、删除等快捷操作
- 将 Chart.js 与页面脚本改为 defer,保证 DOM 就绪与执行顺序
- 修复:补充获取数量输入框引用,避免初始化未声明变量报错
- 其他:微调日志输出格式
This commit is contained in:
snaily
2025-08-18 06:28:48 +08:00
parent e9601ca76c
commit 1aa3d267bb
4 changed files with 198 additions and 5 deletions
+35
View File
@@ -312,6 +312,41 @@ class StatsService:
)
raise
async def get_attention_keys_last_24h(self, include_keys: set[str], limit: int = 20, status_code: int = 429) -> list[dict]:
"""返回最近24小时内指定状态码(默认429)最多的Key列表,仅包含include_keys中的Key。
Returns: [{"key": str, "count": int, "status_code": int}, ...] 按次数降序
"""
try:
now = datetime.datetime.now()
start_time = now - datetime.timedelta(hours=24)
if not include_keys:
return []
query = (
select(
RequestLog.api_key.label("key"),
func.count(RequestLog.id).label("count"),
)
.where(
RequestLog.request_time >= start_time,
RequestLog.status_code == status_code,
RequestLog.api_key.isnot(None),
RequestLog.api_key.in_(list(include_keys)),
)
.group_by(RequestLog.api_key)
.order_by(func.count(RequestLog.id).desc())
.limit(limit)
)
rows = await database.fetch_all(query)
return [
{"key": row["key"], "count": row["count"], "status_code": status_code}
for row in rows
if row["key"]
]
except Exception as e:
logger.error(f"Failed to get attention keys ({status_code}) in last 24h: {e}")
return []
async def get_key_usage_details_last_24h(self, key: str) -> Union[dict, None]:
"""
获取指定 API 密钥在过去 24 小时内按模型统计的调用次数。