230 lines
7.0 KiB
Python
230 lines
7.0 KiB
Python
|
|
# =============================================================================
|
|||
|
|
# 企微IT智能服务台 — 分诊会话模型
|
|||
|
|
# =============================================================================
|
|||
|
|
# 说明:对应数据库 triage_sessions 表
|
|||
|
|
# 存储 AI 分诊的完整会话记录,包括分诊步骤、收集的上下文、路由结果等。
|
|||
|
|
# =============================================================================
|
|||
|
|
|
|||
|
|
import uuid
|
|||
|
|
from datetime import datetime
|
|||
|
|
from typing import Any, Dict, List, Optional
|
|||
|
|
|
|||
|
|
from sqlalchemy import DateTime, Float, Index, Integer, JSON, String, Text
|
|||
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|||
|
|
|
|||
|
|
from app.database import Base
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TriageSession(Base):
|
|||
|
|
"""分诊会话模型 — 对应 triage_sessions 表。
|
|||
|
|
|
|||
|
|
存储员工发起的 AI 分诊全流程数据,从发起分诊到最终路由。
|
|||
|
|
|
|||
|
|
Attributes:
|
|||
|
|
id: 分诊会话ID(UUID)
|
|||
|
|
conversation_id: 关联的企微会话ID
|
|||
|
|
user_id: 员工企微UserID
|
|||
|
|
user_name: 员工姓名
|
|||
|
|
user_dept: 员工部门
|
|||
|
|
user_level: 员工IT技能等级
|
|||
|
|
device_info: 设备信息
|
|||
|
|
request_title: 问题标题
|
|||
|
|
request_content: 问题原文
|
|||
|
|
source: 来源渠道(wecom_h5 / api / other)
|
|||
|
|
problem_type: AI识别的问题类型(硬件/软件/网络/安全/账号/其他)
|
|||
|
|
problem_category: AI识别的问题分类
|
|||
|
|
confidence: AI置信度(0.0-1.0)
|
|||
|
|
urgency: 紧急度(high/medium/low)
|
|||
|
|
suggested_route: AI建议路由(ai_self/human/auto_approval)
|
|||
|
|
matched_knowledge: 匹配到的知识条目
|
|||
|
|
match_score: 知识匹配分数
|
|||
|
|
context_tags: 上下文标签列表(JSON数组)
|
|||
|
|
triage_steps: 分诊步骤数据(JSON数组)
|
|||
|
|
collected_context: 已收集的上下文列表(JSON数组)
|
|||
|
|
status: 分诊状态(pending/triaging/routed/skipped/timeout)
|
|||
|
|
route_action: 最终路由动作(ai_self/human/auto_approval/skip)
|
|||
|
|
route_note: 路由备注
|
|||
|
|
operator_id: 操作坐席ID
|
|||
|
|
operated_at: 操作时间
|
|||
|
|
created_at: 创建时间
|
|||
|
|
updated_at: 更新时间
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
__tablename__ = "triage_sessions"
|
|||
|
|
|
|||
|
|
# 主键
|
|||
|
|
id: Mapped[str] = mapped_column(
|
|||
|
|
String(36),
|
|||
|
|
primary_key=True,
|
|||
|
|
default=lambda: str(uuid.uuid4()),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 会话关联
|
|||
|
|
conversation_id: Mapped[str] = mapped_column(
|
|||
|
|
String(36),
|
|||
|
|
nullable=False,
|
|||
|
|
comment="关联的企微会话ID",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 用户信息
|
|||
|
|
user_id: Mapped[str] = mapped_column(
|
|||
|
|
String(100),
|
|||
|
|
nullable=False,
|
|||
|
|
comment="员工企微UserID",
|
|||
|
|
)
|
|||
|
|
user_name: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(100),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="员工姓名",
|
|||
|
|
)
|
|||
|
|
user_dept: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(100),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="员工部门",
|
|||
|
|
)
|
|||
|
|
user_level: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(20),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="员工IT技能等级",
|
|||
|
|
)
|
|||
|
|
device_info: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(200),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="设备信息",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 问题描述
|
|||
|
|
request_title: Mapped[str] = mapped_column(
|
|||
|
|
String(200),
|
|||
|
|
nullable=False,
|
|||
|
|
comment="问题标题",
|
|||
|
|
)
|
|||
|
|
request_content: Mapped[str] = mapped_column(
|
|||
|
|
Text,
|
|||
|
|
nullable=False,
|
|||
|
|
comment="问题原文",
|
|||
|
|
)
|
|||
|
|
source: Mapped[str] = mapped_column(
|
|||
|
|
String(50),
|
|||
|
|
nullable=False,
|
|||
|
|
default="wecom_h5",
|
|||
|
|
comment="来源渠道",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# AI 分诊分析结果
|
|||
|
|
problem_type: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(50),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="问题类型:硬件/软件/网络/安全/账号/其他",
|
|||
|
|
)
|
|||
|
|
problem_category: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(100),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="问题分类",
|
|||
|
|
)
|
|||
|
|
confidence: Mapped[Optional[float]] = mapped_column(
|
|||
|
|
Float,
|
|||
|
|
nullable=True,
|
|||
|
|
comment="AI置信度(0.0-1.0)",
|
|||
|
|
)
|
|||
|
|
urgency: Mapped[str] = mapped_column(
|
|||
|
|
String(20),
|
|||
|
|
nullable=False,
|
|||
|
|
default="medium",
|
|||
|
|
comment="紧急度:high/medium/low",
|
|||
|
|
)
|
|||
|
|
suggested_route: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(50),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="AI建议路由:ai_self/human/auto_approval",
|
|||
|
|
)
|
|||
|
|
matched_knowledge: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(500),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="匹配到的知识条目",
|
|||
|
|
)
|
|||
|
|
match_score: Mapped[Optional[float]] = mapped_column(
|
|||
|
|
Float,
|
|||
|
|
nullable=True,
|
|||
|
|
comment="知识匹配分数",
|
|||
|
|
)
|
|||
|
|
context_tags: Mapped[List[str]] = mapped_column(
|
|||
|
|
JSON,
|
|||
|
|
nullable=False,
|
|||
|
|
default=list,
|
|||
|
|
comment="上下文标签列表",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 分诊步骤数据
|
|||
|
|
triage_steps: Mapped[List[Dict[str, Any]]] = mapped_column(
|
|||
|
|
JSON,
|
|||
|
|
nullable=False,
|
|||
|
|
default=list,
|
|||
|
|
comment="分诊步骤数据:[{question, options:[{label, probability}]}]",
|
|||
|
|
)
|
|||
|
|
collected_context: Mapped[List[str]] = mapped_column(
|
|||
|
|
JSON,
|
|||
|
|
nullable=False,
|
|||
|
|
default=list,
|
|||
|
|
comment="已收集的上下文列表",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 状态与路由
|
|||
|
|
status: Mapped[str] = mapped_column(
|
|||
|
|
String(30),
|
|||
|
|
nullable=False,
|
|||
|
|
default="pending",
|
|||
|
|
comment="分诊状态:pending/triaging/routed/skipped/timeout",
|
|||
|
|
)
|
|||
|
|
route_action: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(50),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="最终路由动作:ai_self/human/auto_approval/skip",
|
|||
|
|
)
|
|||
|
|
route_note: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
Text,
|
|||
|
|
nullable=True,
|
|||
|
|
comment="路由备注",
|
|||
|
|
)
|
|||
|
|
operator_id: Mapped[Optional[str]] = mapped_column(
|
|||
|
|
String(100),
|
|||
|
|
nullable=True,
|
|||
|
|
comment="操作坐席ID",
|
|||
|
|
)
|
|||
|
|
operated_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_triage_status", "status"),
|
|||
|
|
Index("idx_triage_urgency", "urgency"),
|
|||
|
|
Index("idx_triage_conversation", "conversation_id"),
|
|||
|
|
Index("idx_triage_created", "created_at"),
|
|||
|
|
Index("idx_triage_user", "user_id"),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def __repr__(self) -> str:
|
|||
|
|
"""分诊会话对象的字符串表示。"""
|
|||
|
|
return (
|
|||
|
|
f"<TriageSession(id={self.id}, user={self.user_id}, "
|
|||
|
|
f"status={self.status}, urgency={self.urgency})>"
|
|||
|
|
)
|