Files
gemini-balance/app/router/config_routes.py
snaily 4becc8d4d4 feat: 改进错误日志功能并优化应用初始化流程
本次提交主要包含以下更新:

- **错误日志页面增强**:
    - 重构了 [`app/static/js/error_logs.js`](app/static/js/error_logs.js) 中的分页逻辑,将样式控制移至 CSS,简化了 JavaScript 代码。
    - 更新了 [`app/templates/error_logs.html`](app/templates/error_logs.html) 中的分页样式,使其与 `keys_status.html` 保持一致,提升了视觉统一性。
    - 在错误日志页面新增了“清空全部”按钮,方便用户一键清除所有错误记录。
    - 调整了错误日志表格头部的文本颜色为白色,以改善深色主题下的可读性。

- **应用初始化与配置优化**:
    - 调整了 [`app/config/config.py`](app/config/config.py) 中日志记录器的获取方式,确保在配置加载早期即可用。
    - 在 [`app/core/application.py`](app/core/application.py) 中引入了更明确的数据库连接管理(连接、断开、初始化)逻辑。
    - 优化了 [`app/utils/helpers.py`](app/utils/helpers.py) 中项目路径和版本文件路径的定义方式,使其在模块级别初始化。

- **依赖清理**:
    - 从 [`requirements.txt`](requirements.txt) 中移除了不必要的注释。

这些更改旨在提升错误日志模块的用户体验和功能性,并优化应用程序的启动和配置管理流程。
2025-05-14 14:25:04 +08:00

134 lines
5.2 KiB
Python

"""
配置路由模块
"""
from typing import Any, Dict, List
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import RedirectResponse
from pydantic import BaseModel, Field
from app.core.security import verify_auth_token
from app.log.logger import Logger, get_config_routes_logger
from app.service.config.config_service import ConfigService
router = APIRouter(prefix="/api/config", tags=["config"])
logger = get_config_routes_logger()
@router.get("", response_model=Dict[str, Any])
async def get_config(request: Request):
auth_token = request.cookies.get("auth_token")
if not auth_token or not verify_auth_token(auth_token):
logger.warning("Unauthorized access attempt to config page")
return RedirectResponse(url="/", status_code=302)
return await ConfigService.get_config()
@router.put("", response_model=Dict[str, Any])
async def update_config(config_data: Dict[str, Any], request: Request):
auth_token = request.cookies.get("auth_token")
if not auth_token or not verify_auth_token(auth_token):
logger.warning("Unauthorized access attempt to config page")
return RedirectResponse(url="/", status_code=302)
try:
result = await ConfigService.update_config(config_data)
# 配置更新成功后,立即更新所有 logger 的级别
Logger.update_log_levels(config_data["LOG_LEVEL"])
logger.info("Log levels updated after configuration change.")
return result
except Exception as e:
logger.error(f"Error updating config or log levels: {e}", exc_info=True)
raise HTTPException(status_code=400, detail=str(e))
@router.post("/reset", response_model=Dict[str, Any])
async def reset_config(request: Request):
auth_token = request.cookies.get("auth_token")
if not auth_token or not verify_auth_token(auth_token):
logger.warning("Unauthorized access attempt to config page")
return RedirectResponse(url="/", status_code=302)
try:
return await ConfigService.reset_config()
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
class DeleteKeysRequest(BaseModel):
keys: List[str] = Field(..., description="List of API keys to delete")
@router.delete("/keys/{key_to_delete}", response_model=Dict[str, Any])
async def delete_single_key(key_to_delete: str, request: Request):
auth_token = request.cookies.get("auth_token")
if not auth_token or not verify_auth_token(auth_token):
logger.warning(f"Unauthorized attempt to delete key: {key_to_delete}")
return RedirectResponse(url="/", status_code=302)
try:
logger.info(f"Attempting to delete key: {key_to_delete}")
result = await ConfigService.delete_key(key_to_delete)
if not result.get("success"):
raise HTTPException(
status_code=(
404 if "not found" in result.get("message", "").lower() else 400
),
detail=result.get("message"),
)
return result
except HTTPException as e:
raise e
except Exception as e:
logger.error(f"Error deleting key '{key_to_delete}': {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Error deleting key: {str(e)}")
@router.post("/keys/delete-selected", response_model=Dict[str, Any])
async def delete_selected_keys_route(
delete_request: DeleteKeysRequest, request: Request
):
auth_token = request.cookies.get("auth_token")
if not auth_token or not verify_auth_token(auth_token):
logger.warning("Unauthorized attempt to bulk delete keys")
return RedirectResponse(url="/", status_code=302)
if not delete_request.keys:
logger.warning("Attempt to bulk delete keys with an empty list.")
raise HTTPException(status_code=400, detail="No keys provided for deletion.")
try:
logger.info(f"Attempting to bulk delete {len(delete_request.keys)} keys.")
result = await ConfigService.delete_selected_keys(delete_request.keys)
if not result.get("success") and result.get("deleted_count", 0) == 0:
raise HTTPException(
status_code=400, detail=result.get("message", "Failed to delete keys.")
)
return result
except HTTPException as e:
raise e
except Exception as e:
logger.error(f"Error bulk deleting keys: {e}", exc_info=True)
raise HTTPException(
status_code=500, detail=f"Error bulk deleting keys: {str(e)}"
)
@router.get("/ui/models")
async def get_ui_models(request: Request):
auth_token_cookie = request.cookies.get("auth_token")
if not auth_token_cookie or not verify_auth_token(auth_token_cookie):
logger.warning("Unauthorized access attempt to /api/config/ui/models")
raise HTTPException(status_code=403, detail="Not authenticated")
try:
models = await ConfigService.fetch_ui_models()
return models
except HTTPException as e:
raise e
except Exception as e:
logger.error(f"Unexpected error in /ui/models endpoint: {e}", exc_info=True)
raise HTTPException(
status_code=500,
detail=f"An unexpected error occurred while fetching UI models: {str(e)}",
)