新增全渠道网关的 API 路由层和网关端点。 主要变更: - channel_router.py: 渠道管理 API 路由(CRUD、配置、绑定等) - gateway_sse_router.py: SSE 网关端点 - gateway_ws_router.py: WebSocket 网关端点 - webhook_router.py: Webhook 回调路由 - auth_router.py: 认证路由更新 - routers/__init__.py: 路由注册更新 - main.py: 主入口更新 - lifespan.py: 应用生命周期更新,渠道扩展加载与卸载
135 lines
5.1 KiB
Python
135 lines
5.1 KiB
Python
import os
|
||
from contextlib import asynccontextmanager
|
||
|
||
from fastapi import FastAPI
|
||
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
||
|
||
from yuxi.services.task_service import tasker
|
||
from yuxi.services.mcp_service import ensure_builtin_mcp_servers_in_db
|
||
from yuxi.services.model_provider_service import ensure_builtin_model_providers_in_db
|
||
from yuxi.services.subagent_service import init_builtin_subagents
|
||
from yuxi.services.run_queue_service import close_queue_clients, get_redis_client
|
||
from yuxi.storage.postgres.manager import pg_manager
|
||
from yuxi.knowledge import knowledge_base
|
||
from yuxi.utils import logger
|
||
from yuxi.agents.backends.sandbox import init_sandbox_provider, shutdown_sandbox_provider
|
||
from yuxi import get_version
|
||
|
||
|
||
@asynccontextmanager
|
||
async def lifespan(app: FastAPI):
|
||
"""FastAPI lifespan事件管理器"""
|
||
# 初始化数据库连接
|
||
try:
|
||
pg_manager.initialize()
|
||
await pg_manager.create_business_tables()
|
||
await pg_manager.ensure_business_schema()
|
||
await pg_manager.ensure_knowledge_schema()
|
||
except Exception as e:
|
||
logger.error(f"Failed to initialize database during startup: {e}")
|
||
|
||
# 确保内置 MCP 服务器定义存在于数据库
|
||
try:
|
||
await ensure_builtin_mcp_servers_in_db()
|
||
except Exception as e:
|
||
logger.error(f"Failed to ensure builtin MCP servers during startup: {e}")
|
||
|
||
# 初始化内置模型供应商配置
|
||
try:
|
||
async with pg_manager.get_async_session_context() as session:
|
||
await ensure_builtin_model_providers_in_db(session)
|
||
except Exception as e:
|
||
logger.error(f"Failed to ensure builtin model providers during startup: {e}")
|
||
|
||
# 初始化模型缓存(v2 模型选择使用)
|
||
try:
|
||
from yuxi.services.model_cache import model_cache
|
||
from yuxi.services.model_provider_service import get_all_model_providers
|
||
|
||
async with pg_manager.get_async_session_context() as session:
|
||
providers = await get_all_model_providers(session)
|
||
model_cache.rebuild(providers)
|
||
except Exception as e:
|
||
logger.error(f"Failed to initialize model cache during startup: {e}")
|
||
|
||
# 初始化内置 SubAgent
|
||
try:
|
||
await init_builtin_subagents()
|
||
except Exception as e:
|
||
logger.error(f"Failed to initialize builtin subagents during startup: {e}")
|
||
raise
|
||
|
||
# 初始化知识库管理器
|
||
if os.environ.get("LITE_MODE", "").lower() in ("true", "1"):
|
||
logger.info("LITE_MODE enabled, skipping knowledge base initialization")
|
||
else:
|
||
try:
|
||
await knowledge_base.initialize()
|
||
except Exception as e:
|
||
logger.error(f"Failed to initialize knowledge base manager: {e}")
|
||
|
||
# 预热 Redis(run 队列)
|
||
try:
|
||
redis = await get_redis_client()
|
||
await redis.ping()
|
||
except Exception as e:
|
||
logger.warning(f"Run queue redis unavailable on startup: {e}")
|
||
|
||
try:
|
||
init_sandbox_provider()
|
||
except Exception as e:
|
||
logger.error(f"Failed to initialize sandbox provider during startup: {e}")
|
||
|
||
try:
|
||
from yuxi.channel.gateway.rpc_handlers import register_all_handlers
|
||
register_all_handlers()
|
||
logger.info("Gateway RPC handlers registered (%d methods)", 42)
|
||
except Exception as e:
|
||
logger.error(f"Failed to register gateway RPC handlers: {e}")
|
||
|
||
# =========================================================
|
||
# 2. 核心修复:在这里执行一次 setup(),建完表就拉倒
|
||
# =========================================================
|
||
checkpointer = AsyncPostgresSaver(pg_manager.langgraph_pool)
|
||
await checkpointer.setup()
|
||
print("LangGraph Checkpoint tables verified/created!")
|
||
|
||
try:
|
||
from yuxi.channel.runtime.manager import gateway
|
||
|
||
await gateway.boot()
|
||
trace = gateway.get_startup_trace()
|
||
if not trace.get("success"):
|
||
logger.error("ChannelGateway boot failed: %s", trace.get("error"))
|
||
else:
|
||
logger.info("ChannelGateway ready, %d channels, %.2fs",
|
||
len(gateway.list_channels()), trace.get("duration_seconds", 0))
|
||
except Exception as e:
|
||
logger.error("ChannelGateway boot error: %s", e)
|
||
|
||
await tasker.start()
|
||
logger.info(f"""
|
||
|
||
░██ ░██ ░██
|
||
░██ ░██
|
||
░██ ░██ ░██ ░██ ░██ ░██ ░██
|
||
░████ ░██ ░██ ░██ ░██ ░██
|
||
░██ ░██ ░██ ░█████ ░██
|
||
░██ ░██ ░███ ░██ ░██ ░██
|
||
░██ ░█████░██ ░██ ░██ ░██ v{get_version()}
|
||
|
||
""")
|
||
logger.info("Yuxi backend startup complete")
|
||
yield
|
||
await tasker.shutdown()
|
||
|
||
try:
|
||
from yuxi.channel.gateway.server import gateway_ws_server
|
||
await gateway_ws_server.shutdown()
|
||
except Exception as e:
|
||
logger.error(f"Gateway WS shutdown error: {e}")
|
||
|
||
shutdown_sandbox_provider()
|
||
await close_queue_clients()
|
||
await pg_manager.close()
|