84 lines
3.3 KiB
Python
84 lines
3.3 KiB
Python
"""FastAPI 应用入口"""
|
|
|
|
import asyncio
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import Depends, FastAPI
|
|
from loguru import logger
|
|
|
|
from app.api.agent import router
|
|
from app.api.conversations import router as conversation_router
|
|
from app.api.materials import router as material_router
|
|
from app.core.auth import get_current_user
|
|
from app.core.exceptions import register_exception_handlers
|
|
from app.core.logging import setup_logging
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(application: FastAPI):
|
|
setup_logging()
|
|
from app.agent.screen_agent import get_screen_agent
|
|
from app.clients.decision import close_decision_engine
|
|
from app.clients.mcp import start_mcp_servers, stop_mcp_servers
|
|
from app.clients.user_center import close_user_center
|
|
from app.observability.tracing import flush_tracing
|
|
from app.processor.graph import build_graph
|
|
from app.services.agent import AgentService
|
|
from app.services.material_mongo import warm_material_cache
|
|
from app.services.persistence import open_persistence
|
|
|
|
# 按配置选择 MongoDB 或进程内存,会话记录与图检查点使用同一种存储
|
|
persistence = await open_persistence()
|
|
application.state.conversation_store = persistence.store
|
|
mcp_processes = []
|
|
try:
|
|
# 物料目录启动时载入内存,动作校验与前端接口共用,避免重复查询数据库
|
|
await warm_material_cache(persistence.db)
|
|
# 拉起 mcp_servers.json 中由应用管理的服务;单个服务失败只记录,用到它的请求执行时报错
|
|
mcp_processes = await start_mcp_servers()
|
|
# 提前拉取 MCP 工具并组装 agent,问题在启动时暴露;失败只记录,首个请求会重试
|
|
try:
|
|
await get_screen_agent()
|
|
except Exception as error:
|
|
logger.opt(exception=error).error("screen agent 预先组装失败")
|
|
application.state.agent_service = AgentService(
|
|
build_graph(persistence.checkpointer), persistence.store
|
|
)
|
|
yield
|
|
finally:
|
|
# 共享客户端只在应用退出时关闭,追踪刷新放到线程避免阻塞事件循环
|
|
try:
|
|
await stop_mcp_servers(mcp_processes)
|
|
finally:
|
|
try:
|
|
await persistence.close()
|
|
finally:
|
|
try:
|
|
await close_decision_engine()
|
|
finally:
|
|
try:
|
|
await close_user_center()
|
|
finally:
|
|
try:
|
|
await asyncio.to_thread(flush_tracing)
|
|
finally:
|
|
await logger.complete()
|
|
|
|
|
|
def create_app() -> FastAPI:
|
|
application = FastAPI(title="Screen Agent API", lifespan=lifespan)
|
|
# 统一处理请求校验、HTTP 错误和未捕获异常
|
|
register_exception_handlers(application)
|
|
# 统一 /api 前缀,方便前端代理和反向代理只配置一条规则
|
|
# 会话和 agent 接口需登录,物料目录是全局公开数据
|
|
authenticated = [Depends(get_current_user)]
|
|
application.include_router(router, prefix="/api", dependencies=authenticated)
|
|
application.include_router(
|
|
conversation_router, prefix="/api", dependencies=authenticated
|
|
)
|
|
application.include_router(material_router, prefix="/api")
|
|
return application
|
|
|
|
|
|
app = create_app()
|