2026-10-24 13:41:54 +08:00
|
|
|
"""后端与单一会话存储的生命周期、依赖注入。"""
|
|
|
|
|
from contextlib import AsyncExitStack, asynccontextmanager
|
|
|
|
|
|
2026-01-08 16:22:25 +08:00
|
|
|
from fastapi import FastAPI
|
|
|
|
|
from fastgpt_client import AsyncChatClient
|
2026-10-24 13:41:54 +08:00
|
|
|
|
2026-10-19 14:29:31 +08:00
|
|
|
from ..agent.graph import build_graph
|
2026-07-26 07:25:24 +08:00
|
|
|
from ..backends.chat import ChatBackend
|
|
|
|
|
from ..backends.fastgpt import FastGPTBackend
|
2026-10-19 14:29:31 +08:00
|
|
|
from ..backends.langgraph import LangGraphBackend
|
2026-10-22 20:50:10 +08:00
|
|
|
from ..services.app_service import AccidentAppService
|
2026-10-24 13:41:54 +08:00
|
|
|
from ..storage.checkpoints import delete_checkpoint
|
2026-01-08 16:22:25 +08:00
|
|
|
from .config import Config
|
|
|
|
|
|
|
|
|
|
_fastgpt_client: AsyncChatClient | None = None
|
2026-07-26 07:25:24 +08:00
|
|
|
_chat_backend: ChatBackend | None = None
|
2026-10-20 14:53:46 +08:00
|
|
|
_langgraph_graph = None
|
2026-10-22 20:50:10 +08:00
|
|
|
_app_service: AccidentAppService | None = None
|
2026-01-08 16:22:25 +08:00
|
|
|
|
2026-10-22 22:31:28 +08:00
|
|
|
FASTGPT_TIMEOUT_SECONDS = 60.0
|
|
|
|
|
FASTGPT_MAX_RETRIES = 3
|
|
|
|
|
|
2026-01-08 16:22:25 +08:00
|
|
|
|
|
|
|
|
@asynccontextmanager
|
|
|
|
|
async def lifespan(app: FastAPI):
|
2026-10-24 13:41:54 +08:00
|
|
|
global _chat_backend, _fastgpt_client, _langgraph_graph, _app_service
|
2026-01-08 16:22:25 +08:00
|
|
|
Config.validate()
|
2026-10-23 15:54:51 +08:00
|
|
|
llm = None
|
2026-10-24 13:41:54 +08:00
|
|
|
async with AsyncExitStack() as resources:
|
|
|
|
|
try:
|
|
|
|
|
if Config.AGENT_BACKEND == 'langgraph':
|
|
|
|
|
from ..agent.llm import build_llm_service
|
|
|
|
|
from ..storage.runtime import StorageSettings, open_storage
|
2026-07-28 08:41:34 +08:00
|
|
|
|
2026-10-24 13:41:54 +08:00
|
|
|
storage = await resources.enter_async_context(open_storage(StorageSettings.from_config(Config)))
|
|
|
|
|
_langgraph_graph = build_graph(storage.checkpointer)
|
|
|
|
|
llm = build_llm_service()
|
|
|
|
|
_chat_backend = LangGraphBackend(_langgraph_graph, llm=llm)
|
|
|
|
|
_app_service = AccidentAppService(_chat_backend, storage.repository, locks=storage.locks)
|
|
|
|
|
else:
|
|
|
|
|
_fastgpt_client = AsyncChatClient(
|
|
|
|
|
api_key=Config.FASTGPT_API_KEY, base_url=Config.FASTGPT_BASE_URL,
|
|
|
|
|
timeout=FASTGPT_TIMEOUT_SECONDS, max_retries=FASTGPT_MAX_RETRIES + 1,
|
|
|
|
|
retry_delay=1.0, enable_logging=Config.DEBUG,
|
|
|
|
|
)
|
|
|
|
|
await _fastgpt_client.__aenter__()
|
|
|
|
|
_chat_backend = FastGPTBackend(_fastgpt_client)
|
|
|
|
|
yield
|
|
|
|
|
finally:
|
|
|
|
|
_chat_backend = None
|
|
|
|
|
_langgraph_graph = None
|
|
|
|
|
_app_service = None
|
|
|
|
|
if llm is not None and hasattr(llm, 'aclose'):
|
|
|
|
|
await llm.aclose()
|
|
|
|
|
if _fastgpt_client:
|
|
|
|
|
await _fastgpt_client.__aexit__(None, None, None)
|
|
|
|
|
_fastgpt_client = None
|
2026-01-08 16:22:25 +08:00
|
|
|
|
|
|
|
|
|
2026-10-20 14:53:46 +08:00
|
|
|
async def delete_chat_session(thread_id: str) -> None:
|
2026-10-24 13:41:54 +08:00
|
|
|
await delete_checkpoint(_langgraph_graph, thread_id)
|
2026-10-20 14:53:46 +08:00
|
|
|
|
|
|
|
|
|
2026-01-08 16:22:25 +08:00
|
|
|
def get_fastgpt_client() -> AsyncChatClient:
|
|
|
|
|
if _fastgpt_client is None:
|
2026-10-24 13:41:54 +08:00
|
|
|
raise RuntimeError('FastGPT client not initialized')
|
2026-01-08 16:22:25 +08:00
|
|
|
return _fastgpt_client
|
2026-07-26 07:25:24 +08:00
|
|
|
|
|
|
|
|
|
2026-10-22 20:50:10 +08:00
|
|
|
def get_app_service() -> AccidentAppService:
|
|
|
|
|
if _app_service is None:
|
2026-10-24 13:41:54 +08:00
|
|
|
raise RuntimeError('Application service not initialized')
|
2026-10-22 20:50:10 +08:00
|
|
|
return _app_service
|
|
|
|
|
|
|
|
|
|
|
2026-07-26 07:25:24 +08:00
|
|
|
def get_chat_backend() -> ChatBackend:
|
|
|
|
|
if _chat_backend is None:
|
2026-10-24 13:41:54 +08:00
|
|
|
raise RuntimeError('Chat backend not initialized')
|
2026-07-26 07:25:24 +08:00
|
|
|
return _chat_backend
|