Add client-mode FastGPT routing

This commit is contained in:
Xin Wang
2026-07-28 08:41:34 +08:00
parent 88ba48ac77
commit 3e9385b0ca
7 changed files with 325 additions and 64 deletions
+64 -27
View File
@@ -1,39 +1,76 @@
"""FastGPT client dependency injection."""
from contextlib import asynccontextmanager
from contextlib import AsyncExitStack, asynccontextmanager
from dataclasses import dataclass
from fastapi import FastAPI
from fastgpt_client import AsyncChatClient
from .config import Config
# Global client instance
_fastgpt_client: AsyncChatClient | None = None
@dataclass(frozen=True)
class FastGPTProfile:
"""FastGPT client and app metadata for one client mode."""
client: AsyncChatClient
app_id: str
_fastgpt_profiles: dict[str, FastGPTProfile] = {}
def _profile_settings() -> dict[str, dict[str, str | None]]:
return {
"direct": {
"api_key": Config.FASTGPT_DIRECT_API_KEY,
"base_url": Config.FASTGPT_DIRECT_BASE_URL,
"app_id": Config.FASTGPT_DIRECT_APP_ID,
},
"browser_addon": {
"api_key": Config.FASTGPT_BROWSER_ADDON_API_KEY,
"base_url": Config.FASTGPT_BROWSER_ADDON_BASE_URL,
"app_id": Config.FASTGPT_BROWSER_ADDON_APP_ID,
},
}
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Manage FastGPT client lifecycle."""
global _fastgpt_client
"""Manage all mode-specific FastGPT clients."""
Config.validate()
# Initialize client
_fastgpt_client = AsyncChatClient(
api_key=Config.FASTGPT_API_KEY,
base_url=Config.FASTGPT_BASE_URL,
timeout=60.0,
max_retries=3,
retry_delay=1.0,
enable_logging=Config.DEBUG,
)
await _fastgpt_client.__aenter__()
yield
# Cleanup
if _fastgpt_client:
await _fastgpt_client.__aexit__(None, None, None)
async with AsyncExitStack() as stack:
for client_mode, settings in _profile_settings().items():
client = AsyncChatClient(
api_key=settings["api_key"],
base_url=settings["base_url"],
timeout=60.0,
max_retries=3,
retry_delay=1.0,
enable_logging=Config.DEBUG,
)
await stack.enter_async_context(client)
_fastgpt_profiles[client_mode] = FastGPTProfile(
client=client,
app_id=settings["app_id"],
)
try:
yield
finally:
_fastgpt_profiles.clear()
def get_fastgpt_client() -> AsyncChatClient:
"""Get the FastGPT client instance."""
if _fastgpt_client is None:
raise RuntimeError("FastGPT client not initialized")
return _fastgpt_client
def get_fastgpt_profile(client_mode: str) -> FastGPTProfile:
"""Get the initialized FastGPT profile for a client mode."""
try:
return _fastgpt_profiles[client_mode]
except KeyError as exc:
if client_mode not in _profile_settings():
raise ValueError(f"Unsupported clientMode: {client_mode}") from exc
raise RuntimeError(
f"FastGPT profile is not initialized for clientMode={client_mode}"
) from exc
def get_fastgpt_client(client_mode: str = "direct") -> AsyncChatClient:
"""Get a FastGPT client, defaulting to the legacy direct mode."""
return get_fastgpt_profile(client_mode).client