Refactor chat backend integration and introduce new backend-neutral architecture
- Replaced direct FastGPT client usage with a backend-neutral chat interface, allowing for improved flexibility and maintainability. - Introduced a new `ChatBackend` protocol and implemented `FastGPTBackend` to handle chat operations. - Updated the chat endpoint to utilize the new backend structure, enhancing the handling of chat requests and responses. - Added comprehensive tests to ensure compatibility and functionality of the new backend integration.
This commit is contained in:
72
src/backends/chat.py
Normal file
72
src/backends/chat.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""Backend-neutral chat contract."""
|
||||
|
||||
from collections.abc import AsyncIterator
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ChatInput:
|
||||
"""Input shared by all chat backend implementations."""
|
||||
|
||||
session_id: str
|
||||
text: str
|
||||
need_form_update: bool = False
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TextDelta:
|
||||
"""A piece of raw model text.
|
||||
|
||||
The text may contain a partial ``<state>...</state>`` prefix. Parsing that
|
||||
public protocol remains the responsibility of the FastAPI layer.
|
||||
"""
|
||||
|
||||
text: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FormUpdate:
|
||||
"""A structured form update produced alongside model text."""
|
||||
|
||||
data: Any
|
||||
|
||||
|
||||
ChatStreamEvent = TextDelta | FormUpdate
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ChatResult:
|
||||
"""Backend-neutral result for a non-streaming chat request."""
|
||||
|
||||
content: str
|
||||
status_code: str | None = None
|
||||
form_update: Any = field(default_factory=dict)
|
||||
|
||||
|
||||
class ChatBackend(Protocol):
|
||||
"""Contract implemented by FastGPT today and LangGraph later."""
|
||||
|
||||
def stream(self, chat_input: ChatInput) -> AsyncIterator[ChatStreamEvent]:
|
||||
"""Stream raw text and structured side-channel events."""
|
||||
...
|
||||
|
||||
async def complete(self, chat_input: ChatInput) -> ChatResult:
|
||||
"""Return one complete backend-neutral chat result."""
|
||||
...
|
||||
|
||||
|
||||
class ChatBackendError(Exception):
|
||||
"""Base error raised by a chat backend adapter."""
|
||||
|
||||
|
||||
class ChatBackendAuthenticationError(ChatBackendError):
|
||||
"""The backend rejected its configured credentials."""
|
||||
|
||||
|
||||
class ChatBackendRateLimitError(ChatBackendError):
|
||||
"""The backend rejected the request because of rate limiting."""
|
||||
|
||||
|
||||
class ChatBackendAPIError(ChatBackendError):
|
||||
"""The backend API failed or returned an invalid response."""
|
||||
Reference in New Issue
Block a user