Taktvoller Roboter: Kann zuhören und unterbricht nicht

Die Spracherkennung (im Folgenden: ASR, Automatic Speech Recognition) wird zum Erstellen von Bots und / oder IVR sowie für automatisierte Abfragen verwendet. Voximplant verwendet die von der Good Corporation bereitgestellte ASR - die Google-Erkennung funktioniert schnell und mit hoher Genauigkeit, aber ... Wie immer gibt es eine Einschränkung. Eine Person kann sogar in kurzen Sätzen pausieren, und wir brauchen eine Garantie, dass die ASR keine Pause als Ende der Antwort einlegt. Wenn der ASR der Meinung ist, dass die Person das Sprechen beendet hat, kann das Skript nach der „Antwort“ eine Sprachsynthese mit der folgenden Frage enthalten - gleichzeitig spricht die Person weiter und erhält eine schlechte Benutzererfahrung: Der Bot / IVR unterbricht die Person. Heute werden wir Ihnen erklären, wie Sie damit umgehen sollen, damit sich Ihre Benutzer nicht über die Kommunikation mit Eisenassistenten aufregen.


Konzept


Das Ziel ist es, eine Frage zu stellen und einer Person zuzuhören, ohne sie zu unterbrechen und auf das Ende ihrer Antwort zu warten. ASR wird durch ein separates Modul dargestellt, in dem ein ASR.Result- Ereignis vorliegt. Es wird ausgelöst, wenn eine Person mit dem Sprechen fertig ist. Die Besonderheiten von Googles ASR sind, dass ASR. Das Ergebnis mit erkanntem Text wird zurückgegeben, sobald eine Person mindestens eine Weile innehält und Google entscheidet, dass diese Phrase erkannt und vervollständigt wird.

Um einer Person die Möglichkeit zu geben, eine Pause einzulegen , können Sie das Ereignis ASR.InterimResult verwenden . Darin gibt ASR während des Erkennungsprozesses den gesamten "rohen" Text zurück und korrigiert und ändert ihn je nach Kontext - und so weiter, bis das ASR.Result ausgelöst wird. Somit ist das Ereignis ASR.InterimResult ein Indikator dafür, dass eine Person gerade etwas sagt . Wir werden uns nur auf ihn konzentrieren und sehen, wie lange es nicht kommt. Und die von ASR.Result erhaltenen Zwischenerkennungs-Texte - hinzufügen.

Im Allgemeinen wird es so aussehen:

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

Wir enthüllen die Essenz. Timer


Um mit Pausen richtig zu arbeiten, können Sie ein spezielles Objekt erstellen:

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

Nach dem Stellen einer Frage denkt eine Person oft einige Sekunden nach. Es ist besser, den Timer für die Stille am Anfang von 6-8 Sekunden einzustellen. Wir speichern die Timer-ID im Parameter timeouts.silence .

Pausen in der Mitte der Antwort sind in 3-4 Sekunden optimal, so dass eine Person denken kann, aber nicht in Erwartung gelitten hat, wenn sie fertig ist. Dies ist der Parameter timeouts.pause .

Der allgemeine Timer für die gesamte Antwort - timeouts.duration - ist nützlich, wenn die Person nicht zu lange sprechen soll. Es schützt uns auch vor Fällen, in denen sich eine Person in einem lauten Raum mit Hintergrundstimmen befindet, die von uns für die Rede des Kunden verwendet werden. Und auch aus Fällen, in denen wir zu einem anderen Roboter kamen, der im Kreis mit unserem Roboter spricht.

Zu Beginn des Skripts schließen wir das ASR-Modul an, deklarieren die Variablen und erstellen ein Timeout- Objekt:

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

Eingehender Anruf


Wenn ein eingehender Anruf im Skript eingeht , wird das Ereignis AppEvents.CallAlerting ausgelöst . Erstellen wir einen Handler für dieses Ereignis: Beantworten Sie den Anruf, begrüßen Sie den Client und starten Sie die Erkennung nach der Begrüßung. Lassen wir eine Person den Roboter von der Mitte der gestellten Frage aus unterbrechen (Details - etwas weiter).

Handler 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() }) }) 

Es ist ersichtlich, dass die Funktionen startASR und startSilenceAndDurationTimeouts aufgerufen werden - lassen Sie uns sehen, was dies ist und warum.

Erkennung und Zeitüberschreitungen


Die Erkennung ist in der Funktion startASR implementiert. Es erstellt eine ASR-Instanz und leitet die Stimme der Person an diese Instanz weiter. Außerdem enthält es Ereignishandler für die Ereignisse ASREvents.InterimResult und ASREvents.Result . Wie oben erwähnt, behandeln wir ASR.InterimResult hier als Zeichen dafür, dass eine Person spricht. Der Handler dieses Ereignisses löscht zuvor erstellte Zeitüberschreitungen, legt einen neuen Wert für timeouts.pause fest und stoppt schließlich die synthetisierte Stimme (auf diese Weise kann eine Person den Bot unterbrechen). Der ASREvents.Result-Handler verkettet einfach alle resultierenden Antworten in der Sprachvariablen. In diesem Szenario wird Sprache in keiner Weise verwendet, aber Sie können sie beispielsweise auf Wunsch in Ihr Backend übertragen.

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) } 

Funktion startSilenceAndDurationTimeouts ... Schreibt die Werte der entsprechenden Timer:

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

Und noch ein paar Features


Die Sprachanalyse stoppt die Erkennung und analysiert den Text aus der Sprache (die von ASREvents.Result abgerufen wird ). Wenn es keinen Text gibt, wiederholen wir die Frage; Wenn es einen Text gibt, dann verabschieden Sie sich höflich und legen Sie auf.

Sprachanalyse
 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() }) } } 

Das handleSilence ist für die Wiederholung der Frage verantwortlich:

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

Schließlich eine Hilfsfunktion zum Stoppen von ASR:

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

Alle zusammen


Skriptliste
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

Das letzte Szenario zeigt, wie Sie einen geradlinigen Roboter "adeln" können, indem Sie ihm ein wenig Fingerspitzengefühl und Aufmerksamkeit verleihen. Sicherlich ist diese Methode nicht die einzig mögliche. Wenn Sie also darüber nachdenken, wie Sie die übliche Interaktion zwischen einem Bot und einer Person elegant beenden können, teilen Sie dies in den Kommentaren mit. Für diejenigen, die etwas Fortgeschritteneres wollen und plötzlich unser Tutorial über DialogFlow nicht gelesen haben - wir empfehlen Ihnen, sich vertraut zu machen .

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


All Articles