mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-05-14 20:08:33 +08:00
本次更新引入了对 Google Vertex AI Express API 的支持,允许用户配置和使用 Vertex AI 模型。 主要变更包括: 后端: - 新增 `VERTEX_API_KEYS` 和 `VERTEX_EXPRESS_BASE_URL` 至系统配置 ([`.env.example`](.env.example:13), [`app/config/config.py:62`](app/config/config.py:62), [`app/database/models.py`](app/database/models.py), [`app/database/services.py`](app/database/services.py))。 - 实现 `VertexExpressChatService` ([`app/service/chat/vertex_express_chat_service.py`](app/service/chat/vertex_express_chat_service.py)) 用于处理与 Vertex AI Express API 的交互。 - 添加 `vertex_express_routes` ([`app/router/vertex_express_routes.py`](app/router/vertex_express_routes.py)) 来暴露 Vertex AI 相关的 API 端点,并集成到主应用 ([`app/core/application.py:36`](app/core/application.py:36), [`app/router/routes.py:15`](app/router/routes.py:15))。 - 更新密钥管理器 ([`app/service/key/key_manager.py`](app/service/key/key_manager.py)) 以支持 Vertex API 密钥的获取、检查和轮换。 前端 (配置编辑器): - 在配置页面 ([`app/templates/config_editor.html:463`](app/templates/config_editor.html:463)) 添加了 Vertex API 密钥列表和 Vertex Express API 基础 URL 的表单字段。 - 实现了批量添加和删除 Vertex API 密钥的功能,包括相应的模态框和操作逻辑 ([`app/static/js/config_editor.js:550`](app/static/js/config_editor.js:550), [`app/static/js/config_editor.js:1097`](app/static/js/config_editor.js:1097), [`app/templates/config_editor.html:1657`](app/templates/config_editor.html:1657))。 - 确保新的配置项在初始化 ([`app/static/js/config_editor.js:598`](app/static/js/config_editor.js:598)) 和表单填充 ([`app/static/js/config_editor.js:671`](app/static/js/config_editor.js:671)) 时得到正确处理。 - 更新了数组项添加逻辑以识别 `VERTEX_API_KEYS` 为敏感字段 ([`app/static/js/config_editor.js:1235`](app/static/js/config_editor.js:1235))。 此功能扩展了应用支持的 AI 服务范围,为用户提供了更多模型选择。
179 lines
5.7 KiB
Python
179 lines
5.7 KiB
Python
from datetime import datetime, timedelta, timezone
|
||
from typing import Any, Dict, List, Optional
|
||
|
||
from sqlalchemy import delete, func, select
|
||
|
||
from app.config.config import settings
|
||
from app.database import services as db_services
|
||
from app.database.connection import database
|
||
from app.database.models import ErrorLog
|
||
from app.log.logger import get_error_log_logger
|
||
|
||
logger = get_error_log_logger()
|
||
|
||
|
||
async def delete_old_error_logs():
|
||
"""
|
||
Deletes error logs older than a specified number of days,
|
||
based on the AUTO_DELETE_ERROR_LOGS_ENABLED and AUTO_DELETE_ERROR_LOGS_DAYS settings.
|
||
"""
|
||
if not settings.AUTO_DELETE_ERROR_LOGS_ENABLED:
|
||
logger.info("Auto-deletion of error logs is disabled. Skipping.")
|
||
return
|
||
|
||
days_to_keep = settings.AUTO_DELETE_ERROR_LOGS_DAYS
|
||
if not isinstance(days_to_keep, int) or days_to_keep <= 0:
|
||
logger.error(
|
||
f"Invalid AUTO_DELETE_ERROR_LOGS_DAYS value: {days_to_keep}. Must be a positive integer. Skipping deletion."
|
||
)
|
||
return
|
||
|
||
cutoff_date = datetime.now(timezone.utc) - timedelta(days=days_to_keep)
|
||
|
||
logger.info(
|
||
f"Attempting to delete error logs older than {days_to_keep} days (before {cutoff_date.strftime('%Y-%m-%d %H:%M:%S %Z')})."
|
||
)
|
||
|
||
try:
|
||
if not database.is_connected:
|
||
await database.connect()
|
||
logger.info("Database connection established for deleting error logs.")
|
||
|
||
# First, count how many logs will be deleted (optional, for logging)
|
||
count_query = select(func.count(ErrorLog.id)).where(
|
||
ErrorLog.request_time < cutoff_date
|
||
)
|
||
num_logs_to_delete = await database.fetch_val(count_query)
|
||
|
||
if num_logs_to_delete == 0:
|
||
logger.info(
|
||
"No error logs found older than the specified period. No deletion needed."
|
||
)
|
||
return
|
||
|
||
logger.info(f"Found {num_logs_to_delete} error logs to delete.")
|
||
|
||
# Perform the deletion
|
||
query = delete(ErrorLog).where(ErrorLog.request_time < cutoff_date)
|
||
await database.execute(query)
|
||
logger.info(
|
||
f"Successfully deleted {num_logs_to_delete} error logs older than {days_to_keep} days."
|
||
)
|
||
|
||
except Exception as e:
|
||
logger.error(
|
||
f"Error during automatic deletion of error logs: {e}", exc_info=True
|
||
)
|
||
|
||
|
||
async def process_get_error_logs(
|
||
limit: int,
|
||
offset: int,
|
||
key_search: Optional[str],
|
||
error_search: Optional[str],
|
||
error_code_search: Optional[str],
|
||
start_date: Optional[datetime],
|
||
end_date: Optional[datetime],
|
||
sort_by: str,
|
||
sort_order: str,
|
||
) -> Dict[str, Any]:
|
||
"""
|
||
处理错误日志的检索,支持分页和过滤。
|
||
"""
|
||
try:
|
||
logs_data = await db_services.get_error_logs(
|
||
limit=limit,
|
||
offset=offset,
|
||
key_search=key_search,
|
||
error_search=error_search,
|
||
error_code_search=error_code_search,
|
||
start_date=start_date,
|
||
end_date=end_date,
|
||
sort_by=sort_by,
|
||
sort_order=sort_order,
|
||
)
|
||
total_count = await db_services.get_error_logs_count(
|
||
key_search=key_search,
|
||
error_search=error_search,
|
||
error_code_search=error_code_search,
|
||
start_date=start_date,
|
||
end_date=end_date,
|
||
)
|
||
return {"logs": logs_data, "total": total_count}
|
||
except Exception as e:
|
||
logger.error(f"Service error in process_get_error_logs: {e}", exc_info=True)
|
||
raise
|
||
|
||
|
||
async def process_get_error_log_details(log_id: int) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
处理特定错误日志详细信息的检索。
|
||
如果未找到,则返回 None。
|
||
"""
|
||
try:
|
||
log_details = await db_services.get_error_log_details(log_id=log_id)
|
||
return log_details
|
||
except Exception as e:
|
||
logger.error(
|
||
f"Service error in process_get_error_log_details for ID {log_id}: {e}",
|
||
exc_info=True,
|
||
)
|
||
raise
|
||
|
||
|
||
async def process_delete_error_logs_by_ids(log_ids: List[int]) -> int:
|
||
"""
|
||
按 ID 批量删除错误日志。
|
||
返回尝试删除的日志数量。
|
||
"""
|
||
if not log_ids:
|
||
return 0
|
||
try:
|
||
deleted_count = await db_services.delete_error_logs_by_ids(log_ids)
|
||
return deleted_count
|
||
except Exception as e:
|
||
logger.error(
|
||
f"Service error in process_delete_error_logs_by_ids for IDs {log_ids}: {e}",
|
||
exc_info=True,
|
||
)
|
||
raise
|
||
|
||
|
||
async def process_delete_error_log_by_id(log_id: int) -> bool:
|
||
"""
|
||
按 ID 删除单个错误日志。
|
||
如果删除成功(或找到日志并尝试删除),则返回 True,否则返回 False。
|
||
"""
|
||
try:
|
||
success = await db_services.delete_error_log_by_id(log_id)
|
||
return success
|
||
except Exception as e:
|
||
logger.error(
|
||
f"Service error in process_delete_error_log_by_id for ID {log_id}: {e}",
|
||
exc_info=True,
|
||
)
|
||
raise
|
||
|
||
|
||
async def process_delete_all_error_logs() -> int:
|
||
"""
|
||
处理删除所有错误日志的请求。
|
||
返回删除的日志数量。
|
||
"""
|
||
try:
|
||
if not database.is_connected:
|
||
await database.connect()
|
||
logger.info("Database connection established for deleting all error logs.")
|
||
|
||
deleted_count = await db_services.delete_all_error_logs()
|
||
logger.info(
|
||
f"Successfully processed request to delete all error logs. Count: {deleted_count}"
|
||
)
|
||
return deleted_count
|
||
except Exception as e:
|
||
logger.error(
|
||
f"Service error in process_delete_all_error_logs: {e}",
|
||
exc_info=True,
|
||
)
|
||
raise
|