From e69afc4be43fc1b21646d2017b4ba9dba7e53b6d Mon Sep 17 00:00:00 2001 From: Hoan Luu Huu <110280845+xquanluu@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:34:52 +0700 Subject: [PATCH] fix recognizer/synthesizer label wrongly select between verb and app (#881) * fix recognizer/synthesizer label wrongly select between verb and application * fix jslint * fix ASR cannot fallback * update tts fallback does not send notification --- lib/tasks/say.js | 11 +++-------- lib/tasks/stt-task.js | 38 +++++++++++++++++++++++--------------- lib/tasks/tts-task.js | 9 +++++++++ 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/lib/tasks/say.js b/lib/tasks/say.js index 762c6486..f80a1062 100644 --- a/lib/tasks/say.js +++ b/lib/tasks/say.js @@ -79,10 +79,7 @@ class TaskSay extends TtsTask { let voice = this.synthesizer.voice && this.synthesizer.voice !== 'default' ? this.synthesizer.voice : cs.speechSynthesisVoice; - // label can be null/empty in synthesizer config, just use application level label if it's default - let label = this.synthesizer.label === 'default' ? - cs.speechSynthesisLabel : - this.synthesizer.label; + let label = this.taskInlcudeSynthesizer ? this.synthesizer.label : cs.speechSynthesisLabel; const fallbackVendor = this.synthesizer.fallbackVendor && this.synthesizer.fallbackVendor !== 'default' ? this.synthesizer.fallbackVendor : @@ -93,10 +90,8 @@ class TaskSay extends TtsTask { const fallbackVoice = this.synthesizer.fallbackVoice && this.synthesizer.fallbackVoice !== 'default' ? this.synthesizer.fallbackVoice : cs.fallbackSpeechSynthesisVoice; - // label can be null/empty in synthesizer config, just use application level label if it's default - const fallbackLabel = this.synthesizer.fallbackLabel === 'default' ? - cs.fallbackSpeechSynthesisLabel : - this.synthesizer.fallbackLabel; + const fallbackLabel = this.taskInlcudeSynthesizer ? + this.synthesizer.fallbackLabel : cs.fallbackSpeechSynthesisLabel; if (cs.hasFallbackTts) { vendor = fallbackVendor; diff --git a/lib/tasks/stt-task.js b/lib/tasks/stt-task.js index 4d6df652..273bcc98 100644 --- a/lib/tasks/stt-task.js +++ b/lib/tasks/stt-task.js @@ -24,6 +24,12 @@ class SttTask extends Task { this.consolidateTranscripts = consolidateTranscripts; this.eventHandlers = []; this.isHandledByPrimaryProvider = true; + /** + * Task use taskIncludeRecognizer to identify + * if taskIncludeRecognizer === true, use label from verb.recognizer, even it's empty + * if taskIncludeRecognizer === false, use label from application.recognizer + */ + this.taskIncludeRecognizer = !!this.data.recognizer; if (this.data.recognizer) { const recognizer = this.data.recognizer; this.vendor = recognizer.vendor; @@ -33,7 +39,6 @@ class SttTask extends Task { //fallback this.fallbackVendor = recognizer.fallbackVendor || 'default'; this.fallbackLanguage = recognizer.fallbackLanguage || 'default'; - // label can be empty and should not have default value. this.fallbackLabel = recognizer.fallbackLabel; /* let credentials be supplied in the recognizer object at runtime */ @@ -82,8 +87,7 @@ class SttTask extends Task { this.language = cs.speechRecognizerLanguage; if (this.data.recognizer) this.data.recognizer.language = this.language; } - // label can be empty, should not assign application level label - if ('default' === this.label) { + if (!this.taskIncludeRecognizer) { this.label = cs.speechRecognizerLabel; if (this.data.recognizer) this.data.recognizer.label = this.label; } @@ -96,17 +100,21 @@ class SttTask extends Task { this.fallbackLanguage = cs.fallbackSpeechRecognizerLanguage; if (this.data.recognizer) this.data.recognizer.fallbackLanguage = this.fallbackLanguage; } - // label can be empty, should not assign application level label - if ('default' === this.fallbackLabel) { + if (!this.taskIncludeRecognizer) { this.fallbackLabel = cs.fallbackSpeechRecognizerLabel; if (this.data.recognizer) this.data.recognizer.fallbackLabel = this.fallbackLabel; } - // If call is already fallback to 2nd ASR vendor - // use that. + if (cs.hasFallbackAsr) { - this.vendor = this.fallbackVendor; - this.language = this.fallbackLanguage; - this.label = this.fallbackLabel; + if (this.taskIncludeRecognizer) { + // reset fallback ASR from previous run if this verb contains data.recognizer. + cs.hasFallbackAsr = false; + } else { + this.logger.debug('Call session has fallback to 2nd ASR, use 2nd recognizer configuration'); + this.vendor = this.fallbackVendor; + this.language = this.fallbackLanguage; + this.label = this.fallbackLabel; + } } if (!this.data.recognizer.vendor) { this.data.recognizer.vendor = this.vendor; @@ -181,7 +189,7 @@ class SttTask extends Task { vendor, target_sid: cs.callSid }).catch((err) => this.logger.info({err}, 'Error generating alert for no stt')); - this.notifyTaskDone(); + // the ASR might have fallback configuration, should not done task here. throw new Error(`No speech-to-text service credentials for ${vendor} have been configured`); } @@ -223,12 +231,12 @@ class SttTask extends Task { async _initFallback() { assert(this.fallbackVendor, 'fallback failed without fallbackVendor configuration'); + this.logger.info(`Failed to use primary STT provider, fallback to ${this.fallbackVendor}`); this.isHandledByPrimaryProvider = false; this.cs.hasFallbackAsr = true; - this.logger.info(`Failed to use primary STT provider, fallback to ${this.fallbackVendor}`); - this.vendor = this.fallbackVendor; - this.language = this.fallbackLanguage; - this.label = this.fallbackLabel; + this.vendor = this.cs.fallbackSpeechRecognizerVendor = this.fallbackVendor; + this.language = this.cs.fallbackSpeechRecognizerLanguage = this.fallbackLanguage; + this.label = this.cs.fallbackSpeechRecognizerLabel = this.fallbackLabel; this.data.recognizer.vendor = this.vendor; this.data.recognizer.language = this.language; this.data.recognizer.label = this.label; diff --git a/lib/tasks/tts-task.js b/lib/tasks/tts-task.js index 1936f5dd..2811c5d9 100644 --- a/lib/tasks/tts-task.js +++ b/lib/tasks/tts-task.js @@ -10,6 +10,12 @@ class TtsTask extends Task { this.preconditions = TaskPreconditions.Endpoint; this.earlyMedia = this.data.earlyMedia === true || (parentTask && parentTask.earlyMedia); + /** + * Task use taskInlcudeSynthesizer to identify + * if taskInlcudeSynthesizer === true, use label from verb.synthesizer, even it's empty + * if taskInlcudeSynthesizer === false, use label from application.synthesizer + */ + this.taskInlcudeSynthesizer = !!this.data.synthesizer; this.synthesizer = this.data.synthesizer || {}; this.disableTtsCache = this.data.disableTtsCache; this.options = this.synthesizer.options || {}; @@ -45,6 +51,9 @@ class TtsTask extends Task { const salt = cs.callSid; let credentials = cs.getSpeechCredentials(vendor, 'tts', label); + if (!credentials) { + throw new Error(`No text-to-speech service credentials for ${vendor} with labels: ${label} have been configured`); + } /* parse Nuance voices into name and model */ let model; if (vendor === 'nuance' && voice) {