Files
wecom_it_smart_desk/backend/app/services/funny_phrase_service.py
T

158 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# 企微IT智能服务台 — 趣味话术服务
# =============================================================================
# 说明:管理各场景的趣味话术,包括:
# 1. 根据触发场景返回对应话术
# 2. 从 funny_phrases 表读取话术配置
# 3. 支持按员工 VIP 等级自动切换话术(VIP → 正式版话术)
# 4. 预置 6 种场景的默认话术
# =============================================================================
import logging
import random
from typing import Optional
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.funny_phrase import FunnyPhrase
logger = logging.getLogger(__name__)
class FunnyPhraseService:
"""趣味话术服务。
根据触发场景返回对应的趣味话术。
支持后台动态修改话术内容(通过 funny_phrases 表)。
"""
# 默认话术(当数据库未配置时使用,和 PRD 一致)
DEFAULT_PHRASES = {
"shake": "大哥,俺这就去摇人,稍等...",
"keyword": "收到!这就帮您摇位大神来",
"waiting": "人还在路上,别急别急~",
"connected": "人摇来了!IT坐席为您服务",
"timeout": "坐席都在忙,不过AI还在呢,要不先聊聊?我再继续摇",
"vip": "这就帮您安排专家,请稍候",
}
def __init__(self, db: AsyncSession):
"""初始化趣味话术服务。
Args:
db: 异步数据库会话
"""
self.db = db
# --------------------------------------------------------------------------
# 获取话术
# --------------------------------------------------------------------------
async def get_phrase(
self, scene: str, is_vip: bool = False
) -> str:
"""根据触发场景获取趣味话术。
优先从 funny_phrases 表读取,如果未配置则使用默认话术。
VIP 员工自动使用 "vip" 场景的话术。
场景说明:
- click_shake / shake: 点击摇人按钮
- keyword: 关键词触发转人工
- waiting: 排队等待(30秒无人接单)
- connected: 坐席接入
- timeout: 等待超时(2分钟)
- vip: VIP员工专用
Args:
scene: 触发场景(shake/keyword/waiting/connected/timeout/vip
is_vip: 是否 VIP 员工(VIP 优先使用 vip 场景话术)
Returns:
str: 话术内容
"""
# VIP 员工优先使用 vip 场景话术
actual_scene = scene
if is_vip and scene != "vip":
# 尝试获取 VIP 话术,如果不存在则回退到原场景
vip_phrase = await self._get_phrase_from_db("vip")
if vip_phrase:
logger.debug(f"VIP员工使用专属话术: scene=vip")
return vip_phrase
# 从数据库获取对应场景的话术
phrase = await self._get_phrase_from_db(actual_scene)
if phrase:
return phrase
# 数据库未配置,使用默认话术
default = self.DEFAULT_PHRASES.get(actual_scene, "请稍候...")
logger.debug(f"使用默认话术: scene={actual_scene}")
return default
# --------------------------------------------------------------------------
# 从数据库获取话术
# --------------------------------------------------------------------------
async def _get_phrase_from_db(self, scene: str) -> Optional[str]:
"""从 funny_phrases 表获取指定场景的话术。
同一场景可能有多条话术,随机返回一条(增加趣味性)。
只返回 is_active=True 的话术。
Args:
scene: 触发场景
Returns:
Optional[str]: 话术内容,未找到返回 None
"""
stmt = (
select(FunnyPhrase)
.where(
FunnyPhrase.scene == scene,
FunnyPhrase.is_active == True,
)
.order_by(FunnyPhrase.sort_order)
)
result = await self.db.execute(stmt)
phrases = list(result.scalars().all())
if not phrases:
return None
# 随机选一条(如果有多个话术,增加随机趣味性)
chosen = random.choice(phrases)
return chosen.content
# --------------------------------------------------------------------------
# 获取所有场景的话术
# --------------------------------------------------------------------------
async def get_all_phrases(self) -> dict:
"""获取所有场景的话术。
用于后台管理页面展示当前话术配置。
Returns:
dict: 按场景分组的话术字典
"""
stmt = select(FunnyPhrase).order_by(
FunnyPhrase.scene, FunnyPhrase.sort_order
)
result = await self.db.execute(stmt)
phrases = list(result.scalars().all())
# 按场景分组
grouped: dict = {}
for phrase in phrases:
if phrase.scene not in grouped:
grouped[phrase.scene] = []
grouped[phrase.scene].append({
"id": str(phrase.id),
"content": phrase.content,
"tone": phrase.tone,
"sort_order": phrase.sort_order,
"is_active": phrase.is_active,
})
return grouped