Image title

振铃中央语音信箱助理

在第1 部分中,我解释了 RingCentral 云通信系统和 AI 解决方案的语音信箱功能,这些功能可用于为您的电话客户服务构建有效的虚拟语音信箱助理。我还教您如何创建和设置专用扩展,以便仅获取语音邮件和虚拟语音邮件助理的整体工作流。

在本文中,我将演练开发 Web 应用的基本步骤 – RingCentral 开发人员支持的虚拟语音邮件助手演示,它可以侦听新的语音邮件并执行以下任务。

您可能还喜欢:
Siri vs 谷歌助手 vs Alexa vs Cortana

Voicemail Data Analysis

  1. 接收语音邮件
  2. 检测垃圾邮件语音邮件
  3. 使用 SMS 消息自动回复呼叫者
  4. 抄写语音邮件
  5. 检测语音邮件的紧急性
  6. 对语音邮件内容进行分类
  7. 将支持票证(语音邮件)分配给指定的支持工程师(代理)
  8. 让座席阅读语音邮件脚本或收听原始语音邮件
  9. 允许座席通过点击拨号轻松回电或向呼叫者发送短信

关联的演示应用程序是使用 Node JS Express Web 应用程序框架构建的。因此,为了方便起见,我将使用RingCentral、猴子学习Rev AI提供的节点 JS SDK 来访问他们的服务。您可以使用上述服务提供商提供的客户端库,以您喜欢的任何编程语言轻松构建此 Web 应用后端。

为了生成和运行演示应用,您需要设置以下帐户,获取其 API 密钥和登录凭据:

  • 环中心开发人员帐户。单击此处创建免费开发人员帐户。
  • 猴子学习开发人员帐户。单击此处创建。
  • Rev.ai开发人员帐户。单击此处创建。
  • 白页专业版(又名 Ekata)开发人员帐户。单击此处创建。

注意:本文中显示的代码段较短,仅供说明我建议你从这里下载整个项目。

获取新的语音邮件通知

让我们开始使用语音信箱助理的关键功能 – 侦听到达语音信箱的新语音邮件。此功能可以使用PubNub 通知Webhooks 通知实现。

我将使用 RingCentral Webhooks 通知方法订阅新的语音邮件事件通知。

var eventFilters = ['/restapi/v1.0/account/~/extension/~/voicemail']
platform.post('/subscription',
  {
    eventFilters: eventFilters,
    deliveryMode: {
      transportType: 'WebHook',
      address: 'https://[c1969441.ngrok.io]/webhookcallback'
      }
  })
  .then(function(response) {
    console.log("Ready to receive voicemail notification.")
})

有关完整代码,请参阅webhooks.js模块。我将跳过有关 RingCentral Webhook 的工作原理的说明,但如果您不熟悉 RingCentral Webhook 通知,请阅读此博客以了解更多信息。

