1. 为消息反馈表新增channel字段并完善相关接口返回 2. 创建渠道插件状态存储表与对应索引 3. 调整路由规则agent_config_id字段类型为字符串 4. 添加日志敏感信息脱敏功能 5. 优化消息记录仓库方法,新增响应时间统计和查询接口
238 lines
9.5 KiB
Python
238 lines
9.5 KiB
Python
"""多渠道网关 ORM 模型 - 渠道用户映射、会话映射、消息记录、插件状态"""
|
|
|
|
from typing import Any
|
|
|
|
from sqlalchemy import (
|
|
BigInteger,
|
|
Column,
|
|
DateTime,
|
|
Index,
|
|
Integer,
|
|
String,
|
|
UniqueConstraint,
|
|
text,
|
|
)
|
|
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(String(64), 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),
|
|
}
|
|
|
|
|
|
class ChannelPluginState(Base):
|
|
"""渠道插件运行时状态统一存储"""
|
|
|
|
__tablename__ = "channel_plugin_states"
|
|
|
|
id = Column(BigInteger, primary_key=True, autoincrement=True)
|
|
channel_id = Column(String(32), nullable=False)
|
|
namespace = Column(String(64), nullable=False, default="default")
|
|
entry_key = Column(String(128), nullable=False)
|
|
value_json = Column(JSONB, nullable=False, default=dict)
|
|
created_at = Column(DateTime, nullable=False, default=utc_now_naive)
|
|
updated_at = Column(DateTime, nullable=False, default=utc_now_naive, onupdate=utc_now_naive)
|
|
expires_at = Column(DateTime, nullable=True)
|
|
|
|
__table_args__ = (
|
|
UniqueConstraint("channel_id", "namespace", "entry_key", name="uq_channel_state"),
|
|
Index("idx_plugin_states_expiry", "expires_at", postgresql_where=(text("expires_at IS NOT NULL"))),
|
|
Index("idx_plugin_states_channel", "channel_id", "namespace"),
|
|
)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"id": self.id,
|
|
"channel_id": self.channel_id,
|
|
"namespace": self.namespace,
|
|
"entry_key": self.entry_key,
|
|
"value_json": self.value_json or {},
|
|
"created_at": format_utc_datetime(self.created_at),
|
|
"updated_at": format_utc_datetime(self.updated_at),
|
|
"expires_at": format_utc_datetime(self.expires_at) if self.expires_at else None,
|
|
}
|