Files
my-v0-server/app/main.py
T

84 lines
3.2 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.clients.decision import close_decision_engine
from app.clients.material_mcp import (
MaterialFieldServiceError,
start_material_server,
stop_material_server,
)
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
material_server = None
try:
# 物料目录启动时载入内存,agent 规划与前端接口共用,避免重复查询数据库
await warm_material_cache(persistence.db)
# 物料字段服务给模型查询字段;启动失败只记录,需要查字段的修改执行时会报错
try:
material_server = await start_material_server()
except MaterialFieldServiceError as error:
logger.error("{},修改组件属性和新增组件将无法执行", error)
application.state.agent_service = AgentService(
build_graph(persistence.checkpointer), persistence.store
)
yield
finally:
# 共享客户端只在应用退出时关闭,追踪刷新放到线程避免阻塞事件循环
try:
await stop_material_server(material_server)
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()