- Added a new visitor chat API endpoint (`/api/chat/visitor`) to allow unauthenticated users to engage in conversations without requiring customer data. - Introduced a visitor context dependency to manage visitor interactions seamlessly. - Enhanced the chat API to support explicit session termination and improved response handling for customer service interactions. - Updated the database configuration to include Redis client support for caching visitor data. - Added a new customer note repository to persist user notes independently of the L1 profile slots. This update significantly improves the customer service experience by enabling visitor interactions and ensuring efficient data handling for both registered and unregistered users.
101 lines
2.6 KiB
Python
101 lines
2.6 KiB
Python
"""Pydantic 请求/响应模型、AuthContext 等。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
AgentType = Literal["customer", "advisor", "analyst", "risk", "visitor"]
|
|
TokenType = Literal["customer", "staff", "service", "visitor"]
|
|
IntentType = Literal[
|
|
"product_consult",
|
|
"policy_interpret",
|
|
"faq",
|
|
"chit_chat",
|
|
"save_note",
|
|
"reject",
|
|
"transfer_human",
|
|
"fallback",
|
|
"holding_query",
|
|
"transaction_query",
|
|
"risk_assessment_query",
|
|
"suitability_check",
|
|
]
|
|
|
|
|
|
class AuthContext(BaseModel):
|
|
"""网关校验后注入业务层的身份上下文。"""
|
|
|
|
sub: str
|
|
token_type: TokenType
|
|
roles: list[str]
|
|
permissions: list[str] = Field(default_factory=list)
|
|
tenant_id: str = "default"
|
|
trace_id: str
|
|
agent_type: AgentType
|
|
jti: str
|
|
customer_id: str | None = None
|
|
|
|
def has_role(self, role: str) -> bool:
|
|
return role in self.roles
|
|
|
|
def has_perm(self, perm: str) -> bool:
|
|
if perm in self.permissions:
|
|
return True
|
|
prefix = perm.split(":")[0]
|
|
return any(p.startswith(f"{prefix}:") and p.endswith(":*") for p in self.permissions)
|
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
actor_id: str = Field(..., description="customer_id 或 staff_id")
|
|
token_type: TokenType = "staff"
|
|
roles: list[str] | None = Field(default=None, description="开发期可覆盖角色,默认按 actor_id 推断")
|
|
|
|
|
|
class LoginResponseData(BaseModel):
|
|
access_token: str
|
|
token_type: str = "Bearer"
|
|
expires_in: int
|
|
sub: str
|
|
roles: list[str]
|
|
|
|
|
|
class ChatRequest(BaseModel):
|
|
message: str = Field(..., min_length=1, max_length=8000)
|
|
session_id: str | None = None
|
|
customer_id: str | None = Field(default=None, description="员工 Agent 查询目标客户时使用")
|
|
|
|
|
|
class ChatResponseData(BaseModel):
|
|
session_id: str
|
|
reply: str
|
|
agent_type: AgentType
|
|
has_disclaimer: bool = False
|
|
intent: IntentType | None = Field(default=None, description="仅 customer 返回")
|
|
transfer_to_human: bool = Field(default=False, description="仅 customer 返回")
|
|
|
|
|
|
class ApiResponse(BaseModel):
|
|
code: int = 0
|
|
message: str = "ok"
|
|
data: Any = None
|
|
trace_id: str
|
|
|
|
|
|
class VisitorChatRequest(BaseModel):
|
|
"""游客对话请求(免认证)。"""
|
|
|
|
message: str = Field(..., min_length=1, max_length=8000)
|
|
session_id: str | None = None
|
|
|
|
|
|
class VisitorChatResponseData(BaseModel):
|
|
"""游客对话响应。"""
|
|
|
|
session_id: str
|
|
reply: str
|
|
intent: IntentType
|
|
has_disclaimer: bool = False
|
|
transfer_to_human: bool = False
|