1. 新增多渠道配置项,支持多渠道网关管理 2. 添加用户来源字段,区分本地用户与渠道用户 3. 实现WebSocket聊天路由与Slack Webhook处理 4. 新增渠道消息记录与统计相关存储模型与仓库 5. 实现多渠道管理API与Webhook分发路由 6. 初始化渠道管理器并集成到应用生命周期 7. 添加第三方依赖包支持多渠道SDK 8. 优化鉴权逻辑,排除渠道用户的常规鉴权
204 lines
8.1 KiB
Python
204 lines
8.1 KiB
Python
"""多渠道网关 ORM 模型 - 渠道用户映射、会话映射、消息记录"""
|
|
|
|
from typing import Any
|
|
|
|
from sqlalchemy import (
|
|
BigInteger,
|
|
Column,
|
|
DateTime,
|
|
Index,
|
|
Integer,
|
|
String,
|
|
UniqueConstraint,
|
|
)
|
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
from yuxi.storage.postgres.models_business import Base
|
|
from yuxi.utils.datetime_utils import format_utc_datetime, utc_now_naive
|
|
|
|
|
|
class ChannelUserMapping(Base):
|
|
"""渠道用户映射表 - 渠道用户与内部用户的绑定关系"""
|
|
|
|
__tablename__ = "channels_user_mappings"
|
|
|
|
id = Column(BigInteger, primary_key=True, autoincrement=True)
|
|
channel_id = Column(String(32), nullable=False)
|
|
channel_user_id = Column(String(128), nullable=False)
|
|
internal_user_id = Column(String(64), nullable=False)
|
|
created_at = Column(DateTime, nullable=False, default=utc_now_naive)
|
|
updated_at = Column(DateTime, nullable=False, default=utc_now_naive, onupdate=utc_now_naive)
|
|
|
|
__table_args__ = (UniqueConstraint("channel_id", "channel_user_id", name="uq_channel_user"),)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"id": self.id,
|
|
"channel_id": self.channel_id,
|
|
"channel_user_id": self.channel_user_id,
|
|
"internal_user_id": self.internal_user_id,
|
|
"created_at": format_utc_datetime(self.created_at),
|
|
"updated_at": format_utc_datetime(self.updated_at),
|
|
}
|
|
|
|
|
|
class ChannelThreadMapping(Base):
|
|
"""渠道会话映射表 - 渠道会话与 LangGraph thread_id 的绑定关系"""
|
|
|
|
__tablename__ = "channels_thread_mappings"
|
|
|
|
id = Column(BigInteger, primary_key=True, autoincrement=True)
|
|
channel_id = Column(String(32), nullable=False)
|
|
channel_chat_id = Column(String(128), nullable=False)
|
|
internal_user_id = Column(String(64), nullable=False)
|
|
thread_id = Column(String(64), nullable=False)
|
|
agent_id = Column(String(64), nullable=True)
|
|
last_active_at = Column(DateTime, nullable=False, default=utc_now_naive)
|
|
created_at = Column(DateTime, nullable=False, default=utc_now_naive)
|
|
updated_at = Column(DateTime, nullable=False, default=utc_now_naive, onupdate=utc_now_naive)
|
|
|
|
__table_args__ = (
|
|
UniqueConstraint(
|
|
"channel_id",
|
|
"channel_chat_id",
|
|
"internal_user_id",
|
|
name="uq_channel_thread",
|
|
),
|
|
)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"id": self.id,
|
|
"channel_id": self.channel_id,
|
|
"channel_chat_id": self.channel_chat_id,
|
|
"internal_user_id": self.internal_user_id,
|
|
"thread_id": self.thread_id,
|
|
"agent_id": self.agent_id,
|
|
"last_active_at": format_utc_datetime(self.last_active_at),
|
|
"created_at": format_utc_datetime(self.created_at),
|
|
"updated_at": format_utc_datetime(self.updated_at),
|
|
}
|
|
|
|
|
|
class ChannelMsgRecord(Base):
|
|
"""消息记录表 - 渠道消息的完整处理生命周期"""
|
|
|
|
__tablename__ = "channels_msg_records"
|
|
|
|
id = Column(BigInteger, primary_key=True, autoincrement=True)
|
|
channel_id = Column(String(32), nullable=False)
|
|
channel_type = Column(String(32), nullable=False)
|
|
message_id = Column(String(128), nullable=False)
|
|
chat_id = Column(String(128), nullable=False)
|
|
chat_type = Column(String(32), nullable=False, default="direct")
|
|
content_type = Column(String(32), nullable=False, default="text")
|
|
sender_user_id = Column(String(128), nullable=False)
|
|
content_preview = Column(String(500), nullable=False)
|
|
reply_to_message_id = Column(String(128), nullable=True)
|
|
agent_config_id = Column(Integer, nullable=True)
|
|
status = Column(String(32), nullable=False, default="processing")
|
|
error_message = Column(String(500), nullable=True)
|
|
response_time_ms = Column(Integer, nullable=True)
|
|
reply_message_id = Column(String(128), nullable=True)
|
|
reply_content_preview = Column(String(500), nullable=True)
|
|
created_at = Column(DateTime, nullable=False, default=utc_now_naive)
|
|
replied_at = Column(DateTime, nullable=True)
|
|
extra_metadata = Column("metadata", JSONB, nullable=True)
|
|
|
|
__table_args__ = (
|
|
Index("idx_msg_records_channel_status", "channel_id", "status"),
|
|
Index("idx_msg_records_created_at", "created_at"),
|
|
Index(
|
|
"idx_msg_records_stuck",
|
|
"channel_id",
|
|
"created_at",
|
|
postgresql_where=(status == "processing"),
|
|
),
|
|
Index("idx_msg_records_chat", "channel_id", "chat_id"),
|
|
)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"id": self.id,
|
|
"channel_id": self.channel_id,
|
|
"channel_type": self.channel_type,
|
|
"message_id": self.message_id,
|
|
"chat_id": self.chat_id,
|
|
"chat_type": self.chat_type,
|
|
"content_type": self.content_type,
|
|
"sender_user_id": self.sender_user_id,
|
|
"content_preview": self.content_preview,
|
|
"reply_to_message_id": self.reply_to_message_id,
|
|
"agent_config_id": self.agent_config_id,
|
|
"status": self.status,
|
|
"error_message": self.error_message,
|
|
"response_time_ms": self.response_time_ms,
|
|
"reply_message_id": self.reply_message_id,
|
|
"reply_content_preview": self.reply_content_preview,
|
|
"created_at": format_utc_datetime(self.created_at),
|
|
"replied_at": format_utc_datetime(self.replied_at),
|
|
"metadata": self.extra_metadata or {},
|
|
}
|
|
|
|
|
|
class ChannelPolicyConfig(Base):
|
|
"""渠道策略配置表"""
|
|
|
|
__tablename__ = "channels_policy_configs"
|
|
|
|
id = Column(BigInteger, primary_key=True, autoincrement=True)
|
|
channel_id = Column(String(32), nullable=False, unique=True)
|
|
group_chat_mode = Column(String(16), nullable=False, default="all")
|
|
whitelist_ids = Column(JSONB, nullable=False, default=list)
|
|
welcome_message = Column(String(500), nullable=True)
|
|
work_hours_start = Column(String(5), nullable=True, default="09:00")
|
|
work_hours_end = Column(String(5), nullable=True, default="18:00")
|
|
timezone_offset = Column(Integer, nullable=False, default=8)
|
|
off_hours_reply = Column(String(500), nullable=True)
|
|
created_at = Column(DateTime, nullable=False, default=utc_now_naive)
|
|
updated_at = Column(DateTime, nullable=False, default=utc_now_naive, onupdate=utc_now_naive)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"id": self.id,
|
|
"channel_id": self.channel_id,
|
|
"group_chat_mode": self.group_chat_mode,
|
|
"whitelist_ids": self.whitelist_ids or [],
|
|
"welcome_message": self.welcome_message,
|
|
"work_hours_start": self.work_hours_start,
|
|
"work_hours_end": self.work_hours_end,
|
|
"timezone_offset": self.timezone_offset,
|
|
"off_hours_reply": self.off_hours_reply,
|
|
"created_at": format_utc_datetime(self.created_at),
|
|
"updated_at": format_utc_datetime(self.updated_at),
|
|
}
|
|
|
|
|
|
class ChannelRoutingRule(Base):
|
|
"""渠道 Agent 路由规则表"""
|
|
|
|
__tablename__ = "channels_routing_rules"
|
|
|
|
id = Column(BigInteger, primary_key=True, autoincrement=True)
|
|
channel_id = Column(String(32), nullable=False)
|
|
command = Column(String(64), nullable=False)
|
|
agent_config_id = Column(Integer, nullable=False)
|
|
priority = Column(Integer, nullable=False, default=0)
|
|
created_at = Column(DateTime, nullable=False, default=utc_now_naive)
|
|
updated_at = Column(DateTime, nullable=False, default=utc_now_naive, onupdate=utc_now_naive)
|
|
|
|
__table_args__ = (
|
|
Index("idx_routing_rules_channel", "channel_id"),
|
|
UniqueConstraint("channel_id", "command", name="uq_channel_command"),
|
|
)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"id": self.id,
|
|
"channel_id": self.channel_id,
|
|
"command": self.command,
|
|
"agent_config_id": self.agent_config_id,
|
|
"priority": self.priority,
|
|
"created_at": format_utc_datetime(self.created_at),
|
|
"updated_at": format_utc_datetime(self.updated_at),
|
|
}
|