语音识别(以下称为ASR,自动语音识别)用于创建漫游器和/或IVR,以及用于自动轮询。 Voximplant使用“好公司”提供的ASR-Google识别可以快速且高精度地工作,但是……一如既往,有一个警告。 一个人甚至可以用短句暂停,我们需要保证ASR不会在回答结束时停顿。 如果ASR认为该人已经完成讲话,则在“答案”之后,脚本可能会包含语音合成以及以下问题-同时,该人将继续讲话并获得不良的用户体验:bot / IVR会打断该人。 今天,我们将告诉您如何处理此问题,以使您的用户在与铁助手进行交流时不会感到烦恼。
概念图
目的是提出一个问题并倾听一个人,而不会打扰并等待他的回答结束。 ASR由一个
单独的模块表示,该
模块中有一个
ASR.Result事件-当一个人说完话就会触发。 Google的ASR的详细信息是ASR。带有识别文本的结果会在一个人停顿至少一会儿后返回,并且Google决定该短语已被识别并完成。
要使一个人有机会暂停,可以使用
ASR.InterimResult事件。 其中,在识别过程中,ASR返回所有“原始”文本,并根据上下文对其进行更正和更改-依此类推,直到触发ASR.Result。 因此,ASR.InterimResult事件
表示一个人当前正在说些什么 。 我们将只关注他,看看不会持续多久。 并从ASR.Result接收中间识别的文本-添加。
一般而言,它将如下所示:
asr.addEventListener(ASREvents.InterimResult, e => { clearTimeout(timer) timer = setTimeout(stop, 3000) }) asr.addEventListener(ASREvents.Result, e => { answer += " " + e.text }) function stop(){
我们揭示了本质。 计时器
要在暂停时正常工作,您可以创建一个特殊的对象:
timeouts = { silence: null, pause: null, duration: null }
提出问题后,一个人经常思考几秒钟。 最好在开始的6-8秒内将计时器设置为静音,我们将计时器ID保存在
timeouts.silence参数中。
答案中间的停顿在3-4秒内是最佳的,因此一个人可以思考,但在完成后并没有遭受期望。 这是
timeouts.pause参数。
如果我们不希望对方讲话太长时间,则整个答案的通用计时器
-timeouts.duration-非常有用。 当有人坐在嘈杂的房间中并带有背景声音时,它也可以保护我们免受客户讲话的影响。 以及当我们到达另一个与我们的机器人围成一圈交谈的机器人的情况下。
因此,在脚本的开头,我们插入ASR模块,声明变量,并创建一个
超时对象:
require(Modules.ASR) let call, asr, speech = "" timeouts = { silence: null, pause: null, duration: null }
来电
当传入呼叫到达脚本中时,将
触发AppEvents.CallAlerting事件。 让我们为该事件创建一个处理程序:接听电话,打招呼,在问候语之后开始识别。 让我们从一个问题的中间打扰一下机器人(详细信息-进一步说明)。
处理程序AppEvents.CallAlerting VoxEngine.addEventListener(AppEvents.CallAlerting, e => { call = e.call
可以看出,
调用了
startASR和
startSilenceAndDurationTimeouts函数-
让我们看看这是什么以及为什么。
识别和超时
识别是在
startASR功能中实现的。 它创建一个ASR实例并将人的声音定向到该实例;它还包含
ASREvents.InterimResult和
ASREvents.Result事件的事件处理程序。 如上所述,在这里我们将ASR.InterimResult视为一个人在说话的信号。 此事件的处理程序清除以前创建的超时,为
timeouts.pause设置一个新值
,最后停止合成语音(这是人可以中断机器人的方式)。 ASREvents.Result处理程序仅将所有结果响应串联在
语音变量中。 具体而言,在这种情况下,不会以任何方式使用
语音 ,但是您可以
将其传输到后端,例如,如果需要的话。
startASR function startASR() { asr = VoxEngine.createASR({ lang: ASRLanguage.RUSSIAN_RU, interimResults: true }) asr.addEventListener(ASREvents.InterimResult, e => { clearTimeout(timeouts.pause) clearTimeout(timeouts.silence) timeouts.pause = setTimeout(speechAnalysis, 3000) call.stopPlayback() }) asr.addEventListener(ASREvents.Result, e => {
函数
startSilenceAndDurationTimeouts ...写入相应计时器的值:
function startSilenceAndDurationTimeouts() { timeouts.silence = setTimeout(speechAnalysis, 8000) timeouts.duration = setTimeout(speechAnalysis, 30000) }
还有更多功能
speechAnalysis停止识别并从
语音 (从
ASREvents.Result获得)中解析文本。 如果没有文字,那么我们重复这个问题; 如果有文字,请客气地告别,然后挂断电话。
语音分析 function speechAnalysis() {
handleSilence负责重复该问题:
function handleSilence() { call.say(", . , , ?", Language.RU_RUSSIAN_FEMALE)
最后,一个帮助程序功能停止ASR:
function stopASR() { asr.stop() call.removeEventListener(CallEvents.PlaybackFinished) clearTimeout(timeouts.duration) }
一起
脚本清单 | require(Modules.ASR) |
| |
| let call, |
| asr, |
| speech = "" |
| |
| timeouts = { |
| silence: null, |
| pause: null, |
| duration: null |
| } |
| |
| // CallAlerting , |
| VoxEngine.addEventListener(AppEvents.CallAlerting, e => { |
| |
| call = e.call |
| |
| // . Connected |
| call.answer() |
| call.addEventListener(CallEvents.Connected, e => { |
| call.say(", . , , ?", Language.RU_RUSSIAN_FEMALE) |
| |
| // 4 |
| setTimeout(startASR, 4000) |
| // |
| call.addEventListener(CallEvents.PlaybackFinished, startSilenceAndDurationTimeouts) |
| }); |
| call.addEventListener(CallEvents.Disconnected, e => { |
| VoxEngine.terminate() |
| }) |
| }) |
| |
| function startASR() { |
| asr = VoxEngine.createASR({ |
| lang: ASRLanguage.RUSSIAN_RU, |
| interimResults: true |
| }) |
| |
| asr.addEventListener(ASREvents.InterimResult, e => { |
| clearTimeout(timeouts.pause) |
| clearTimeout(timeouts.silence) |
| |
| timeouts.pause = setTimeout(speechAnalysis, 3000) |
| call.stopPlayback() |
| }) |
| |
| asr.addEventListener(ASREvents.Result, e => { |
| // |
| speech += " " + e.text |
| }) |
| |
| // ASR |
| call.sendMediaTo(asr) |
| } |
| |
| function startSilenceAndDurationTimeouts() { |
| timeouts.silence = setTimeout(speechAnalysis, 8000) |
| timeouts.duration = setTimeout(speechAnalysis, 30000) |
| } |
| |
| function speechAnalysis() { |
| // ASR |
| stopASR() |
| const cleanText = speech.trim().toLowerCase() |
| |
| if (!cleanText.length) { |
| // , , |
| // .. , , , |
| handleSilence() |
| } else { |
| call.say( |
| " ! !", |
| Language.RU_RUSSIAN_FEMALE |
| ) |
| call.addEventListener(CallEvents.PlaybackFinished, () => { |
| call.removeEventListener(CallEvents.PlaybackFinished) |
| call.hangup() |
| }) |
| } |
| } |
| |
| function handleSilence() { |
| call.say(", . , , ?", Language.RU_RUSSIAN_FEMALE) |
| |
| // 3 |
| setTimeout(startASR, 3000) |
| call.addEventListener(CallEvents.PlaybackFinished, startSilenceAndDurationTimeouts) |
| } |
| |
| function stopASR() { |
| asr.stop() |
| call.removeEventListener(CallEvents.PlaybackFinished) |
| clearTimeout(timeouts.duration) |
| } |
最终方案显示了如何“使”直线型机器人“高贵”,并给它增加一些技巧和注意力。 当然,这种方法不是唯一可行的方法,因此,如果您对如何优雅地完成机器人与人之间通常的交互有任何想法,请分享评论。 对于那些想要更高级的知识而又突然没有阅读我们关于DialogFlow的教程的人,我们
建议您熟悉一下自己 。