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
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 => {
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() {
El
handleSilence es responsable de repetir la pregunta:
function handleSilence() { call.say(", . , , ?", Language.RU_RUSSIAN_FEMALE)
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) |
| } |
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 .