mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-07 08:46:37 +08:00
refactor: 重构密钥状态页面为客户端动态加载
- 新增 key_routes.py 分离密钥相关路由逻辑 - 将密钥列表从服务器端渲染改为 JavaScript 动态加载 - 优化 keys_status 页面错误处理,提供默认数据结构 - 在 KeyManager 中添加 get_all_keys_with_fail_count 方法 - 移除服务器端模板中的静态密钥渲染代码 这次重构提升了页面加载性能和用户体验,同时改善了错误处理机制。
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from app.service.key.key_manager import KeyManager, get_key_manager_instance
|
||||
from app.core.security import verify_auth_token
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/api/keys")
|
||||
async def get_keys_paginated(
|
||||
request: Request,
|
||||
page: int = 1,
|
||||
limit: int = 10,
|
||||
search: str = None,
|
||||
fail_count_threshold: int = None,
|
||||
status: str = "all", # 'valid', 'invalid', 'all'
|
||||
key_manager: KeyManager = Depends(get_key_manager_instance),
|
||||
):
|
||||
"""
|
||||
Get paginated, filtered, and searched keys.
|
||||
"""
|
||||
auth_token = request.cookies.get("auth_token")
|
||||
if not auth_token or not verify_auth_token(auth_token):
|
||||
return JSONResponse(status_code=401, content={"detail": "Unauthorized"})
|
||||
|
||||
all_keys_with_status = await key_manager.get_all_keys_with_fail_count()
|
||||
|
||||
# Filter by status
|
||||
if status == "valid":
|
||||
keys_to_filter = all_keys_with_status["valid_keys"]
|
||||
elif status == "invalid":
|
||||
keys_to_filter = all_keys_with_status["invalid_keys"]
|
||||
else:
|
||||
# Combine both for 'all' status, which might be useful for a unified view if ever needed
|
||||
keys_to_filter = {**all_keys_with_status["valid_keys"], **all_keys_with_status["invalid_keys"]}
|
||||
|
||||
|
||||
# Further filtering (search and fail_count_threshold)
|
||||
filtered_keys = {}
|
||||
for key, fail_count in keys_to_filter.items():
|
||||
search_match = True
|
||||
if search:
|
||||
search_match = search.lower() in key.lower()
|
||||
|
||||
fail_count_match = True
|
||||
if fail_count_threshold is not None:
|
||||
fail_count_match = fail_count >= fail_count_threshold
|
||||
|
||||
if search_match and fail_count_match:
|
||||
filtered_keys[key] = fail_count
|
||||
|
||||
# Pagination
|
||||
keys_list = list(filtered_keys.items())
|
||||
total_items = len(keys_list)
|
||||
start_index = (page - 1) * limit
|
||||
end_index = start_index + limit
|
||||
paginated_keys = dict(keys_list[start_index:end_index])
|
||||
|
||||
return {
|
||||
"keys": paginated_keys,
|
||||
"total_items": total_items,
|
||||
"total_pages": (total_items + limit - 1) // limit,
|
||||
"current_page": page,
|
||||
}
|
||||
+23
-4
@@ -9,7 +9,7 @@ from fastapi.templating import Jinja2Templates
|
||||
from app.core.security import verify_auth_token
|
||||
from app.config.config import settings
|
||||
from app.log.logger import get_routes_logger
|
||||
from app.router import error_log_routes, gemini_routes, openai_routes, config_routes, scheduler_routes, stats_routes, version_routes, openai_compatiable_routes, vertex_express_routes, files_routes
|
||||
from app.router import error_log_routes, gemini_routes, openai_routes, config_routes, scheduler_routes, stats_routes, version_routes, openai_compatiable_routes, vertex_express_routes, files_routes, key_routes
|
||||
from app.service.key.key_manager import get_key_manager_instance
|
||||
from app.service.stats.stats_service import StatsService
|
||||
|
||||
@@ -36,6 +36,7 @@ def setup_routers(app: FastAPI) -> None:
|
||||
app.include_router(openai_compatiable_routes.router)
|
||||
app.include_router(vertex_express_routes.router)
|
||||
app.include_router(files_routes.router)
|
||||
app.include_router(key_routes.router)
|
||||
|
||||
setup_page_routes(app)
|
||||
|
||||
@@ -103,8 +104,8 @@ def setup_page_routes(app: FastAPI) -> None:
|
||||
"keys_status.html",
|
||||
{
|
||||
"request": request,
|
||||
"valid_keys": keys_status["valid_keys"],
|
||||
"invalid_keys": keys_status["invalid_keys"],
|
||||
"valid_keys": {},
|
||||
"invalid_keys": {},
|
||||
"total_keys": total_keys,
|
||||
"valid_key_count": valid_key_count,
|
||||
"invalid_key_count": invalid_key_count,
|
||||
@@ -113,7 +114,25 @@ def setup_page_routes(app: FastAPI) -> None:
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Error retrieving keys status or API stats: {str(e)}")
|
||||
raise
|
||||
# Even if there's an error, render the page with whatever data is available
|
||||
# or with empty/default values, so the frontend can still load.
|
||||
return templates.TemplateResponse(
|
||||
"keys_status.html",
|
||||
{
|
||||
"request": request,
|
||||
"valid_keys": {},
|
||||
"invalid_keys": {},
|
||||
"total_keys": 0,
|
||||
"valid_key_count": 0,
|
||||
"invalid_key_count": 0,
|
||||
"api_stats": { # Provide a default structure for api_stats
|
||||
"calls_1m": {"total": 0, "success": 0, "failure": 0},
|
||||
"calls_1h": {"total": 0, "success": 0, "failure": 0},
|
||||
"calls_24h": {"total": 0, "success": 0, "failure": 0},
|
||||
"calls_month": {"total": 0, "success": 0, "failure": 0},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
@app.get("/config", response_class=HTMLResponse)
|
||||
async def config_page(request: Request):
|
||||
|
||||
Reference in New Issue
Block a user