WIP-CHECKPOINT[auth-refactor]: 固化工程师崩溃前部分成果 + 同树其他未提交WIP(仅源码,不含密钥/二进制)-- 待重激活工程师续作
This commit is contained in:
@@ -22,6 +22,21 @@ from app.models.config_change_log import ConfigChangeLog
|
||||
from app.models.role import Role
|
||||
from app.models.user_role import UserRole
|
||||
from app.models.role_mapping_rule import RoleMappingRule
|
||||
from app.models.conversation_evaluation import ConversationEvaluation
|
||||
from app.models.audit_log import AuditLog
|
||||
from app.models.conversation_annotation import ConversationAnnotation # P2-10 会话标注
|
||||
from app.models.knowledge_suggestion import KnowledgeSuggestion # P2-13 知识库自动迭代
|
||||
from app.models.knowledge_base import KnowledgeBase
|
||||
# 阶段5 自动化闭环模型
|
||||
from app.models.automation import (
|
||||
AutoSession,
|
||||
AutoAction,
|
||||
ApprovalTicket,
|
||||
ScenarioConfig,
|
||||
RuleVersion,
|
||||
ActionLog,
|
||||
MappingCache,
|
||||
)
|
||||
# 所有模型类的列表,方便遍历
|
||||
__all__ = [
|
||||
"Conversation",
|
||||
@@ -40,4 +55,16 @@ __all__ = [
|
||||
"Role",
|
||||
"UserRole",
|
||||
"RoleMappingRule",
|
||||
"ConversationEvaluation",
|
||||
"AuditLog",
|
||||
"ConversationAnnotation",
|
||||
"KnowledgeSuggestion",
|
||||
"KnowledgeBase",
|
||||
"AutoSession",
|
||||
"AutoAction",
|
||||
"ApprovalTicket",
|
||||
"ScenarioConfig",
|
||||
"RuleVersion",
|
||||
"ActionLog",
|
||||
"MappingCache",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
# =============================================================================
|
||||
# 企微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, 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)
|
||||
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})>"
|
||||
@@ -0,0 +1,100 @@
|
||||
# =============================================================================
|
||||
# 企微IT智能服务台 — 会话标注模型
|
||||
# =============================================================================
|
||||
# 说明:对应数据库 conversation_annotations 表
|
||||
# 存储坐席对AI回复的标注数据,用于模型优化
|
||||
# =============================================================================
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, Index, Integer, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class ConversationAnnotation(Base):
|
||||
"""会话标注模型 — 对应 conversation_annotations 表。
|
||||
|
||||
存储坐席对AI回复的标注数据,用于持续优化AI能力。
|
||||
|
||||
Attributes:
|
||||
id: 标注ID(UUID)
|
||||
conversation_id: 会话ID
|
||||
agent_id: 坐席ID
|
||||
message_id: 被标注的消息ID(AI回复)
|
||||
feedback: 反馈类型(useful=有用/useless=无用)
|
||||
comment: 备注(可选)
|
||||
created_at: 创建时间
|
||||
"""
|
||||
|
||||
# 表名
|
||||
__tablename__ = "conversation_annotations"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 字段定义
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# 主键
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
primary_key=True,
|
||||
default=lambda: str(uuid.uuid4()),
|
||||
)
|
||||
|
||||
# 会话ID
|
||||
conversation_id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
nullable=False,
|
||||
index=True,
|
||||
comment="会话ID",
|
||||
)
|
||||
|
||||
# 坐席ID
|
||||
agent_id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
nullable=False,
|
||||
comment="坐席ID",
|
||||
)
|
||||
|
||||
# 被标注的消息ID
|
||||
message_id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
nullable=False,
|
||||
comment="被标注的消息ID",
|
||||
)
|
||||
|
||||
# 反馈类型
|
||||
feedback: Mapped[str] = mapped_column(
|
||||
String(20),
|
||||
nullable=False,
|
||||
comment="useful=有用/useless=无用",
|
||||
)
|
||||
|
||||
# 备注
|
||||
comment: Mapped[str] = mapped_column(
|
||||
Text,
|
||||
nullable=True,
|
||||
comment="备注",
|
||||
)
|
||||
|
||||
# 创建时间
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
default=datetime.now,
|
||||
comment="创建时间",
|
||||
)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 索引定义
|
||||
# --------------------------------------------------------------------------
|
||||
__table_args__ = (
|
||||
Index("idx_annotation_conversation", "conversation_id"),
|
||||
Index("idx_annotation_message", "message_id"),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""标注对象的字符串表示。"""
|
||||
return f"<ConversationAnnotation(id={self.id}, feedback={self.feedback})>"
|
||||
@@ -0,0 +1,122 @@
|
||||
# =============================================================================
|
||||
# 企微IT智能服务台 — 满意度评价模型
|
||||
# =============================================================================
|
||||
# 说明:对应数据库 conversation_evaluations 表,存储会话满意度评价数据
|
||||
# 核心概念:每个会话结束后,员工对本次服务进行满意度评价
|
||||
# 评价要素:星级(1-5)、表情(满意/一般/不满意)、文字反馈
|
||||
# =============================================================================
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import DateTime, Index, Integer, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class ConversationEvaluation(Base):
|
||||
"""满意度评价模型 — 对应 conversation_evaluations 表。
|
||||
|
||||
在会话结束后,员工对本次IT服务进行满意度评价。
|
||||
评价数据关联会话ID,用于服务质量分析和改进。
|
||||
|
||||
Attributes:
|
||||
id: 评价记录唯一标识(UUID,数据库自动生成)
|
||||
conversation_id: 关联的会话ID(关联 conversations 表)
|
||||
employee_id: 评价员工UserID
|
||||
employee_name: 评价员工姓名(冗余存储)
|
||||
star_rating: 星级评分(1-5)
|
||||
emoji: 表情评价(satisfied:满意/neutral:一般/dissatisfied:不满意)
|
||||
feedback_text: 文字反馈(可选,限200字)
|
||||
created_at: 评价时间
|
||||
"""
|
||||
|
||||
# 表名
|
||||
__tablename__ = "conversation_evaluations"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 字段定义
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# 主键:UUID,Python端生成
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
primary_key=True,
|
||||
default=lambda: str(uuid.uuid4()),
|
||||
)
|
||||
|
||||
# 关联的会话ID(关联 conversations 表)
|
||||
conversation_id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
nullable=False,
|
||||
comment="关联的会话ID",
|
||||
)
|
||||
|
||||
# 评价员工UserID
|
||||
employee_id: Mapped[str] = mapped_column(
|
||||
String(64),
|
||||
nullable=False,
|
||||
comment="评价员工UserID",
|
||||
)
|
||||
|
||||
# 评价员工姓名(冗余存储)
|
||||
employee_name: Mapped[str] = mapped_column(
|
||||
String(128),
|
||||
nullable=False,
|
||||
default="",
|
||||
comment="评价员工姓名",
|
||||
)
|
||||
|
||||
# 星级评分(1-5)
|
||||
star_rating: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
comment="星级评分(1-5)",
|
||||
)
|
||||
|
||||
# 表情评价
|
||||
# satisfied: 满意 😀
|
||||
# neutral: 一般 😐
|
||||
# dissatisfied: 不满意 😞
|
||||
emoji: Mapped[str] = mapped_column(
|
||||
String(20),
|
||||
nullable=False,
|
||||
comment="表情评价(satisfied/neutral/dissatisfied)",
|
||||
)
|
||||
|
||||
# 文字反馈(可选,限200字)
|
||||
feedback_text: Mapped[Optional[str]] = mapped_column(
|
||||
Text,
|
||||
nullable=True,
|
||||
comment="文字反馈(可选,限200字)",
|
||||
)
|
||||
|
||||
# 评价时间
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
default=datetime.now,
|
||||
comment="评价时间",
|
||||
)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 索引定义
|
||||
# --------------------------------------------------------------------------
|
||||
__table_args__ = (
|
||||
# 按会话ID查询(获取某会话的评价)
|
||||
Index("idx_evaluations_conversation_id", "conversation_id"),
|
||||
# 按员工ID查询(查询某员工的评价历史)
|
||||
Index("idx_evaluations_employee_id", "employee_id"),
|
||||
# 按创建时间倒序查询
|
||||
Index("idx_evaluations_created_at", "created_at"),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""评价对象的字符串表示。"""
|
||||
return (
|
||||
f"<ConversationEvaluation(id={self.id}, "
|
||||
f"conversation_id={self.conversation_id}, "
|
||||
f"star_rating={self.star_rating}, emoji={self.emoji})>"
|
||||
)
|
||||
@@ -0,0 +1,123 @@
|
||||
# =============================================================================
|
||||
# 企微IT智能服务台 — 知识库模型
|
||||
# =============================================================================
|
||||
# 说明:对应数据库 knowledge_base 表,存储IT知识库FAQ
|
||||
# 分类:按问题类型(硬件/软件/网络/安全/账号/其他)
|
||||
# 支持标签、命中统计
|
||||
# =============================================================================
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
from sqlalchemy import DateTime, Index, Integer, JSON, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class KnowledgeBase(Base):
|
||||
"""知识库FAQ模型 — 对应 knowledge_base 表。
|
||||
|
||||
存储IT知识库的问答对,支持分类、标签、命中统计。
|
||||
|
||||
Attributes:
|
||||
id: 知识ID(UUID)
|
||||
category: 分类(硬件/软件/网络/安全/账号/其他)
|
||||
title: 问题标题
|
||||
content: 答案内容(支持富文本)
|
||||
tags: 标签列表(JSON数组)
|
||||
view_count: 查看次数
|
||||
use_count: 使用次数(坐席引用次数)
|
||||
created_at: 创建时间
|
||||
updated_at: 更新时间
|
||||
"""
|
||||
|
||||
# 表名
|
||||
__tablename__ = "knowledge_base"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 字段定义
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# 主键
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
primary_key=True,
|
||||
default=lambda: str(uuid.uuid4()),
|
||||
)
|
||||
|
||||
# 分类
|
||||
category: Mapped[str] = mapped_column(
|
||||
String(64),
|
||||
nullable=False,
|
||||
default="其他",
|
||||
comment="分类:硬件/软件/网络/安全/账号/其他",
|
||||
)
|
||||
|
||||
# 问题标题
|
||||
title: Mapped[str] = mapped_column(
|
||||
String(256),
|
||||
nullable=False,
|
||||
comment="问题标题",
|
||||
)
|
||||
|
||||
# 答案内容
|
||||
content: Mapped[str] = mapped_column(
|
||||
Text,
|
||||
nullable=False,
|
||||
comment="答案内容",
|
||||
)
|
||||
|
||||
# 标签列表
|
||||
tags: Mapped[List[str]] = mapped_column(
|
||||
JSON,
|
||||
nullable=False,
|
||||
default=list,
|
||||
comment="标签列表",
|
||||
)
|
||||
|
||||
# 查看次数
|
||||
view_count: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
default=0,
|
||||
comment="查看次数",
|
||||
)
|
||||
|
||||
# 使用次数(坐席引用次数)
|
||||
use_count: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
default=0,
|
||||
comment="使用次数",
|
||||
)
|
||||
|
||||
# 创建时间
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
default=datetime.now,
|
||||
comment="创建时间",
|
||||
)
|
||||
|
||||
# 更新时间
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
default=datetime.now,
|
||||
onupdate=datetime.now,
|
||||
comment="更新时间",
|
||||
)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 索引定义
|
||||
# --------------------------------------------------------------------------
|
||||
__table_args__ = (
|
||||
Index("idx_kb_category", "category"),
|
||||
# Index("idx_kb_tags", "tags"), # JSON 字段不能用 btree,需要 GIN 索引或注释
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""知识库对象的字符串表示。"""
|
||||
return f"<KnowledgeBase(id={self.id}, category={self.category}, title={self.title})>"
|
||||
@@ -0,0 +1,173 @@
|
||||
# =============================================================================
|
||||
# 企微IT智能服务台 — 知识库优化建议模型
|
||||
# =============================================================================
|
||||
# 说明:对应数据库 knowledge_suggestions 表
|
||||
# 存储AI分析生成的优化建议,用于知识库迭代
|
||||
# 分析维度:错误标注高频问题、未命中知识库的会话、AI不确定回复
|
||||
# =============================================================================
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlalchemy import DateTime, Index, Integer, JSON, String, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class KnowledgeSuggestion(Base):
|
||||
"""知识库优化建议模型 — 对应 knowledge_suggestions 表。
|
||||
|
||||
存储AI自动分析生成的优化建议,用于知识库持续迭代。
|
||||
|
||||
Attributes:
|
||||
id: 建议ID(UUID)
|
||||
suggestion_type: 建议类型(new_faq=新增FAQ/update=更新/outdated=标记过时)
|
||||
status: 状态(pending=待审核/approved=已通过/rejected=已拒绝/applied=已应用)
|
||||
title: 建议标题(新增/更新的FAQ标题)
|
||||
content: 建议内容(答案内容)
|
||||
category: 分类
|
||||
tags: 标签列表(JSON数组)
|
||||
source_type: 分析来源(annotation=标注数据/conversation=会话数据/ai_uncertain=AI不确定)
|
||||
source_data: 来源数据(JSON,存储相关会话ID或标注ID列表)
|
||||
reason: 生成理由(AI分析的理由)
|
||||
reject_reason: 拒绝理由(审核拒绝时填写)
|
||||
reviewer_id: 审核人ID
|
||||
reviewed_at: 审核时间
|
||||
created_at: 创建时间
|
||||
updated_at: 更新时间
|
||||
"""
|
||||
|
||||
# 表名
|
||||
__tablename__ = "knowledge_suggestions"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 字段定义
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# 主键
|
||||
id: Mapped[str] = mapped_column(
|
||||
String(36),
|
||||
primary_key=True,
|
||||
default=lambda: str(uuid.uuid4()),
|
||||
)
|
||||
|
||||
# 建议类型
|
||||
suggestion_type: Mapped[str] = mapped_column(
|
||||
String(20),
|
||||
nullable=False,
|
||||
default="new_faq",
|
||||
comment="new_faq=新增FAQ/update=更新/outdated=标记过时",
|
||||
)
|
||||
|
||||
# 状态
|
||||
status: Mapped[str] = mapped_column(
|
||||
String(20),
|
||||
nullable=False,
|
||||
default="pending",
|
||||
index=True,
|
||||
comment="pending=待审核/approved=已通过/rejected=已拒绝/applied=已应用",
|
||||
)
|
||||
|
||||
# 建议标题
|
||||
title: Mapped[str] = mapped_column(
|
||||
String(256),
|
||||
nullable=False,
|
||||
comment="新增/更新的FAQ标题",
|
||||
)
|
||||
|
||||
# 建议内容
|
||||
content: Mapped[str] = mapped_column(
|
||||
Text,
|
||||
nullable=False,
|
||||
comment="答案内容",
|
||||
)
|
||||
|
||||
# 分类
|
||||
category: Mapped[str] = mapped_column(
|
||||
String(64),
|
||||
nullable=False,
|
||||
default="其他",
|
||||
comment="分类:硬件/软件/网络/安全/账号/其他",
|
||||
)
|
||||
|
||||
# 标签列表
|
||||
tags: Mapped[List[str]] = mapped_column(
|
||||
JSON,
|
||||
nullable=False,
|
||||
default=list,
|
||||
comment="标签列表",
|
||||
)
|
||||
|
||||
# 分析来源
|
||||
source_type: Mapped[str] = mapped_column(
|
||||
String(30),
|
||||
nullable=False,
|
||||
comment="annotation=标注数据/conversation=会话数据/ai_uncertain=AI不确定",
|
||||
)
|
||||
|
||||
# 来源数据(JSON)
|
||||
source_data: Mapped[Optional[List[str]]] = mapped_column(
|
||||
JSON,
|
||||
nullable=True,
|
||||
comment="相关会话ID或标注ID列表",
|
||||
)
|
||||
|
||||
# 生成理由
|
||||
reason: Mapped[Optional[str]] = mapped_column(
|
||||
Text,
|
||||
nullable=True,
|
||||
comment="AI分析的理由",
|
||||
)
|
||||
|
||||
# 拒绝理由
|
||||
reject_reason: Mapped[Optional[str]] = mapped_column(
|
||||
Text,
|
||||
nullable=True,
|
||||
comment="审核拒绝时填写",
|
||||
)
|
||||
|
||||
# 审核人ID
|
||||
reviewer_id: Mapped[Optional[str]] = mapped_column(
|
||||
String(36),
|
||||
nullable=True,
|
||||
comment="审核人ID",
|
||||
)
|
||||
|
||||
# 审核时间
|
||||
reviewed_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
comment="审核时间",
|
||||
)
|
||||
|
||||
# 创建时间
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
default=datetime.now,
|
||||
comment="创建时间",
|
||||
)
|
||||
|
||||
# 更新时间
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
default=datetime.now,
|
||||
onupdate=datetime.now,
|
||||
comment="更新时间",
|
||||
)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 索引定义
|
||||
# --------------------------------------------------------------------------
|
||||
__table_args__ = (
|
||||
Index("idx_suggestion_status", "status"),
|
||||
Index("idx_suggestion_type", "suggestion_type"),
|
||||
Index("idx_suggestion_created", "created_at"),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""建议对象的字符串表示。"""
|
||||
return f"<KnowledgeSuggestion(id={self.id}, type={self.suggestion_type}, status={self.status})>"
|
||||
Reference in New Issue
Block a user