HowTo文档
如何在 XSwitch 中实现满意度评价
在语音客服的呼入和呼出场景中,常常需要客户对当前服务进行满意度评价,来收集客户对本次服务的满意度,进而对整体服务过程进行调整与优化。
XSwitch支持客户在与客服沟通完成后,客服主动挂断后,进行满意度评价。满意度评价大致流程如下:
- 客服主动挂断通话,客户通话通道转入
myd
路由。 - XSwitch向客户播放欢迎音,说明各个满意度等级对应的DTMF按键。(如满意请按1,不满意请按2)。
- 客户根据自身体验与受服务程度给出此次的满意度等级,通过DTMF按键传给XSwitch。
- XSwitch将客户评价的满意度等级进行存储。(存储方式有:存入数据库、给某个地址发送HTTP消息、ESL Event等)。
满意度路由
XSwitch已为您预设一条专门用作满意度评价的路由:
- 名称:
myd
- 呼叫源:
分机
- 被叫字冠:
myd
- 目的地类型:系统
- 内容:
lua xui/scripts/grade_ivr.lua
XSwitch默认满意度评级为:
- 1:满意
- 2:一般
- 3:不满意
呼入进行满意度评价
假设您的呼入路由为:
- 名称:
call-in
- 呼叫源:
分机
- 被叫字冠:
1
- 最大号长:
4
- 目的地类型:
本地分机
那么您拨打所有1
开头的4位纯数字号码均会进入该路由,并桥接至同号码分机上。
您可在本路由的【动作】内添加以下两个动作即可:
动作1:
- 名称:
set
- 模块参数:
hangup_after_bridge=false
动作2:
- 名称:
set
- 模块参数:
transfer_after_bridge=myd:XML:context-1
呼出进行满意度评价
通过路由直接外呼
假设您的呼入路由为:
- 名称:
call-out
- 呼叫源:
分机
- 被叫字冠:
0
- 最大号长:
12
- 目的地类型:
网关
那么您拨打所有0
开头的12位纯数字号码均会进入该路由,并通过网关桥接至对应号码。
您可在本路由的【动作】内添加以下两个动作即可:
动作1:
- 名称:
export
- 模块参数:
hangup_after_bridge=false
动作2:
- 名称:
export
- 模块参数:
nolocal:transfer_after_bridge=myd:XML:context-1
通过XCC接口呼出
为避免出现无效满意度评价出现,推荐您使用如下方式实现满意度评价:
XNode.Dial发起外呼
--> 客户应答
--> 客服与客户交互
--> XNode.Transfer将客户转移至myd路由
--> 客服自动挂机
--> 客户满意度评价
--> 获取满意度评价结果
其中XNode.Transfer
示例如下:
{ "jsonrpc": "2.0", "method": "XNode.Transfer", "id": "f6f8a912-3757-469c-a14f-bd512e51ad5b", "params": { "ctrl_uuid": "41f54dd7-dedb-452b-956f-86c911f62dc6", "uuid": "f6f8a912-3757-469c-a14f-bd512e51ad5b", "extension": "myd", "dialplan": "XML", "context": "context-1" } }
其中uuid
必须为客户UUID,id
为uuidv4
格式uuid。
通过REST API呼出
如何使用REST API呼出参见REST API呼出,假设您使用如下消息进行呼出,则表示XSwitch先呼叫分机号为1000
的客服,同时进行录音,再重路由到18666666666
号码上。
{ "autoAnswer": "true", "destNumber": "1000", "apps": [ { "app": "set", "args": "RECORD_ANSWER_REQ=true" }, { "app": "record_session", "args": "/tmp/test.wav" }, { "app": "transfer", "args": "18666666666" } ] }
18666666666
号码会匹配到您预先设置好的路由(假设路由名称为call-out
)。
您需在call-out
路由内添加以下两个动作:
动作1:
- 名称:
export
- 模块参数:
hangup_after_bridge=false
动作2:
- 名称:
export
- 模块参数:
nolocal:transfer_after_bridge=myd:XML:context-1
完成以上配置后,在1000
客服与18666666666
客户沟通完成后,1000
客服主动挂机后,18666666666
客户将路由至myd
路由进行满意度评价。
获取满意度评价结果
ESL Event
推荐使用XCC接收事件,在【对接】--【XCC】--【xcc】选择XCC-BINDINGS
界面点击【添加】按钮,内容如下:
- 域:
XCC-BINDINGS
- 键:
CUSTOM:100
- 值:
grade::grade
配置完成后点击【重载】按钮。
这样您就可以在cn.xswitch.ctrl.event
节点内收到满意度评价消息。
HTTP消息
修改myd
路由中的内容为lua xui/scripts/grade_ivr.lua url http://192.168.31.98:9000/grade
来实现将满意度评价通过HTTP消息推送至您指定的接口内。
数据库
修改myd
路由中的内容为lua xui/scripts/grade_ivr.lua database
来实现将满意度评价存储到数据库内。
若您想查询数据库内的满意度评价结果,请联系我们。
修改满意度评级
若您觉得我们预设的满意度评级不够精准,您也可以设置您自己的满意度评级,不过需进行以下步骤才可实现。
修改评级音频
您需新建一个满意度评级的提示音,并命名为grade_welcome.wav
。将XSwitch容器内的/usr/local/freeswitch/sounds/zh/cn/link/xswitch/grade_welcome.wav
替换为最新的grade_welcome.wav
文件。
以上方式在XSwitch容器重启将失效,需重新替换grade_welcome.wav
文件。
修改lua脚本
lua脚本见附件,其中收集用户DTMF按键信息的核心功能为:
local grade = session:playAndGetDigits( 1, 1, 3, 5000, "#", sound_path .. "grade_welcome.wav", sound_path .. "grade_invalid.wav", "[1-3]", 5000)
若您修改后有效满意度评级为1-5,那么请修改为如下形式:
local grade = session:playAndGetDigits( 1, 1, 3, 5000, "#", sound_path .. "grade_welcome.wav", sound_path .. "grade_invalid.wav", "[1-5]", 5000)
修改有效值校验逻辑,原始代码如下:
if grade == "invalid" or grade == "1" or grade == "2" or grade == "3" then
同样,修改后代码如下:
if grade == "invalid" or grade == "1" or grade == "2" or grade == "3" or grade == "4" or grade == "5" then
修改完成后,将新的grade_ivr.lua
上传至XSwitch容器内/usr/local/freeswitch/xui/lua/xui/xui/scripts
目录下。即刻生效。
永久化处理
上述两个章节,无论修改评级音频还是修改grade_ivr.lua
均为将修改后文件上传至XSwitch容器内。在XSwitch容器重启后,文件将恢复成初始状态,之前修改无效。
因此您可通过在docker-compose.yml
文件内的volumes
下新增挂载配置项,将grade_welcome.wav
和grade_ivr.lua
挂载到XSwitch容器内的对应位置。这样,新文件将不再受XSwitch重启的影响。
若您有任何疑问,请及时联系我们。
附件
-- for test local cur_dir = debug.getinfo(1).source; cur_dir = string.gsub(debug.getinfo(1).source, "^@(.+/)[^/]+$", "%1") if cur_dir:sub(1,1) == '/' then -- plain Lua package.path = package.path .. ";/etc/xtra/?.lua" package.path = package.path .. ";" .. cur_dir .. "?.lua" package.path = package.path .. ";" .. cur_dir .. "vendor/?.lua" end local utils = require 'utils' local config = require 'xtra_config' local xdb = require 'xdb' local config = require 'xtra_config' local utils = require 'utils' local xdb = require 'xdb' local api = freeswitch.API() local db_handle = xdb.new() db_handle:connect(config.dsn) if config.db_auto_connect then db_handle:connect(config.dsn) end local sound_path = "xswitch/" local post_type = argv[1] local post_url = argv[2] local result = {} result.grade_level = 0 local curl = freeswitch.cURL() local json = freeswitch.JSON() session:answer() session:streamFile("silence_stream://2000") local grade = session:playAndGetDigits( 1, 1, 3, 5000, "#", sound_path .. "grade_welcome.wav", sound_path .. "grade_invalid.wav", "[1-3]", 5000) if grade == '' then grade = 'invalid' end local uuid = session:getVariable("uuid") local caller_id_number = session:getVariable("caller_id_number") local original_destination_number = session:getVariable("original_destination_number") local cc_agent = session:getVariable("cc_agent") local queue_name = session:getVariable("cc_queue") if grade == "invalid" or grade == "1" or grade == "2" or grade == "3" then session:setVariable("grade", grade) local uuid = session:getVariable("uuid") if post_type and post_type == "database" then result.grade_level = grade result.uuid = uuid result.caller_id_number = caller_id_number result.destination_number = original_destination_number result.agent = cc_agent result.queue = queue_name db_handle:create_return_id('grades', result) elseif post_type and post_type == "url" then if post_url then result.grade_level = grade result.uuid = uuid result.destination_number = original_destination_number result.caller_id_number = caller_id_number result.agent = cc_agent result.queue = queue_name local ret = curl:post({url = post_url, headers = {['X-Tested-By'] = 'XUI-GRADE'}, data = utils.json_encode(result), dataType = 'application/json' }) end else local e = freeswitch.Event("CUSTOM", "grade::grade") e:addHeader("subclass", "grade") e:addHeader("grade_level", grade) e:addHeader("timestamp", os.date("%Y-%m-%d %H:%M:%S")) e:addHeader("uuid", uuid) e:addHeader("caller_id_number", caller_id_number) e:addHeader("original_destination_number", original_destination_number) e:addHeader("cc_agent", cc_agent) e:addHeader("cc_queue", queue_name) e:fire() end end session:streamFile(sound_path .. "grade_bye.wav") session:streamFile("silence_stream://1000") session:hangup()