File size: 7,061 Bytes
c50496f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | """
Main Web Integration - Integrates all routers and modules
集合router并开启主服务
"""
import asyncio
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from config import get_server_host, get_server_port
from log import log
# Import managers and utilities
from src.credential_manager import credential_manager
# Import all routers
from src.router.antigravity.openai import router as antigravity_openai_router
from src.router.antigravity.gemini import router as antigravity_gemini_router
from src.router.antigravity.anthropic import router as antigravity_anthropic_router
from src.router.antigravity.model_list import router as antigravity_model_list_router
from src.router.geminicli.openai import router as geminicli_openai_router
from src.router.geminicli.gemini import router as geminicli_gemini_router
from src.router.geminicli.anthropic import router as geminicli_anthropic_router
from src.router.geminicli.model_list import router as geminicli_model_list_router
from src.task_manager import shutdown_all_tasks
from src.panel import router as panel_router
from src.keeplive import keepalive_service
# 全局凭证管理器
global_credential_manager = None
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
global global_credential_manager
log.info("启动 GCLI2API 主服务")
# 初始化配置缓存(优先执行)
try:
import config
await config.init_config()
log.info("配置缓存初始化成功")
except Exception as e:
log.error(f"配置缓存初始化失败: {e}")
# 初始化全局凭证管理器(通过单例工厂)
try:
# credential_manager 会在第一次调用时自动初始化
# 这里预先触发初始化以便在启动时检测错误
await credential_manager._get_or_create()
log.info("凭证管理器初始化成功")
except Exception as e:
log.error(f"凭证管理器初始化失败: {e}")
global_credential_manager = None
# OAuth回调服务器将在需要时按需启动
# 启动保活服务(未配置URL时自动跳过,零开销)
try:
await keepalive_service.start()
except Exception as e:
log.error(f"保活服务启动失败: {e}")
yield
# 清理资源
log.info("开始关闭 GCLI2API 主服务")
# 停止保活服务
try:
await keepalive_service.stop()
except Exception as e:
log.error(f"关闭保活服务时出错: {e}")
# 首先关闭所有异步任务
try:
await shutdown_all_tasks(timeout=10.0)
log.info("所有异步任务已关闭")
except Exception as e:
log.error(f"关闭异步任务时出错: {e}")
# 然后关闭凭证管理器
if global_credential_manager:
try:
await global_credential_manager.close()
log.info("凭证管理器已关闭")
except Exception as e:
log.error(f"关闭凭证管理器时出错: {e}")
log.info("GCLI2API 主服务已停止")
# 创建FastAPI应用
app = FastAPI(
title="GCLI2API",
description="Gemini API proxy with OpenAI compatibility",
version="2.0.0",
lifespan=lifespan,
)
# CORS中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 挂载路由器
# OpenAI兼容路由 - 处理OpenAI格式请求
app.include_router(geminicli_openai_router, prefix="", tags=["Geminicli OpenAI API"])
# Gemini原生路由 - 处理Gemini格式请求
app.include_router(geminicli_gemini_router, prefix="", tags=["Geminicli Gemini API"])
# Geminicli模型列表路由 - 处理Gemini格式的模型列表请求
app.include_router(geminicli_model_list_router, prefix="", tags=["Geminicli Model List"])
# Antigravity路由 - 处理OpenAI格式请求并转换为Antigravity API
app.include_router(antigravity_openai_router, prefix="", tags=["Antigravity OpenAI API"])
# Antigravity路由 - 处理Gemini格式请求并转换为Antigravity API
app.include_router(antigravity_gemini_router, prefix="", tags=["Antigravity Gemini API"])
# Antigravity模型列表路由 - 处理Gemini格式的模型列表请求
app.include_router(antigravity_model_list_router, prefix="", tags=["Antigravity Model List"])
# Antigravity Anthropic Messages 路由 - Anthropic Messages 格式兼容
app.include_router(antigravity_anthropic_router, prefix="", tags=["Antigravity Anthropic Messages"])
# Geminicli Anthropic Messages 路由 - Anthropic Messages 格式兼容 (Geminicli)
app.include_router(geminicli_anthropic_router, prefix="", tags=["Geminicli Anthropic Messages"])
# Panel路由 - 包含认证、凭证管理和控制面板功能
app.include_router(panel_router, prefix="", tags=["Panel Interface"])
# 静态文件路由 - 服务docs目录下的文件
app.mount("/docs", StaticFiles(directory="docs"), name="docs")
# 静态文件路由 - 服务front目录下的文件(HTML、JS、CSS等)
app.mount("/front", StaticFiles(directory="front"), name="front")
# 保活接口(仅响应 HEAD)
@app.head("/keepalive")
async def keepalive() -> Response:
return Response(status_code=200)
def main():
"""主启动函数"""
from hypercorn.asyncio import serve
from hypercorn.config import Config
from hypercorn.run import run
workers = int(os.environ.get("WORKERS", 1))
async def _run():
port = await get_server_port()
host = await get_server_host()
log.info("=" * 60)
log.info("启动 GCLI2API")
log.info("=" * 60)
log.info(f"控制面板: http://127.0.0.1:{port}")
if workers > 1:
log.info(f"Worker 数量: {workers}")
log.info("=" * 60)
config = Config()
config.bind = [f"{host}:{port}"]
config.accesslog = "-"
config.errorlog = "-"
config.loglevel = "INFO"
# 设置连接超时
config.keep_alive_timeout = 900
config.read_timeout = 900
await serve(app, config)
if workers == 1:
asyncio.run(_run())
else:
# 多 worker 模式下 hypercorn run 自行管理进程,先同步获取配置
port = int(os.environ.get("PORT", 7861))
host = os.environ.get("HOST", "0.0.0.0")
log.info("=" * 60)
log.info("启动 GCLI2API")
log.info("=" * 60)
log.info(f"控制面板: http://127.0.0.1:{port}")
log.info(f"Worker 数量: {workers}")
log.info("=" * 60)
config = Config()
config.bind = [f"{host}:{port}"]
config.accesslog = "-"
config.errorlog = "-"
config.loglevel = "INFO"
config.workers = workers
config.application_path = "web:app"
config.keep_alive_timeout = 900
config.read_timeout = 900
run(config)
if __name__ == "__main__":
main()
|