O reconhecimento de fala (doravante - ASR, Reconhecimento Automático de Fala) é usado para criar bots e / ou IVR, bem como para pesquisas automatizadas. O Voximplant usa o ASR fornecido pela Good Corporation - o reconhecimento do Google funciona rapidamente e com alta precisão, mas ... Como sempre, há uma ressalva. Uma pessoa pode fazer uma pausa, mesmo em frases curtas, e precisamos de uma garantia de que o ASR não fará uma pausa como final da resposta. Se o ASR achar que a pessoa terminou de falar, depois da "resposta", o script poderá incluir a síntese de voz com a seguinte pergunta - ao mesmo tempo, a pessoa continuará falando e terá uma experiência ruim do usuário: o bot / IVR interrompe a pessoa. Hoje, mostraremos como lidar com isso, para que seus usuários não fiquem chateados ao se comunicar com os auxiliares de ferro.
Conceito
O objetivo é fazer uma pergunta e ouvir uma pessoa sem interromper e aguardar o final de sua resposta. O ASR é representado por um
módulo separado , onde há um evento
ASR.Result - é acionado quando uma pessoa termina de falar. Os detalhes específicos do ASR do Google são que o resultado do ASR com texto reconhecido retornará assim que uma pessoa parar por pelo menos um pouco e o Google decidir que a frase mencionada é reconhecida e concluída.
Para dar a uma pessoa a oportunidade de fazer uma pausa, você pode usar o evento
ASR.InterimResult . Nele, o ASR no processo de reconhecimento retorna todo o texto "bruto", corrigindo e alterando, dependendo do contexto - e assim por diante, até que o ASR.Result seja acionado. Portanto, o evento ASR.InterimResult
é um indicador de que uma pessoa está dizendo algo no momento . Vamos nos concentrar apenas nele e ver quanto tempo não chega. E os textos reconhecidos intermediários recebidos do ASR.Result - para adicionar.
Em termos gerais, ficará assim:
asr.addEventListener(ASREvents.InterimResult, e => { clearTimeout(timer) timer = setTimeout(stop, 3000) }) asr.addEventListener(ASREvents.Result, e => { answer += " " + e.text }) function stop(){
Nós revelamos a essência. Temporizadores
Para funcionar corretamente com pausas, você pode criar um objeto especial:
timeouts = { silence: null, pause: null, duration: null }
Depois de fazer uma pergunta, uma pessoa costuma pensar por alguns segundos. É melhor definir o timer para o silêncio logo no início de 6 a 8 segundos, salvaremos o ID do timer no parâmetro
timeouts.silence .
As pausas no meio da resposta são ótimas em 3-4 segundos, para que uma pessoa possa pensar, mas não sofreu expectativa quando terminou. Este é o parâmetro
timeouts.pause .
O cronômetro geral para toda a resposta -
timeouts.duração - é útil se não queremos que a pessoa fale por muito tempo. Também nos protege de casos em que uma pessoa está em uma sala barulhenta com vozes de fundo que serão tomadas por nós para a fala do cliente. E também nos casos em que chegamos a outro robô que fala com o robô em círculo.
Portanto, no início do script, conectamos o módulo ASR, declaramos as variáveis e criamos um objeto de
timeouts :
require(Modules.ASR) let call, asr, speech = "" timeouts = { silence: null, pause: null, duration: null }
Chamada recebida
Quando uma chamada de entrada chega no script, o evento
AppEvents.CallAlerting é acionado . Vamos criar um manipulador para este evento: atender a chamada, cumprimentar o cliente, iniciar o reconhecimento após a saudação. E vamos deixar uma pessoa interromper o robô no meio da pergunta (detalhes - um pouco mais).
manipulador AppEvents.CallAlerting VoxEngine.addEventListener(AppEvents.CallAlerting, e => { call = e.call
Pode-se observar que as funções
startASR e
startSilenceAndDurationTimeouts são chamadas -
vamos ver o que é isso e por quê.
Reconhecimento e tempos limite
O reconhecimento é implementado na função
startASR . Ele cria uma instância ASR e direciona a voz da pessoa para essa instância; também contém manipuladores de eventos para os
eventos ASREvents.InterimResult e
ASREvents.Result . Como dissemos acima, aqui tratamos o ASR.InterimResult como um sinal de que uma pessoa está falando. O manipulador deste evento limpa os tempos limites criados anteriormente, define um novo valor para
timeouts.pause e
, finalmente, interrompe a voz sintetizada (é assim que uma pessoa pode interromper o bot). O manipulador ASREvents.Result simplesmente concatena todas as respostas resultantes na variável de
fala . Especificamente, nesse cenário, a
fala não é usada de forma alguma, mas você pode
transferi-la para o back-end, por exemplo, se desejar.
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 => {
Função
startSilenceAndDurationTimeouts ... Grava os valores dos timers correspondentes:
function startSilenceAndDurationTimeouts() { timeouts.silence = setTimeout(speechAnalysis, 8000) timeouts.duration = setTimeout(speechAnalysis, 30000) }
E mais alguns recursos
speechAnalysis interrompe o reconhecimento e analisa o texto da
fala (obtido de
ASREvents.Result ). Se não houver texto, repetimos a pergunta; se houver um texto, diga educadamente adeus e desligue.
speechAnalysis function speechAnalysis() {
O
handleSilence é responsável por repetir a pergunta:
function handleSilence() { call.say(", . , , ?", Language.RU_RUSSIAN_FEMALE)
Finalmente, uma função auxiliar para parar o ASR:
function stopASR() { asr.stop() call.removeEventListener(CallEvents.PlaybackFinished) clearTimeout(timeouts.duration) }
Todos juntos
lista de scripts | 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) |
| } |
O cenário final mostra como você pode "enobrecer" um robô retilíneo, acrescentando um pouco de tato e atenção. Certamente esse método não é o único possível; portanto, se você tiver alguma ideia de como terminar com elegância a interação usual entre um bot e uma pessoa, compartilhe nos comentários. Para quem quer algo mais avançado e de repente não leu nosso tutorial sobre o DialogFlow,
recomendamos que você se familiarize .