Robot con tacto: puede escuchar y no interrumpe

El reconocimiento de voz (en adelante, ASR, reconocimiento automático de voz) se utiliza para crear bots y / o IVR, así como para encuestas automatizadas. Voximplant utiliza el ASR proporcionado por Good Corporation: el reconocimiento de Google funciona rápidamente y con alta precisión, pero ... Como siempre, hay una advertencia. Una persona puede hacer una pausa incluso en oraciones cortas, y necesitamos una garantía de que el ASR no tomará una pausa como el final de la respuesta. Si el ASR piensa que la persona ha terminado de hablar, entonces, después de la "respuesta", el guión puede incluir síntesis de voz con la siguiente pregunta: al mismo tiempo, la persona continuará hablando y tendrá una mala experiencia de usuario: el bot / IVR interrumpe a la persona. Hoy le diremos cómo lidiar con esto, para que sus usuarios no se enojen cuando se comuniquen con los asistentes de hierro.


Concepto


El objetivo es hacer una pregunta y escuchar a una persona sin interrumpir y esperar el final de su respuesta. ASR está representado por un módulo separado donde hay un evento ASR.Result : se dispara cuando una persona ha terminado de hablar. Los detalles del ASR de Google es que el ASR. El resultado con texto reconocido regresará tan pronto como una persona haga una pausa de al menos un poco y Google decida que dicha frase se reconoce y completa.

Para darle a una persona la oportunidad de pausar, puede usar el evento ASR.InterimResult . En él, ASR en el proceso de reconocimiento devuelve todo el texto "en bruto", corrigiéndolo y cambiándolo según el contexto, y así sucesivamente, hasta que se active el resultado ASR.Result. Por lo tanto, el evento ASR.InterimResult es un indicador de que una persona está diciendo algo actualmente . Nos centraremos solo en él y veremos cuánto tiempo no llega. Y los textos intermedios reconocidos recibidos de ASR. Resultado - para agregar.

En términos generales, se verá así:

asr.addEventListener(ASREvents.InterimResult, e => { clearTimeout(timer) timer = setTimeout(stop, 3000) }) asr.addEventListener(ASREvents.Result, e => { answer += " " + e.text }) function stop(){ //... } 

Revelamos la esencia. Temporizadores


Para trabajar correctamente con pausas, puede crear un objeto especial:

 timeouts = { silence: null, pause: null, duration: null } 

Después de hacer una pregunta, una persona a menudo piensa por unos segundos. Es mejor configurar el temporizador para el silencio al principio de 6 a 8 segundos, guardaremos la ID del temporizador en el parámetro timeout.silence .

Las pausas en el medio de la respuesta son óptimas en 3-4 segundos, para que una persona pueda pensar, pero no sufrió las expectativas cuando terminó. Este es el parámetro timeouts.pause .

El temporizador general para toda la respuesta, timeouts.duration , es útil si no queremos que la persona hable durante demasiado tiempo. También nos protege de los casos en que una persona está en una habitación ruidosa con voces de fondo que tomaremos para el discurso del cliente. Y también de los casos en que llegamos a otro robot que habla con nuestro robot en círculo.

Entonces, al comienzo del script, conectamos el módulo ASR, declaramos las variables y creamos un objeto de tiempo de espera :

 require(Modules.ASR) let call, asr, speech = "" timeouts = { silence: null, pause: null, duration: null } 

Llamada entrante


Cuando llega una llamada entrante en el script, se desencadena el evento AppEvents.CallAlerting . Creemos un controlador para este evento: responda la llamada, salude al cliente, comience el reconocimiento después del saludo. Y dejemos que una persona interrumpa el robot desde la mitad de la pregunta (detalles, un poco más).

controlador AppEvents.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() }) }) 

Se puede ver que las funciones startASR y startSilenceAndDurationTimeouts se llaman : veamos qué es esto y por qué.

Reconocimiento y tiempos de espera


El reconocimiento se implementa en la función startASR . Crea una instancia de ASR y dirige la voz de la persona a esta instancia; también contiene controladores de eventos para los eventos ASREvents.InterimResult y ASREvents.Result . Como dijimos anteriormente, aquí tratamos ASR.InterimResult como una señal de que una persona está hablando. El controlador de este evento borra los tiempos de espera previamente creados, establece un nuevo valor para los tiempos de espera. Pausa, y finalmente detiene la voz sintetizada (así es como una persona puede interrumpir el bot). El controlador ASREvents.Result simplemente concatena todas las respuestas resultantes en la variable de voz . Específicamente, en este escenario, el habla no se usa de ninguna manera, pero puede transferirlo a su servidor, por ejemplo, si lo desea.

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 => { //    speech += " " + e.text }) //    ASR call.sendMediaTo(asr) } 

Función startSilenceAndDurationTimeouts ... Escribe los valores de los temporizadores correspondientes:

 function startSilenceAndDurationTimeouts() { timeouts.silence = setTimeout(speechAnalysis, 8000) timeouts.duration = setTimeout(speechAnalysis, 30000) } 

Y algunas características más


speechAnalysis detiene el reconocimiento y analiza el texto del discurso (que se obtiene de ASREvents.Result ). Si no hay texto, entonces repetimos la pregunta; si hay un mensaje de texto, cortésmente despídase y cuelgue.

discursoAnálisis
 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() }) } } 

El handleSilence es responsable de repetir la pregunta:

 function handleSilence() { call.say(",   . , ,        ?", Language.RU_RUSSIAN_FEMALE) //    3          setTimeout(startASR, 3000) call.addEventListener(CallEvents.PlaybackFinished, startSilenceAndDurationTimeouts) } 

Finalmente, una función auxiliar para detener ASR:

 function stopASR() { asr.stop() call.removeEventListener(CallEvents.PlaybackFinished) clearTimeout(timeouts.duration) } 

Todos juntos


listado de guiones
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)
}
view raw asr.js hosted with ❤ by GitHub

El escenario final muestra cómo puede "ennoblecer" un robot rectilíneo, agregando un poco de tacto y atención. Sin duda, este método no es el único posible, por lo que si tiene alguna idea sobre cómo puede terminar con elegancia la interacción habitual entre un bot y una persona, comparta los comentarios. Para aquellos que quieren algo más avanzado y de repente no leyeron nuestro tutorial sobre DialogFlow, les recomendamos que se familiaricen .

Source: https://habr.com/ru/post/es431676/


All Articles