bea288e414
== 已部署上线 (9项) == - 代办事项真实数据源集成 (企微审批API 8bug修复链) - H5/坐席端 Logo样式统一+绿色背景 - 视频引导页修复 (localStorage key v2) - 坐席端 v9 Vue版本修复 (ElMessage._context) - 截图按钮 v10 修复 (getDisplayMedia user gesture) - 扫码样式恢复+H5扫码登录跳转修复 - H5截图快捷键提示 == 代码完成待部署 (3项) == - 知识迭代3Bug修复 (#8 POST端点/#7 MERGE幂等/#6 过期检查) - 会议室预定-小鱼易联终端 (40文件, 40/40测试通过) - IT资产升级审批推送 (asset_service.py) == 需求文档 (2项) == - 坐席端AI辅助消息框-PRD (4项新功能确认) - 坐席端布局优化建议 v2.0 (7天计划) == 新增文档 == - 日报-2026-07-11.md - 知识迭代Bug修复报告-20260711.md - 会议室预定-部署指南.md - CHANGELOG.md 更新 == 测试 == - test_todo_integration.py: 40/40 - test_meetingroom.py: 40/40 - test_bugfix_ki_suggestions.py: 21/21
434 lines
22 KiB
Python
434 lines
22 KiB
Python
# =============================================================================
|
||
# 企微IT智能服务台 — 阶段5 自动化闭环 数据模型
|
||
# =============================================================================
|
||
# 说明:自动化引擎相关表,表名统一前缀 auto_。
|
||
# 模型清单:
|
||
# 1. AutoSession — 自动化处置会话(生命周期/状态机)
|
||
# 2. AutoAction — 单个处置动作(与场景动作计划对应)
|
||
# 3. ApprovalTicket — 审批单(高危动作 / 员工二次确认)
|
||
# 4. ScenarioConfig — 场景配置(开关 + 触发条件 + 动作 + 审批策略)
|
||
# 5. RuleVersion — 规则版本(P1 灰度发布)
|
||
# 6. ActionLog — 外部调用审计日志(出入参全记录)
|
||
# 7. MappingCache — 终端/员工映射缓存(联软>eHR,TTL)
|
||
#
|
||
# 风格:沿用项目既有模型写法(SQLAlchemy 2.0 Mapped / mapped_column + 注释)。
|
||
# 关联:AutoSession 与工单(conversation)为「弱关联」(仅存 conversation_id,
|
||
# 不建外键约束,便于阶段5 独立演进)。
|
||
# =============================================================================
|
||
|
||
import uuid
|
||
from datetime import datetime
|
||
from typing import Optional
|
||
|
||
from sqlalchemy import JSON, Boolean, DateTime, Float, Integer, Numeric, SmallInteger, String, Text
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from app.database import Base
|
||
|
||
|
||
def _uuid() -> str:
|
||
"""生成 UUID 字符串主键(兼容 PostgreSQL 与 SQLite)。"""
|
||
return str(uuid.uuid4())
|
||
|
||
|
||
# =============================================================================
|
||
# 1. 自动化处置会话
|
||
# =============================================================================
|
||
class AutoSession(Base):
|
||
"""自动化处置会话 — 对应 auto_sessions 表。
|
||
|
||
一个员工的一次自动化处置诉求对应一个会话,贯穿「意图识别→动作编排→
|
||
执行/审批→处置成功→静默关单」全过程。
|
||
|
||
Attributes:
|
||
id: 会话唯一ID
|
||
conversation_id: 关联工单ID(弱关联,可空)
|
||
employee_id: 发起员工企微 UserID
|
||
agent_id: 接管坐席ID(转人工后填入)
|
||
scenario_key: 命中场景(password_reset/software_install/virus_dispose/terminal_locate)
|
||
status: 会话状态机(created/running/paused/resolved/closed/handoff/error)
|
||
mode: 执行模式(plan_only/real_exec)
|
||
confidence: 意图识别置信度(0-1)
|
||
intent: 意图识别原始结果(JSON)
|
||
current_action_id: 当前正在执行的动作ID
|
||
title: 会话标题(展示用)
|
||
auto_close_at: 静默关单触发时间(写入 Redis TTL 同步)
|
||
resolved_at: 处置成功时间
|
||
closed_by: 关单/接管操作人
|
||
meta: 扩展上下文(原始消息、映射结果等)
|
||
"""
|
||
|
||
__tablename__ = "auto_sessions"
|
||
|
||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
||
conversation_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True, index=True)
|
||
employee_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
||
agent_id: Mapped[Optional[str]] = mapped_column(String(64), nullable=True, index=True)
|
||
scenario_key: Mapped[Optional[str]] = mapped_column(String(64), nullable=True, index=True)
|
||
status: Mapped[str] = mapped_column(String(20), nullable=False, default="created", index=True)
|
||
mode: Mapped[str] = mapped_column(String(20), nullable=False, default="real_exec")
|
||
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
||
intent: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
current_action_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True)
|
||
title: Mapped[str] = mapped_column(String(256), nullable=False, default="")
|
||
auto_close_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
||
resolved_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
||
closed_by: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||
meta: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
# 复杂场景重构:暂停时间戳,用于超时计算;恢复后置 NULL
|
||
paused_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
updated_at: Mapped[datetime] = mapped_column(
|
||
DateTime(timezone=True), nullable=False, default=datetime.now, onupdate=datetime.now
|
||
)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<AutoSession(id={self.id}, scenario={self.scenario_key}, status={self.status})>"
|
||
|
||
|
||
# =============================================================================
|
||
# 2. 处置动作
|
||
# =============================================================================
|
||
class AutoAction(Base):
|
||
"""单个处置动作 — 对应 auto_actions 表。
|
||
|
||
每个动作对应场景动作计划中的一步,由 action_registry 的适配器真正执行。
|
||
|
||
Attributes:
|
||
id: 动作ID
|
||
session_id: 所属会话
|
||
action_index: 动作在计划中的顺序
|
||
action_type: 语义动作类型(password_reset_guide/software_install/virus_quarantine/terminal_locate...)
|
||
adapter: 执行适配器(huorong/lianruan/ehr/atrust/...)
|
||
risk_level: 风险等级(read/low/high)
|
||
title/description: 展示信息
|
||
status: 动作状态机
|
||
payload: 动作入参
|
||
result: 动作执行结果
|
||
error: 错误信息
|
||
approved_by/approved_at: 审批人/时间
|
||
"""
|
||
|
||
__tablename__ = "auto_actions"
|
||
|
||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
||
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
||
action_index: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||
action_type: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
||
adapter: Mapped[str] = mapped_column(String(32), nullable=False, default="")
|
||
risk_level: Mapped[str] = mapped_column(String(16), nullable=False, default="read")
|
||
title: Mapped[str] = mapped_column(String(256), nullable=False, default="")
|
||
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||
status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending", index=True)
|
||
payload: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
result: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
error: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||
approved_by: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||
approved_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
updated_at: Mapped[datetime] = mapped_column(
|
||
DateTime(timezone=True), nullable=False, default=datetime.now, onupdate=datetime.now
|
||
)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<AutoAction(id={self.id}, type={self.action_type}, status={self.status})>"
|
||
|
||
|
||
# =============================================================================
|
||
# 3. 审批单
|
||
# =============================================================================
|
||
class ApprovalTicket(Base):
|
||
"""审批单 — 对应 auto_approval_tickets 表。
|
||
|
||
高危动作需坐席审批,或写操作需员工 H5 二次确认时生成审批单。
|
||
|
||
Attributes:
|
||
id: 审批单ID
|
||
action_id: 关联动作
|
||
session_id: 关联会话
|
||
approver_id: 审批人(坐席/员工)
|
||
channel: 审批渠道(agent/h5)
|
||
status: 审批状态(pending/approved/rejected/expired)
|
||
reason: 申请理由
|
||
decision_note: 审批意见
|
||
decided_at: 决定时间
|
||
"""
|
||
|
||
__tablename__ = "auto_approval_tickets"
|
||
|
||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
||
action_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
||
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
||
approver_id: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||
channel: Mapped[str] = mapped_column(String(16), nullable=False, default="agent")
|
||
status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending", index=True)
|
||
reason: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||
decision_note: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||
decided_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<ApprovalTicket(id={self.id}, action={self.action_id}, status={self.status})>"
|
||
|
||
|
||
# =============================================================================
|
||
# 4. 场景配置
|
||
# =============================================================================
|
||
class ScenarioConfig(Base):
|
||
"""场景配置 — 对应 auto_scenario_configs 表。
|
||
|
||
本期(Q5)管理后台结构化简易配置:场景开关 + 触发条件 + 动作 + 审批策略。
|
||
编排引擎列为 P2,本期动作计划为静态模板。
|
||
|
||
Attributes:
|
||
scenario_key: 场景键(唯一,password_reset/software_install/virus_dispose/terminal_locate)
|
||
name/description: 展示信息
|
||
enabled: 是否启用
|
||
trigger_conditions: 触发条件({"intents":[],"keywords":[]})
|
||
actions: 动作计划(有序列表,每项 {action_type, adapter, risk_level, params})
|
||
approval_strategy: 审批策略({"read":"auto","low":"auto","high":"approval"})
|
||
current_version_id: 当前生效版本ID
|
||
"""
|
||
|
||
__tablename__ = "auto_scenario_configs"
|
||
|
||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
||
scenario_key: Mapped[str] = mapped_column(String(64), nullable=False, unique=True, index=True)
|
||
name: Mapped[str] = mapped_column(String(128), nullable=False, default="")
|
||
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
||
trigger_conditions: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
actions: Mapped[Optional[list]] = mapped_column(JSON, nullable=True)
|
||
approval_strategy: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
current_version_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
updated_at: Mapped[datetime] = mapped_column(
|
||
DateTime(timezone=True), nullable=False, default=datetime.now, onupdate=datetime.now
|
||
)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<ScenarioConfig(key={self.scenario_key}, enabled={self.enabled})>"
|
||
|
||
|
||
# =============================================================================
|
||
# 5. 规则版本(P1 灰度)
|
||
# =============================================================================
|
||
class RuleVersion(Base):
|
||
"""规则版本 — 对应 auto_rule_versions 表。
|
||
|
||
支持场景配置的版本化与灰度发布(P1):每次新建/修改生成快照,
|
||
canary_percent 控制灰度比例,status 控制 draft/published/archived。
|
||
|
||
Attributes:
|
||
scenario_key: 所属场景
|
||
version: 版本号(同场景内递增)
|
||
content: 配置快照(actions + approval_strategy + trigger_conditions)
|
||
status: 版本状态(draft/published/archived)
|
||
canary_percent: 灰度比例(0-100,100 表示全量)
|
||
created_by: 创建人
|
||
remark: 版本说明
|
||
"""
|
||
|
||
__tablename__ = "auto_rule_versions"
|
||
|
||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
||
scenario_key: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
||
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||
content: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
status: Mapped[str] = mapped_column(String(20), nullable=False, default="draft", index=True)
|
||
canary_percent: Mapped[int] = mapped_column(Integer, nullable=False, default=100)
|
||
created_by: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||
remark: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<RuleVersion(key={self.scenario_key}, v={self.version}, status={self.status})>"
|
||
|
||
|
||
# =============================================================================
|
||
# 6. 外部调用审计日志
|
||
# =============================================================================
|
||
class ActionLog(Base):
|
||
"""外部调用审计日志 — 对应 auto_action_logs 表。
|
||
|
||
所有外部系统调用的出入参全量落表,满足审计与排障需求。
|
||
|
||
Attributes:
|
||
session_id: 关联会话
|
||
action_id: 关联动作(可选)
|
||
employee_id: 关联员工(可选)
|
||
event: 事件名(如 huorong.isolate / dify.intent / lianruan.query)
|
||
direction: 方向(in/out)
|
||
system: 外部系统(huorong/lianruan/dify/ragflow/ehr/internal)
|
||
request/response: 出入参(脱敏后)
|
||
status: 状态(success/error/http_xxx)
|
||
latency_ms: 耗时
|
||
error: 错误
|
||
"""
|
||
|
||
__tablename__ = "auto_action_logs"
|
||
|
||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
||
session_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True, index=True)
|
||
action_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True, index=True)
|
||
employee_id: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||
event: Mapped[str] = mapped_column(String(128), nullable=False, default="")
|
||
direction: Mapped[str] = mapped_column(String(8), nullable=False, default="out")
|
||
system: Mapped[str] = mapped_column(String(32), nullable=False, default="internal")
|
||
request: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
response: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
status: Mapped[str] = mapped_column(String(32), nullable=False, default="")
|
||
latency_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
||
error: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<ActionLog(event={self.event}, system={self.system}, status={self.status})>"
|
||
|
||
|
||
# =============================================================================
|
||
# 7. 终端/员工映射缓存
|
||
# =============================================================================
|
||
class MappingCache(Base):
|
||
"""映射缓存 — 对应 auto_mapping_cache 表。
|
||
|
||
联软(主)解析员工→终端结果缓存,TTL 过期后回退 EHR 兜底并刷新。
|
||
避免每次处置都打联软,降低外部依赖压力。
|
||
|
||
Attributes:
|
||
employee_id: 员工ID
|
||
source: 映射源(lianruan/ehr)
|
||
mapped_data: 映射结果(终端列表/部门/资产等)
|
||
expires_at: 过期时间
|
||
"""
|
||
|
||
__tablename__ = "auto_mapping_cache"
|
||
|
||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
||
employee_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
||
source: Mapped[str] = mapped_column(String(32), nullable=False, default="lianruan")
|
||
mapped_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||
expires_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<MappingCache(employee={self.employee_id}, source={self.source})>"
|
||
|
||
|
||
# =============================================================================
|
||
# 8. 信息项(复杂场景重构第一阶段)
|
||
# =============================================================================
|
||
class InformationItem(Base):
|
||
"""信息项 — 对应 auto_information_items 表。
|
||
|
||
管理对话中收集的信息项及其变更历史,支持更正(CORRECT)与补充(SUPPLEMENT)。
|
||
|
||
修饰符(modifiers)取值:
|
||
固定 — 动作执行后锁定,不可更正
|
||
增量 — 补充时追加而非覆盖
|
||
明确 — 用户明确提供的值
|
||
隐含 — 从上下文推断的值
|
||
复述 — 更正后需向员工发送确认消息
|
||
必需 — 流程阻塞项,未填写时不可继续执行
|
||
|
||
Attributes:
|
||
id: UUID 主键
|
||
session_id: 关联会话ID(弱关联,不建外键)
|
||
name: 信息项名称(如"用户名"、"终端ID"、"部门")
|
||
value: 当前值
|
||
modifiers: 修饰符列表,如 ["固定","必需"]
|
||
is_filled: 是否已填写
|
||
is_locked: 是否已锁定(固定修饰符 + 关联动作已执行 → True,不可更正)
|
||
version: 版本号,每次更正/补充 +1
|
||
update_history: 变更历史数组
|
||
created_at: 创建时间
|
||
updated_at: 最后更新时间
|
||
"""
|
||
|
||
__tablename__ = "auto_information_items"
|
||
|
||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
||
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||
value: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
||
modifiers: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
||
is_filled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||
is_locked: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||
update_history: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
updated_at: Mapped[datetime] = mapped_column(
|
||
DateTime(timezone=True), nullable=False, default=datetime.now, onupdate=datetime.now
|
||
)
|
||
# Phase 2: 复杂场景重构第二阶段新增
|
||
derived_from: Mapped[Optional[list]] = mapped_column(JSON, nullable=True) # 推导来源 item_key 数组
|
||
correction_reason: Mapped[Optional[str]] = mapped_column(String(200), nullable=True) # 更正备注
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<InformationItem(session={self.session_id}, name={self.name}, v={self.version})>"
|
||
|
||
|
||
# =============================================================================
|
||
# 9. 上下文压缩记录(复杂场景重构第二阶段 P2)
|
||
# =============================================================================
|
||
class ContextCompression(Base):
|
||
"""上下文压缩记录 — 对应 auto_context_compressions 表。
|
||
|
||
每次上下文压缩操作的日志记录,包含压缩前后 token 数、压缩比、耗时等。
|
||
|
||
Attributes:
|
||
session_id: 关联会话ID
|
||
tokens_before: 压缩前 token 数
|
||
tokens_after: 压缩后 token 数
|
||
compression_ratio: 压缩比(after/before)
|
||
task_node: 压缩时任务节点
|
||
duration_ms: 压缩耗时(毫秒)
|
||
compression_level: 压缩级别(1/2/3)
|
||
summary: 压缩摘要内容
|
||
"""
|
||
__tablename__ = "auto_context_compressions"
|
||
|
||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
||
tokens_before: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
tokens_after: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
compression_ratio: Mapped[float] = mapped_column(Numeric(5, 2), nullable=False)
|
||
task_node: Mapped[Optional[str]] = mapped_column(String(128), nullable=True)
|
||
duration_ms: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
compression_level: Mapped[int] = mapped_column(SmallInteger, nullable=False, default=1)
|
||
summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<ContextCompression(session={self.session_id}, {self.tokens_before}→{self.tokens_after})>"
|
||
|
||
|
||
# =============================================================================
|
||
# 10. 信息项快照(复杂场景重构第二阶段 P3)
|
||
# =============================================================================
|
||
class InformationSnapshot(Base):
|
||
"""信息项快照 — 对应 auto_information_snapshots 表。
|
||
|
||
每次更正发生前创建快照,记录该 session 全部信息项的完整状态,
|
||
用于支持更正撤销(undo)功能。
|
||
|
||
Attributes:
|
||
session_id: 关联会话ID
|
||
trigger_item_key: 触发更正的信息项 key
|
||
snapshot_data: 全部信息项快照 {item_key: {value, version}}
|
||
correction_ids: 本次更正涉及的信息项版本 ID 列表
|
||
is_undone: 是否已被撤销
|
||
"""
|
||
__tablename__ = "auto_information_snapshots"
|
||
|
||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
||
trigger_item_key: Mapped[str] = mapped_column(String(64), nullable=False)
|
||
snapshot_data: Mapped[dict] = mapped_column(JSON, nullable=False)
|
||
correction_ids: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
||
is_undone: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<InformationSnapshot(session={self.session_id}, trigger={self.trigger_item_key}, undone={self.is_undone})>"
|