214 lines
7.6 KiB
Plaintext
214 lines
7.6 KiB
Plaintext
|
|
# 业务路由推荐 — 类图
|
|||
|
|
|
|||
|
|
> 数据模型 + 服务类 + API 类的完整定义
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
classDiagram
|
|||
|
|
direction LR
|
|||
|
|
|
|||
|
|
%% ===== 数据模型 =====
|
|||
|
|
class BusinessContact {
|
|||
|
|
+id: int
|
|||
|
|
+name: str
|
|||
|
|
+gender: str
|
|||
|
|
+department: str
|
|||
|
|
+position: str
|
|||
|
|
+responsibility: str
|
|||
|
|
+extension: str
|
|||
|
|
+service_area: str
|
|||
|
|
+wecom_userid: str
|
|||
|
|
+avatar_url: str
|
|||
|
|
+business_category: str
|
|||
|
|
+is_active: bool
|
|||
|
|
+created_at: datetime
|
|||
|
|
+updated_at: datetime
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class RoutingEvent {
|
|||
|
|
+id: int
|
|||
|
|
+conversation_id: str
|
|||
|
|
+employee_id: str
|
|||
|
|
+message_content: str
|
|||
|
|
+business_category: str
|
|||
|
|
+routing_confidence: float
|
|||
|
|
+contact_id: int
|
|||
|
|
+contact_name: str
|
|||
|
|
+is_clicked: bool
|
|||
|
|
+created_at: datetime
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
%% ===== 服务类 =====
|
|||
|
|
class RoutingService {
|
|||
|
|
-ROUTING_PREFILTER_KEYWORDS: list~str~
|
|||
|
|
-ROUTING_KEYWORD_TO_CATEGORY: dict~str, str~
|
|||
|
|
-ROUTING_CONFIDENCE_THRESHOLD: float
|
|||
|
|
+keyword_prefilter(text: str) bool
|
|||
|
|
+async detect_routing_intent(text: str, employee_id: str) dict
|
|||
|
|
-async _call_dify_unified_intent(text: str, employee_id: str) dict
|
|||
|
|
-_fallback_routing_detect(text: str) tuple
|
|||
|
|
+async get_contact_by_category(category: str, db: AsyncSession) BusinessContact
|
|||
|
|
+async get_contacts(category: str, keyword: str, db: AsyncSession) list~BusinessContact~
|
|||
|
|
+async send_contact_card(db, conversation, employee_id, contact, reason) Message
|
|||
|
|
-async _create_routing_text_message(db, conversation, reason, category) Message
|
|||
|
|
-async _create_system_hint_message(db, conversation) Message
|
|||
|
|
+async record_routing_event(db, conversation_id, employee_id, content, category, confidence, contact) RoutingEvent
|
|||
|
|
-async _push_via_ws(employee_id, conversation, messages) None
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
%% ===== API 类 =====
|
|||
|
|
class RoutingAPI {
|
|||
|
|
+GET /api/h5/routing/contact
|
|||
|
|
+GET /api/routing/contacts
|
|||
|
|
+POST /api/conversations/{id}/send-contact-card
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class ApprovalAPI {
|
|||
|
|
+POST /api/approval/detect-intent
|
|||
|
|
-async _call_dify_approval_intent(text, employee_id) dict
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
%% ===== Schema 类 =====
|
|||
|
|
class ApprovalDetectIntentResponse {
|
|||
|
|
+is_approval_request: bool
|
|||
|
|
+confidence: float
|
|||
|
|
+approval_type: str|None
|
|||
|
|
+source: str
|
|||
|
|
+intent_type: str
|
|||
|
|
+business_category: str|None
|
|||
|
|
+routing_confidence: float
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class ContactCardResponse {
|
|||
|
|
+id: int
|
|||
|
|
+name: str
|
|||
|
|
+gender: str
|
|||
|
|
+department: str
|
|||
|
|
+position: str
|
|||
|
|
+responsibility: str
|
|||
|
|
+extension: str
|
|||
|
|
+service_area: str
|
|||
|
|
+wecom_userid: str
|
|||
|
|
+avatar_url: str
|
|||
|
|
+business_category: str
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class SendContactCardRequest {
|
|||
|
|
+contact_id: int
|
|||
|
|
+reason: str
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
%% ===== 现有类(引用) =====
|
|||
|
|
class Message {
|
|||
|
|
+id: str
|
|||
|
|
+conversation_id: str
|
|||
|
|
+sender_type: str
|
|||
|
|
+msg_type: str
|
|||
|
|
+content: str
|
|||
|
|
+extra_data: dict
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class H5AiTask {
|
|||
|
|
+async process_h5_ai_reply(conversation_id, employee_id, content, dify_conversation_id)
|
|||
|
|
-async _handle_routing(db, conversation, employee_id, content) bool
|
|||
|
|
-async _handle_byod_query(db, conversation, employee_id, content)
|
|||
|
|
-async _persist_and_push(db, conversation, employee_id, content, ...)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class WSManager {
|
|||
|
|
+async broadcast(data: dict)
|
|||
|
|
+async broadcast_to_employees(employee_ids: list~str~, data: dict)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class DifyAPI {
|
|||
|
|
POST /v1/chat-messages
|
|||
|
|
+inputs: dict
|
|||
|
|
+query: str
|
|||
|
|
+response_mode: "blocking"
|
|||
|
|
+user: str
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
%% ===== 关系 =====
|
|||
|
|
BusinessContact "1" --> RoutingEvent : contact_id FK
|
|||
|
|
|
|||
|
|
RoutingService --> BusinessContact : 查询/创建
|
|||
|
|
RoutingService --> RoutingEvent : 记录
|
|||
|
|
RoutingService --> Message : 创建contact_card消息
|
|||
|
|
RoutingService --> WSManager : WS推送
|
|||
|
|
RoutingService --> DifyAPI : 调用统一意图识别
|
|||
|
|
RoutingService ..> ApprovalDetectIntentResponse : 解析响应
|
|||
|
|
|
|||
|
|
RoutingAPI --> RoutingService : 调用
|
|||
|
|
RoutingAPI ..> ContactCardResponse : 返回
|
|||
|
|
RoutingAPI ..> SendContactCardRequest : 接收
|
|||
|
|
|
|||
|
|
ApprovalAPI ..> ApprovalDetectIntentResponse : 返回(扩展)
|
|||
|
|
ApprovalAPI --> DifyAPI : 调用(同一Dify应用)
|
|||
|
|
|
|||
|
|
H5AiTask --> RoutingService : 调用_handle_routing
|
|||
|
|
H5AiTask --> Message : 创建AI消息
|
|||
|
|
H5AiTask --> WSManager : WS推送
|
|||
|
|
|
|||
|
|
%% ===== 样式 =====
|
|||
|
|
style BusinessContact fill:#e8f5e9,stroke:#07C160
|
|||
|
|
style RoutingEvent fill:#e8f5e9,stroke:#07C160
|
|||
|
|
style RoutingService fill:#fff3e0,stroke:#ff9800
|
|||
|
|
style RoutingAPI fill:#e3f2fd,stroke:#1976d2
|
|||
|
|
style ApprovalAPI fill:#e3f2fd,stroke:#1976d2
|
|||
|
|
style ApprovalDetectIntentResponse fill:#f3e5f5,stroke:#9c27b0
|
|||
|
|
style ContactCardResponse fill:#f3e5f5,stroke:#9c27b0
|
|||
|
|
style SendContactCardRequest fill:#f3e5f5,stroke:#9c27b0
|
|||
|
|
style Message fill:#f5f5f5,stroke:#9e9e9e
|
|||
|
|
style H5AiTask fill:#fce4ec,stroke:#e91e63
|
|||
|
|
style WSManager fill:#f5f5f5,stroke:#9e9e9e
|
|||
|
|
style DifyAPI fill:#e0f7fa,stroke:#00acc1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 字段详情
|
|||
|
|
|
|||
|
|
### BusinessContact(业务联系人)
|
|||
|
|
|
|||
|
|
| 属性 | 类型 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| id | int | PK, 自增 |
|
|||
|
|
| name | str(50) | 联系人姓名 |
|
|||
|
|
| gender | str(10) | male / female |
|
|||
|
|
| department | str(100) | 部门名称(如「行政部」) |
|
|||
|
|
| position | str(100) | 岗位(如「设备管理岗」) |
|
|||
|
|
| responsibility | str(500) | 负责业务描述 |
|
|||
|
|
| extension | str(20) | 分机号 |
|
|||
|
|
| service_area | str(200) | 服务区域/办公地点 |
|
|||
|
|
| wecom_userid | str(100) | 企微用户ID(openEnterpriseChat 用) |
|
|||
|
|
| avatar_url | str(500) | 头像URL(空则用姓名首字渲染) |
|
|||
|
|
| business_category | str(50) | 行政/人力资源/财务/法务/行政-物业 |
|
|||
|
|
| is_active | bool | 是否启用(默认 true) |
|
|||
|
|
| created_at | datetime | 创建时间 |
|
|||
|
|
| updated_at | datetime | 更新时间 |
|
|||
|
|
|
|||
|
|
### RoutingEvent(路由命中统计 — P1)
|
|||
|
|
|
|||
|
|
| 属性 | 类型 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| id | int | PK, 自增 |
|
|||
|
|
| conversation_id | str(36) | FK → conversations.id |
|
|||
|
|
| employee_id | str(64) | 员工企微 UserID |
|
|||
|
|
| message_content | str(500) | 触发路由的员工消息(截断) |
|
|||
|
|
| business_category | str(50) | 识别的业务类别 |
|
|||
|
|
| routing_confidence | float | 路由置信度 |
|
|||
|
|
| contact_id | int | FK → business_contacts.id |
|
|||
|
|
| contact_name | str(50) | 联系人姓名(冗余存储) |
|
|||
|
|
| is_clicked | bool | 员工是否点击「联系TA」 |
|
|||
|
|
| created_at | datetime | 创建时间 |
|
|||
|
|
|
|||
|
|
### RoutingService 方法说明
|
|||
|
|
|
|||
|
|
| 方法 | 签名 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| keyword_prefilter | (text: str) → bool | 非IT关键词预过滤,命中返回True |
|
|||
|
|
| detect_routing_intent | async (text: str, employee_id: str) → dict | 调用Dify统一意图识别,返回路由判断结果 |
|
|||
|
|
| _call_dify_unified_intent | async (text: str, employee_id: str) → dict | 调用Dify原生API(私有方法) |
|
|||
|
|
| _fallback_routing_detect | (text: str) → tuple | Dify不可用时关键词降级兜底(私有) |
|
|||
|
|
| get_contact_by_category | async (category: str, db) → BusinessContact | 按业务类别查询第一个有效联系人 |
|
|||
|
|
| get_contacts | async (category: str, keyword: str, db) → list[BusinessContact] | 查询联系人列表(坐席端用) |
|
|||
|
|
| send_contact_card | async (db, conversation, employee_id, contact, reason) → Message | 发送名片三段式消息(路由文本+名片+系统提示) |
|
|||
|
|
| record_routing_event | async (db, ...) → RoutingEvent | 记录路由命中事件(P1统计) |
|