| | |
| | |
| |
|
| | import os |
| | import sys |
| | import psutil |
| | from contextlib import asynccontextmanager |
| | from fastapi import FastAPI, Response |
| | from fastapi.middleware.cors import CORSMiddleware |
| | from fastapi.staticfiles import StaticFiles |
| |
|
| | from app.core.config import settings |
| | from app.core import openai |
| | from app.utils.reload_config import RELOAD_CONFIG |
| | from app.utils.logger import setup_logger |
| | from app.providers import initialize_providers |
| |
|
| | from app.admin import routes as admin_routes |
| | from app.admin import api as admin_api |
| |
|
| | from granian import Granian |
| |
|
| |
|
| | |
| | logger = setup_logger(log_dir="logs", debug_mode=settings.DEBUG_LOGGING) |
| |
|
| |
|
| | @asynccontextmanager |
| | async def lifespan(app: FastAPI): |
| | |
| | from app.services.token_dao import init_token_database |
| | await init_token_database() |
| |
|
| | |
| | initialize_providers() |
| |
|
| | |
| | from app.utils.token_pool import initialize_token_pool_from_db |
| | token_pool = await initialize_token_pool_from_db( |
| | provider="zai", |
| | failure_threshold=settings.TOKEN_FAILURE_THRESHOLD, |
| | recovery_timeout=settings.TOKEN_RECOVERY_TIMEOUT |
| | ) |
| |
|
| | if not token_pool and not settings.ANONYMOUS_MODE: |
| | logger.warning("⚠️ 未找到可用 Token 且未启用匿名模式,服务可能无法正常工作") |
| |
|
| | yield |
| |
|
| | logger.info("🔄 应用正在关闭...") |
| |
|
| |
|
| | |
| | |
| | app = FastAPI(lifespan=lifespan, root_path=settings.ROOT_PATH) |
| |
|
| | |
| | app.add_middleware( |
| | CORSMiddleware, |
| | allow_origins=["*"], |
| | allow_credentials=True, |
| | allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], |
| | allow_headers=["Content-Type", "Authorization"], |
| | ) |
| |
|
| | |
| | try: |
| | app.mount("/static", StaticFiles(directory="app/static"), name="static") |
| | except RuntimeError: |
| | |
| | os.makedirs("app/static/css", exist_ok=True) |
| | os.makedirs("app/static/js", exist_ok=True) |
| | app.mount("/static", StaticFiles(directory="app/static"), name="static") |
| |
|
| | |
| | app.include_router(openai.router) |
| |
|
| | |
| | app.include_router(admin_routes.router) |
| | app.include_router(admin_api.router) |
| |
|
| |
|
| | @app.options("/") |
| | async def handle_options(): |
| | """Handle OPTIONS requests""" |
| | return Response(status_code=200) |
| |
|
| |
|
| | @app.get("/") |
| | async def root(): |
| | """Root endpoint""" |
| | return {"message": "OpenAI Compatible API Server"} |
| |
|
| |
|
| | def run_server(): |
| | service_name = settings.SERVICE_NAME |
| |
|
| | logger.info(f"🚀 启动 {service_name} 服务...") |
| | logger.info(f"📡 监听地址: 0.0.0.0:{settings.LISTEN_PORT}") |
| | logger.info(f"🔧 调试模式: {'开启' if settings.DEBUG_LOGGING else '关闭'}") |
| | logger.info(f"🔐 匿名模式: {'开启' if settings.ANONYMOUS_MODE else '关闭'}") |
| |
|
| | try: |
| | Granian( |
| | "main:app", |
| | interface="asgi", |
| | address="0.0.0.0", |
| | port=settings.LISTEN_PORT, |
| | reload=False, |
| | process_name=service_name, |
| | **RELOAD_CONFIG, |
| | ).serve() |
| | except KeyboardInterrupt: |
| | logger.info("🛑 收到中断信号,正在关闭服务...") |
| | except Exception as e: |
| | logger.error(f"❌ 服务启动失败: {e}") |
| | sys.exit(1) |
| |
|
| |
|
| | if __name__ == "__main__": |
| | run_server() |
| |
|