由于我希望在我的本地计算机上运行该应用程序,我使用ngrok工具获取回调地址 [https://c1969441.ngrok.io]。如果事件通知订阅已成功订阅,我将在向上述指定地址发出后请求中收到通知。

收到通知时,我将分析数据以获取正文JSON 对象、所有者 Id(订阅通知的用户的扩展 ID)和订阅 Id。然后,我调用进程语音信箱通知()函数来处理数据。我使用分机 Id查找应处理语音邮件通知的用户,并使用订阅 Id验证该消息是否属于我订阅的事件。

app.post('/webhookcallback', function(req, res) {
  if(req.headers.hasOwnProperty("validation-token")) {
    res.setHeader('Validation-Token', req.headers['validation-token']);
    res.statusCode = 200;
    res.end();
  }else{
    var data = []
    req.on('data', function(chunk) {
      data.push(chunk);
    })
    .on('end', function() {
      data = Buffer.concat(data).toString();
      var jsonObj = JSON.parse(data)
      var body = jsonObj.body
      var extensionId = jsonObj.ownerId
      var subscriptionId = jsonObj.subscriptionId
      processVoicemailNotification(body,extensionId,subscriptionId)
    });
  }
})
function processVoicemailNotification(body, extId, subscriptionId){
  var index = getUserIndexByExtensionId(extId)
  if (index < 0)
    return
  if (users[index].getSubscriptionId() == subscriptionId)
    users[index].processVoicemailNotification(body)
  else
    console.log("not my subscription")
}

让我们继续分析语音邮件通知的正文,以提取一些重要数据:

{
  "body": {
    id: 1054xxxx,
    from: {
      phoneNumber: '+1650224xxxx',
      location: 'Mountain View, CA'
    },
    type: 'VoiceMail',
    readStatus: 'Unread',
    attachments: [ 
      {
        id: 1054xxxx,
        uri:
'https://media.ringcentral.com/restapi/v1.0/account/~/extension/~/message-store/1054xxxx/content/1054xxxx',
        type: 'AudioRecording',
        contentType: 'audio/mpeg',
        vmDuration: 11
    },{
        id: 2406yyyy,
        uri: 'https://media

com/restapi/v1.0/帐户/\/扩展/*/消息存储/1054xxxx/内容/2406yyy’,
类型:”音频脚本”,
内容类型:”文本/纯”,
vm 持续时间: 11,
文件名:”转录”
} ],
最后修改时间: ‘2019-06-16T22:17:41.584Z’,
vmTranscription 状态:”已完成”
}
}

我提取数据并将其保存在对象中,如下所示:

var item = {}
if (body.from.hasOwnProperty("phoneNumber")){
  item['fromNumber'] = body.from.phoneNumber
  if (body.from.hasOwnProperty('name'))
    item['fromName'] = body.from.name
  else
    item['fromName'] = "Unknown"
}else{
  // Just for demo purpose. Use predefined scam numbers
  if (index >= samplePhoneNumber.length)
    index = 0
  item['fromNumber'] = samplePhoneNumber[index]
  item['fromName'] = "Unknown"
  index++
}
item['toNumber'] = body.to[0].phoneNumber
item['toName'] = body.to[0].name
var timestamp = new Date(body.lastModifiedTime).getTime()
item['date'] = timestamp
item['id'] = body.id

我需要检测呼叫者的电话号码是否存在。这是必要的,因为如果呼叫是匿名的,则”from.phone 号码”可能会丢失。在这个演示中,我预定义了一个诈骗电话号码列表,并用它来模拟诈骗电话,如果呼叫是匿名的。在实际应用程序中,我们仍可以对匿名呼叫进行语音邮件分析,并尝试检测呼叫者是否在语音邮件中留下回叫号码。

识别呼叫者

使用呼叫者的电话号码,我查询到我的客户数据库以查找客户并检索客户的信息,如名字和姓氏以及电话号码类型(即移动)。在实际应用程序中,您可以连接到 CRM 数据库并提取座席在向客户进行回拨时应注意的任何必要的客户信息。

var query = "SELECT first_name, last_name, phone_number_type FROM customers WHERE phone_number='" + phoneNumber + "'"

为了演示目的,我创建了一个小型客户数据库,下面仅提供基本客户信息:

customer_id = 名字 = 姓氏 = 电话_号码 = 电话号码_类型

如果呼叫者是注册客户,我继续分析语音邮件。否则,我将继续检测是否垃圾邮件发送者。

诈骗语音信箱检测

正如我前面提到的,我使用 WhitePages 服务来检测电话号码信誉。

var url = "https://proapi.whitepages.com/3.0/phone_reputation?"
url += "api_key=[WHITEPAGES_PHONE_REPUTATION_APIKEY]";
url += "&phone=[phoneNumber]"
request.get(url, function(err, res, body){
  if(res.statusCode == 200 ){
    // parse the body to get phone reputation info
    var jsonObj = JSON.parse(body)
    var numberInfo = {}
    if (jsonObj.hasOwnProperty("reputation_level"))
      numberInfo['reputation_level'] = jsonObj.reputation_level
    ...
    if (jsonObj.hasOwnProperty("reputation_details"))
      numberInfo['reputation_details'] = jsonObj.reputation_details
    ...
  }
});

有关完整代码,请参阅number_analysis.js模块。

此时,我应该有足够的信息,根据信誉级别确定呼叫者是否为垃圾邮件发送者。我还使用从 WhitePages 返回的”信誉详细信息”中的”类别”标记对语音邮件源进行分类。对于注册客户的语音信箱,我使用”客户”标签。

如果信誉级别值大于 1,则我根据信誉级别使用标签(可能、高或有风险)将语音邮件标记为垃圾邮件,并且我将停止分析语音邮件

获取语音邮件脚本

如果语音信箱由 RingCentral 自动转录,我可以通过通知事件正文的附件 URI 访问语音邮件记录。但是,我需要检查语音信箱转录状态是否已完成,以及附件类型是否为”音频转录”,然后再获取脚本。

if (body.vmTranscriptionStatus == "Completed"){
  for (var attachment of body.attachments){
    if (attachment.type == "AudioTranscription"){
      platform.get(attachment.uri)
        .then(function(res) {
          return res.response().buffer();
        })
        .then(function(buffer) {
          var transcript = buffer.toString()
          item['transcript'] = transcript
        })
      break
    }
  }
}

有关完整代码,请参阅转录_engine.js模块。

为语音邮件分析做好准备

我决定使用猴子学习AI服务进行紧急检测和分类。使用 MonkeyLearn 的数据模型创建工具训练您自己的数据集非常简单。

Image title

对于紧急检测,我使用他们的演示数据模型进行演示,因为它可以根据”尽快”、”尽快”、”这是紧急”等关键字来检测紧急性。

对于分类,我训练了自己的数据集以构建用于检测以下预定义类别的数据模型:

消息 • 语音 • 会议 • 数据 • 身份验证 • 配置 • 通知 • 集成

首先,我从RingCentral 开发人员论坛收集了几百个技术问题,并把它们放在 Excel 工作表中并对其进行适当的标记,然后将它们保存在 CSV 文件中。值得注意的是,您提供的数据样本越多,分类结果就越好。

Image title

然后,我上传文件到猴子学习开始训练过程。

Image title

以下是使用 MonkeyLearn 训练数据模型的主要步骤:

  1. 选择型号类型
  2. 选择分类类型
  3. 从文件导入示例数据
  4. 构建模型
  5. 测试模型
  6. 复制模型 ID 并将其用于代码
const MonkeyLearn = require('monkeylearn')
const ml = new MonkeyLearn(process.env.MONKEYLEARN_APIKEY)
let urgency_model_id = 'cl_Aiu8dfYF'
let categorization_model_id = 'cl_zBbUZ6dU'

分析语音邮件

现在,我有语音信箱记录和我自己的数据模型,下一个任务是检测紧急性和对语音邮件进行分类。但在分析语音邮件内容之前,我先快速检查一下,看看语音信箱中是否有足够的信息来分析它我也确保语音信箱不是垃圾邮件。

var wordArr = transcript.split(" ")
if (wordArr.length > 10 && reputation_level == 1){
  analyzeVoicemail(transcript)
}

为了检测紧急性,我调用 MonkeyLearn 分类器 API,传递”紧急_model_id”和”脚本”,然后分析 API 响应以提取紧急状态(”紧急”、”不紧急”),并将置信度从 1 转换为 10。

let data = [transcript]
ml.classifiers.classify(urgency_model_id, data).then(res => {
  var body = res.body[0]
  var result = {}
  if (body.error == false){
    var classification = body.classifications[0]
    result['status'] = classification.tag_name
    var scaled = (classification.confidence * 10)
    if (classification.tag_name == "Urgent"){
     result['confidence'] = Math.ceil((scaled / 2) + 5)
    }else{
     result['confidence'] = Math.ceil(scaled / 2)
    }
  }else{
   console.log("Error: " + JSON.stringify(body))
  }
})

要对语音邮件进行分类,我调用 MonkeyLearn 分类器 API,传递”分类_model_id”和”脚本”,然后分析 API 响应以读取类别。可以有多个类别,并且每个类别都与置信度分数相关联。我遍迭代”分类”数组,并选择置信度得分最高的类别。

let data = [transcript]
ml.classifiers.classify(categorization_model_id, data).then(res => {
  var body = res.body[0]
  var result = null
  if (body.error == false){
    var confidence_score = 0
    for (var item of body.classifications){
      if (item.confidence > confidence_score){
        result = {
          category: item.tag_name,
          confidence: item.confidence
        }
        confidence_score = item.confidence
      }
    }
  }else{
    console.log("Error: " + JSON.stringify(body))
  }
})

有关完整代码,请参阅内容分析.js模块。

将支持票证分配给指定的支持工程师

假设开发人员支持团队中有几个支持工程师(代理),我根据他们的技术技能分配他们的职责,这些技能符合我上面定义的类别(分配可以从此演示应用程序的设置页面完成)。

Image title

var agentName = "Unassigned"
for (agent of settings.assigned_agents){
  for (var cat of agent.category){
    if (cat == result.category){
      var table = "voicemail_" + agent.id
      agentName = agent.name
      item['assigned'] = agent.name
      addSupportCaseToAgentDB(table, item)
      if (item.status == "Urgent" && item.confidence > 6){
        var text = "You have an urgent callback request from "
        text += item['fromNumber']  + "\n"
        text += (item['transcript'].length < 150) ? 
                 item['transcript'] : 
                 item['transcript'].substr(0, 150)
        notifyAgentBySmsMessage(thisUser, agent.id, text)
      }else{
        console.log("Not urgent. No need to alert an agent")
      }
      break;
    }
  }
}

在上面的代码块中,我遍尼访问”已分配_代理”列表,并将语音邮件类别与座席的每个分配类别进行比较。如果存在匹配项,我向该代理分配支持票证,然后将票证信息添加到数据库中。如果检测到语音邮件是紧急的,我还会发送短信通知代理。

自动回复客户短信

为了增强客户体验,我们可以立即发送回复短信,通知呼叫者我们正在处理他们的问题,并将尽快给他们回电。

要发送回复短信,我只需要确保来电者的电话号码是一个手机号码,然后撰写相关消息,并使用 RingCentral SMS API 发送 SMS 消息。

var text = "Hi, thank you for your voice message! We will get back to you as soon as possible. For your reference, here is your case number 1234567890"
var params = {
  from: { 'phoneNumber': ourServicePhoneNumber },
  to: [{ 'phoneNumber': item['fromNumber'] }],
  text: text
  }
platform.post('/account/~/extension/~/sms', params)
  .then(function (response) {
    console.log("sent SMS")
  })
  .catch(function(e){
    console.log(e.message)
  })

Demo of a Virtual Voicemail Assistant

这是现在演示 – 你应该能够开始建立你的虚拟语音信箱助理,你想的方式,并随时进一步开发这个应用程序,使其有用的业务。

在此处了解有关我们的开发人员计划:https://developer.ringcentral.com/

进一步阅读

虚拟助理弊大于利吗?

在环中心 API 上应用 OAuth(第 2 部分)

Comments are closed.