mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-02 22:17:52 +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 服务范围,为用户提供了更多模型选择。
154 lines
4.7 KiB
Python
154 lines
4.7 KiB
Python
from contextlib import asynccontextmanager
|
|
from pathlib import Path
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.staticfiles import StaticFiles
|
|
from fastapi.templating import Jinja2Templates
|
|
|
|
from app.config.config import settings, sync_initial_settings
|
|
from app.database.connection import connect_to_db, disconnect_from_db
|
|
from app.database.initialization import initialize_database
|
|
from app.exception.exceptions import setup_exception_handlers
|
|
from app.log.logger import get_application_logger
|
|
from app.middleware.middleware import setup_middlewares
|
|
from app.router.routes import setup_routers
|
|
from app.scheduler.scheduled_tasks import start_scheduler, stop_scheduler
|
|
from app.service.key.key_manager import get_key_manager_instance
|
|
from app.service.update.update_service import check_for_updates
|
|
from app.utils.helpers import get_current_version
|
|
|
|
logger = get_application_logger()
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
|
STATIC_DIR = PROJECT_ROOT / "app" / "static"
|
|
TEMPLATES_DIR = PROJECT_ROOT / "app" / "templates"
|
|
|
|
# 初始化模板引擎,并添加全局变量
|
|
templates = Jinja2Templates(directory="app/templates")
|
|
|
|
|
|
# 定义一个函数来更新模板全局变量
|
|
def update_template_globals(app: FastAPI, update_info: dict):
|
|
# Jinja2Templates 实例没有直接更新全局变量的方法
|
|
# 我们需要在请求上下文中传递这些变量,或者修改 Jinja 环境
|
|
# 更简单的方法是将其存储在 app.state 中,并在渲染时传递
|
|
app.state.update_info = update_info
|
|
logger.info(f"Update info stored in app.state: {update_info}")
|
|
|
|
|
|
# --- Helper functions for lifespan ---
|
|
async def _setup_database_and_config(app_settings):
|
|
"""Initializes database, syncs settings, and initializes KeyManager."""
|
|
initialize_database()
|
|
logger.info("Database initialized successfully")
|
|
await connect_to_db()
|
|
await sync_initial_settings()
|
|
await get_key_manager_instance(app_settings.API_KEYS, app_settings.VERTEX_API_KEYS)
|
|
logger.info("Database, config sync, and KeyManager initialized successfully")
|
|
|
|
|
|
async def _shutdown_database():
|
|
"""Disconnects from the database."""
|
|
await disconnect_from_db()
|
|
|
|
|
|
def _start_scheduler():
|
|
"""Starts the background scheduler."""
|
|
try:
|
|
start_scheduler()
|
|
logger.info("Scheduler started successfully.")
|
|
except Exception as e:
|
|
logger.error(f"Failed to start scheduler: {e}")
|
|
|
|
|
|
def _stop_scheduler():
|
|
"""Stops the background scheduler."""
|
|
stop_scheduler()
|
|
|
|
|
|
async def _perform_update_check(app: FastAPI):
|
|
"""Checks for updates and stores the info in app.state."""
|
|
update_available, latest_version, error_message = await check_for_updates()
|
|
current_version = get_current_version()
|
|
update_info = {
|
|
"update_available": update_available,
|
|
"latest_version": latest_version,
|
|
"error_message": error_message,
|
|
"current_version": current_version,
|
|
}
|
|
if not hasattr(app, "state"):
|
|
from starlette.datastructures import State
|
|
|
|
app.state = State()
|
|
app.state.update_info = update_info
|
|
logger.info(f"Update check completed. Info: {update_info}")
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""
|
|
Manages the application startup and shutdown events.
|
|
|
|
Args:
|
|
app: FastAPI应用实例
|
|
"""
|
|
logger.info("Application starting up...")
|
|
try:
|
|
await _setup_database_and_config(settings)
|
|
await _perform_update_check(app)
|
|
_start_scheduler()
|
|
|
|
except Exception as e:
|
|
logger.critical(
|
|
f"Critical error during application startup: {str(e)}", exc_info=True
|
|
)
|
|
|
|
yield
|
|
|
|
logger.info("Application shutting down...")
|
|
_stop_scheduler()
|
|
await _shutdown_database()
|
|
|
|
|
|
def create_app() -> FastAPI:
|
|
"""
|
|
创建并配置FastAPI应用程序实例
|
|
|
|
Returns:
|
|
FastAPI: 配置好的FastAPI应用程序实例
|
|
"""
|
|
|
|
# 创建FastAPI应用
|
|
current_version = get_current_version()
|
|
app = FastAPI(
|
|
title="Gemini Balance API",
|
|
description="Gemini API代理服务,支持负载均衡和密钥管理",
|
|
version=current_version,
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
if not hasattr(app, "state"):
|
|
from starlette.datastructures import State
|
|
|
|
app.state = State()
|
|
app.state.update_info = {
|
|
"update_available": False,
|
|
"latest_version": None,
|
|
"error_message": "Initializing...",
|
|
"current_version": current_version,
|
|
}
|
|
|
|
# 配置静态文件
|
|
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
|
|
|
|
# 配置中间件
|
|
setup_middlewares(app)
|
|
|
|
# 配置异常处理器
|
|
setup_exception_handlers(app)
|
|
|
|
# 配置路由
|
|
setup_routers(app)
|
|
|
|
return app
|