Files
my-v0-server/app/main.py
T
2026-10-02 02:36:11 -07:00

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()