ForcePilot/backend/package/yuxi/storage/postgres/models_channels.py

204 lines
8.1 KiB
Python
Raw Normal View History

"""多渠道网关 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),
}