# ============================================================================= # 企微IT智能服务台 — 阶段5 自动化闭环 Schema # ============================================================================= # 说明:定义自动化会话相关接口的 Pydantic 请求/响应模型,以及 ORM → dict # 序列化辅助函数。所有响应沿用项目 {code, data, message} 约定, # 此处只描述 data 结构。 # ============================================================================= from __future__ import annotations from datetime import datetime from typing import Any, Dict, List, Optional from pydantic import BaseModel, Field # -------------------------------------------------------------------------- # 请求模型 # -------------------------------------------------------------------------- class CreateSessionRequest(BaseModel): """创建自动化会话请求。""" conversation_id: Optional[str] = Field(None, description="关联工单ID(弱关联)") employee_id: str = Field(..., description="发起员工企微 UserID") description: str = Field(..., description="员工诉求/原始消息") mode: str = Field("real_exec", description="执行模式:plan_only / real_exec") class ApprovalDecisionRequest(BaseModel): """坐席审批决策请求。""" decision: str = Field(..., description="approve / reject") note: Optional[str] = Field(None, description="审批意见") class ConfirmRequest(BaseModel): """员工 H5 二次确认请求。""" confirmed: bool = Field(..., description="是否确认执行") note: Optional[str] = Field(None, description="备注") class TakeoverRequest(BaseModel): """转人工接管请求。""" agent_id: str = Field(..., description="接管坐席ID") note: Optional[str] = Field(None, description="接管说明") class ResolveFeedbackRequest(BaseModel): """处置结果反馈(员工是否满意)。""" satisfied: bool = Field(True, description="是否满意") note: Optional[str] = Field(None, description="反馈备注") class ScenarioConfigUpdate(BaseModel): """场景配置更新请求(管理端)。""" name: Optional[str] = None description: Optional[str] = None enabled: Optional[bool] = None trigger_conditions: Optional[dict] = None actions: Optional[list] = None approval_strategy: Optional[dict] = None # -------------------------------------------------------------------------- # 响应模型 # -------------------------------------------------------------------------- class IntentResult(BaseModel): """意图识别结果。""" scenario_key: Optional[str] = None confidence: float = 0.0 raw: str = "" error: str = "" class ActionResponse(BaseModel): """处置动作响应。""" id: str session_id: str action_index: int action_type: str adapter: str risk_level: str title: str description: str status: str payload: Optional[dict] = None result: Optional[dict] = None error: Optional[str] = None approved_by: Optional[str] = None approved_at: Optional[str] = None class ApprovalTicketResponse(BaseModel): """审批单响应。""" id: str action_id: str session_id: str approver_id: Optional[str] = None channel: str status: str reason: Optional[str] = None decision_note: Optional[str] = None decided_at: Optional[str] = None class SessionResponse(BaseModel): """自动化会话响应。""" id: str conversation_id: Optional[str] = None employee_id: str agent_id: Optional[str] = None scenario_key: Optional[str] = None status: str mode: str confidence: float title: str intent: Optional[dict] = None current_action_id: Optional[str] = None auto_close_at: Optional[str] = None resolved_at: Optional[str] = None closed_by: Optional[str] = None meta: Optional[dict] = None # 复杂场景重构:暂停时间戳 paused_at: Optional[str] = None actions: List[ActionResponse] = Field(default_factory=list) approval: Optional[ApprovalTicketResponse] = None created_at: Optional[str] = None updated_at: Optional[str] = None class ScenarioConfigResponse(BaseModel): """场景配置响应。""" id: str scenario_key: str name: str description: str enabled: bool trigger_conditions: Optional[dict] = None actions: Optional[list] = None approval_strategy: Optional[dict] = None current_version_id: Optional[str] = None class RuleVersionResponse(BaseModel): """规则版本响应。""" id: str scenario_key: str version: int content: Optional[dict] = None status: str canary_percent: int created_by: Optional[str] = None remark: str created_at: Optional[str] = None class AutoMetricsResponse(BaseModel): """自动化看板指标响应。""" total_sessions: int = 0 resolved_sessions: int = 0 handoff_sessions: int = 0 error_sessions: int = 0 auto_executed_actions: int = 0 approval_required_actions: int = 0 by_scenario: Dict[str, int] = Field(default_factory=dict) # -------------------------------------------------------------------------- # 序列化辅助 # -------------------------------------------------------------------------- def _iso(dt: Optional[datetime]) -> Optional[str]: """将 datetime 转为 ISO 字符串(None 透传)。""" return dt.isoformat() if dt else None def serialize_action(action: Any) -> ActionResponse: """将 AutoAction ORM 对象序列化为响应模型。""" return ActionResponse( id=action.id, session_id=action.session_id, action_index=action.action_index, action_type=action.action_type, adapter=action.adapter, risk_level=action.risk_level, title=action.title, description=action.description, status=action.status, payload=action.payload, result=action.result, error=action.error, approved_by=action.approved_by, approved_at=_iso(action.approved_at), ) def serialize_approval(ticket: Any) -> ApprovalTicketResponse: """将 ApprovalTicket ORM 对象序列化为响应模型。""" return ApprovalTicketResponse( id=ticket.id, action_id=ticket.action_id, session_id=ticket.session_id, approver_id=ticket.approver_id, channel=ticket.channel, status=ticket.status, reason=ticket.reason, decision_note=ticket.decision_note, decided_at=_iso(ticket.decided_at), ) def serialize_session( session: Any, actions: Optional[List[Any]] = None, ticket: Optional[Any] = None, ) -> SessionResponse: """将 AutoSession ORM 对象序列化为响应模型。""" return SessionResponse( id=session.id, conversation_id=session.conversation_id, employee_id=session.employee_id, agent_id=session.agent_id, scenario_key=session.scenario_key, status=session.status, mode=session.mode, confidence=session.confidence, title=session.title, intent=session.intent, current_action_id=session.current_action_id, auto_close_at=_iso(session.auto_close_at), resolved_at=_iso(session.resolved_at), closed_by=session.closed_by, meta=session.meta, paused_at=_iso(session.paused_at), actions=[serialize_action(a) for a in (actions or [])], approval=serialize_approval(ticket) if ticket else None, created_at=_iso(session.created_at), updated_at=_iso(session.updated_at), ) # =========================================================================== # 复杂场景重构第一阶段 — 新增 Schema # =========================================================================== # -------------------------------------------------------------------------- # 全局意图识别结果(扩展 IntentResult) # -------------------------------------------------------------------------- class GlobalIntentResult(BaseModel): """全局意图识别结果。""" global_intent: Optional[str] = None # pause / resume_task / correct / supplement / null scenario_key: Optional[str] = None # 未命中全局意图时走场景识别 confidence: float = 0.0 corrected_field: Optional[str] = None # CORRECT: 更正的字段名 old_value: Optional[str] = None # CORRECT: 旧值 new_value: Optional[str] = None # CORRECT: 新值 supplement_field: Optional[str] = None # SUPPLEMENT: 补充的字段名 supplement_value: Optional[str] = None # SUPPLEMENT: 补充的值 raw: str = "" error: str = "" # -------------------------------------------------------------------------- # 请求模型(复杂场景重构) # -------------------------------------------------------------------------- class PauseRequest(BaseModel): """暂停会话请求(通常由意图识别触发,也可直接调用)。""" reason: Optional[str] = None class ResumeRequest(BaseModel): """恢复会话请求。""" session_id: Optional[str] = None # 多任务时指定恢复哪个;None 则自动选择唯一的 class CorrectRequest(BaseModel): """信息更正请求。""" field: str = Field(..., description="更正的字段名") new_value: str = Field(..., description="新值") old_value: Optional[str] = None class SupplementRequest(BaseModel): """信息补充请求。""" field: str = Field(..., description="补充的字段名") value: str = Field(..., description="补充的值") class AgentResumeRequest(BaseModel): """坐席代恢复请求。""" note: Optional[str] = None class AgentCloseRequest(BaseModel): """坐席关闭会话请求。""" note: Optional[str] = None # -------------------------------------------------------------------------- # 响应模型(复杂场景重构) # -------------------------------------------------------------------------- class InformationItemResponse(BaseModel): """信息项响应。""" id: str session_id: str name: str value: str modifiers: List[str] = Field(default_factory=list) is_filled: bool is_locked: bool version: int update_history: List[dict] = Field(default_factory=list) updated_at: Optional[str] = None class ResumePointResponse(BaseModel): """恢复点响应。""" session_id: str title: str scenario_key: Optional[str] = None current_step: str paused_at: Optional[str] = None pending_items: List[str] = Field(default_factory=list) info_items: List[InformationItemResponse] = Field(default_factory=list) class PausedSessionItem(BaseModel): """暂停会话列表项。""" session_id: str title: str scenario_key: Optional[str] = None paused_at: Optional[str] = None paused_duration: str = "" # 如 "2h 15min" # -------------------------------------------------------------------------- # 序列化辅助(复杂场景重构) # -------------------------------------------------------------------------- def serialize_information_item(item: Any) -> InformationItemResponse: """将 InformationItem ORM 对象序列化为响应模型。""" return InformationItemResponse( id=item.id, session_id=item.session_id, name=item.name, value=item.value, modifiers=item.modifiers or [], is_filled=item.is_filled, is_locked=item.is_locked, version=item.version, update_history=item.update_history or [], updated_at=_iso(item.updated_at), ) # =========================================================================== # 复杂场景重构第二阶段 — P2/P3 新增 Schema # =========================================================================== # -------------------------------------------------------------------------- # P3 请求模型 # -------------------------------------------------------------------------- class BatchCorrectRequest(BaseModel): """批量更正请求。""" corrections: List[dict] = Field( ..., description="更正列表 [{field, new_value, old_value?}, ...]" ) reason: Optional[str] = Field(None, description="更正备注") class UndoCorrectionRequest(BaseModel): """撤销更正请求。""" pass # 无参数,撤销最近一次更正 class VersionDiffRequest(BaseModel): """版本对比请求。""" v1: int = Field(..., description="版本号1") v2: int = Field(..., description="版本号2") # -------------------------------------------------------------------------- # P3 响应模型 # -------------------------------------------------------------------------- class BatchCorrectResponse(BaseModel): """批量更正响应。""" corrected_items: List[dict] = Field(default_factory=list) snapshot_id: int dependency_warnings: List[dict] = Field(default_factory=list) class UndoCorrectionResponse(BaseModel): """撤销更正响应。""" undone_items: List[str] = Field(default_factory=list) restored_values: Dict[str, str] = Field(default_factory=dict) snapshot_id: int remaining_undo_count: int = 5 class CorrectionHistoryResponse(BaseModel): """更正历史响应。""" history: List[dict] = Field(default_factory=list) class VersionChainResponse(BaseModel): """版本链响应。""" item_key: str chain: List[dict] = Field(default_factory=list) class VersionDiffResponse(BaseModel): """版本对比响应。""" item_key: str v1: int v1_value: str v2: int v2_value: str changed: bool # -------------------------------------------------------------------------- # P2 响应模型 # -------------------------------------------------------------------------- class CompressionLogItem(BaseModel): """压缩日志项。""" id: int session_id: str tokens_before: int tokens_after: int compression_ratio: float task_node: Optional[str] = None duration_ms: int compression_level: int summary: Optional[str] = None created_at: Optional[str] = None class CompressionLogListResponse(BaseModel): """压缩日志列表响应。""" logs: List[CompressionLogItem] = Field(default_factory=list) total: int = 0