WIP-CHECKPOINT[auth-refactor]: 固化工程师崩溃前部分成果 + 同树其他未提交WIP(仅源码,不含密钥/二进制)-- 待重激活工程师续作

This commit is contained in:
Simon
2026-07-07 21:52:11 +08:00
parent 242c1967ff
commit fab75760e0
203 changed files with 21504 additions and 3345 deletions
+27
View File
@@ -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",
]
+313
View File
@@ -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-100100 表示全量)
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: 标注IDUUID
conversation_id: 会话ID
agent_id: 坐席ID
message_id: 被标注的消息IDAI回复)
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"
# --------------------------------------------------------------------------
# 字段定义
# --------------------------------------------------------------------------
# 主键:UUIDPython端生成
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})>"
)
+123
View File
@@ -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: 知识IDUUID
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})>"
+173
View File
@@ -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: 建议IDUUID
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})>"