mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-06-08 09:09:36 +08:00
feat(vertex): 集成 Vertex AI Express API 支持
本次更新引入了对 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 服务范围,为用户提供了更多模型选择。
This commit is contained in:
@@ -45,11 +45,8 @@ Base = declarative_base(metadata=metadata)
|
||||
if settings.DATABASE_TYPE == "sqlite":
|
||||
database = Database(DATABASE_URL)
|
||||
else:
|
||||
database = Database(DATABASE_URL, min_size=5, max_size=20, pool_recycle=1800) # Reduced recycle time to 30 mins
|
||||
database = Database(DATABASE_URL, min_size=5, max_size=20, pool_recycle=1800)
|
||||
|
||||
# 移除了 SessionLocal 和 get_db 函数
|
||||
|
||||
# --- Async connection functions for lifespan/async routes ---
|
||||
async def connect_to_db():
|
||||
"""
|
||||
连接到数据库
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
数据库模型模块
|
||||
"""
|
||||
import datetime
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, JSON, Boolean # 添加 Boolean
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, JSON, Boolean
|
||||
|
||||
from app.database.connection import Base
|
||||
|
||||
@@ -53,7 +53,7 @@ class RequestLog(Base):
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
request_time = Column(DateTime, default=datetime.datetime.now, comment="请求时间")
|
||||
model_name = Column(String(100), nullable=True, comment="模型名称")
|
||||
api_key = Column(String(100), nullable=True, comment="使用的API密钥") # 考虑安全性,后续可优化
|
||||
api_key = Column(String(100), nullable=True, comment="使用的API密钥")
|
||||
is_success = Column(Boolean, nullable=False, comment="请求是否成功")
|
||||
status_code = Column(Integer, nullable=True, comment="API响应状态码")
|
||||
latency_ms = Column(Integer, nullable=True, comment="请求耗时(毫秒)")
|
||||
|
||||
@@ -189,7 +189,6 @@ async def get_error_logs(
|
||||
ErrorLog.request_time
|
||||
)
|
||||
|
||||
# Apply filters
|
||||
if key_search:
|
||||
query = query.where(ErrorLog.gemini_key.ilike(f"%{key_search}%"))
|
||||
if error_search:
|
||||
@@ -219,14 +218,14 @@ async def get_error_logs(
|
||||
result = await database.fetch_all(query)
|
||||
return [dict(row) for row in result]
|
||||
except Exception as e:
|
||||
logger.exception(f"Failed to get error logs with filters: {str(e)}") # Use exception for stack trace
|
||||
logger.exception(f"Failed to get error logs with filters: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
async def get_error_logs_count(
|
||||
key_search: Optional[str] = None,
|
||||
error_search: Optional[str] = None,
|
||||
error_code_search: Optional[str] = None, # Added error code search
|
||||
error_code_search: Optional[str] = None,
|
||||
start_date: Optional[datetime] = None,
|
||||
end_date: Optional[datetime] = None
|
||||
) -> int:
|
||||
@@ -294,7 +293,7 @@ async def get_error_log_details(log_id: int) -> Optional[Dict[str, Any]]:
|
||||
try:
|
||||
log_dict['request_msg'] = json.dumps(log_dict['request_msg'], ensure_ascii=False, indent=2)
|
||||
except TypeError:
|
||||
log_dict['request_msg'] = str(log_dict['request_msg']) # Fallback to string
|
||||
log_dict['request_msg'] = str(log_dict['request_msg'])
|
||||
return log_dict
|
||||
else:
|
||||
return None
|
||||
@@ -372,7 +371,6 @@ async def delete_all_error_logs() -> int:
|
||||
try:
|
||||
# 1. 获取删除前的总数
|
||||
count_query = select(func.count()).select_from(ErrorLog)
|
||||
# fetch_val() is suitable here as we expect a single scalar value
|
||||
total_to_delete = await database.fetch_val(count_query)
|
||||
|
||||
if total_to_delete == 0:
|
||||
@@ -380,7 +378,6 @@ async def delete_all_error_logs() -> int:
|
||||
return 0
|
||||
|
||||
# 2. 执行删除操作
|
||||
# This creates a query like "DELETE FROM error_log"
|
||||
delete_query = delete(ErrorLog)
|
||||
await database.execute(delete_query)
|
||||
|
||||
@@ -388,7 +385,6 @@ async def delete_all_error_logs() -> int:
|
||||
return total_to_delete
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to delete all error logs: {str(e)}", exc_info=True)
|
||||
# Re-raise the exception so it can be caught by the service layer or route handler
|
||||
raise
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user