diff --git a/lib/tasks/gather.js b/lib/tasks/gather.js index 60783972..4a531831 100644 --- a/lib/tasks/gather.js +++ b/lib/tasks/gather.js @@ -11,6 +11,19 @@ const makeTask = require('./make_task'); const assert = require('assert'); //const GATHER_STABILITY_THRESHOLD = Number(process.env.JAMBONZ_GATHER_STABILITY_THRESHOLD || 0.7); +const compileTranscripts = (logger, evt, arr) => { + //logger.debug({arr, evt}, 'compile transcripts'); + if (!Array.isArray(arr) || arr.length === 0) return; + let t = ''; + for (const a of arr) { + //logger.debug(`adding ${a.alternatives[0].transcript}`); + t += ` ${a.alternatives[0].transcript}`; + } + t += ` ${evt.alternatives[0].transcript}`; + evt.alternatives[0].transcript = t.trim(); + //logger.debug(`compiled transcript: ${evt.alternatives[0].transcript}`); +}; + class TaskGather extends Task { constructor(logger, opts, parentTask) { super(logger, opts); @@ -86,7 +99,7 @@ class TaskGather extends Task { } if (!this.sayTask && !this.playTask) this.listenDuringPrompt = false; - /* buffer speech for continueous asr */ + /* buffer speech for continuous asr */ this._bufferedTranscripts = []; this.parentTask = parentTask; @@ -487,6 +500,13 @@ class TaskGather extends Task { }; } } + + /* count words for bargein feature */ + const words = evt.alternatives[0].transcript.split(' ').length; + const bufferedWords = this._bufferedTranscripts.reduce((count, e) => { + return count + e.alternatives[0].transcript.split(' ').length; + }, 0); + if (evt.is_final) { if (evt.alternatives[0].transcript === '' && !this.callSession.callGone && !this.killed) { this.logger.info({evt}, 'TaskGather:_onTranscription - got empty transcript, listen again'); @@ -513,7 +533,18 @@ class TaskGather extends Task { this._startAsrTimer(); return this._startTranscribing(ep); } - else this._resolve('speech', evt); + else { + if (this.bargein && (words + bufferedWords) < this.minBargeinWordCount) { + this.logger.debug({evt, words, bufferedWords}, + 'TaskGather:_onTranscription - final transcript but < min barge words'); + this._bufferedTranscripts.push(evt); + this._startTranscribing(ep); + return; + } + else { + this._resolve('speech', evt); + } + } } else { /* google has a measure of stability: @@ -521,9 +552,7 @@ class TaskGather extends Task { others do not. */ //const isStableEnough = typeof evt.stability === 'undefined' || evt.stability > GATHER_STABILITY_THRESHOLD; - - if (this.bargein && /* isStableEnough && */ - evt.alternatives[0].transcript.split(' ').length >= this.minBargeinWordCount) { + if (this.bargein && (words + bufferedWords) >= this.minBargeinWordCount) { if (!this.playComplete) { this.logger.debug({transcript: evt.alternatives[0].transcript}, 'killing audio due to speech'); this.emit('vad'); @@ -544,7 +573,7 @@ class TaskGather extends Task { this._killAudio(cs); } - if (!this.resolved && !this.killed) { + if (!this.resolved && !this.killed && !this._bufferedTranscripts.length) { this._startTranscribing(ep); } } @@ -579,6 +608,10 @@ class TaskGather extends Task { }; this.logger.debug({evt}, 'TaskGather:resolve continuous asr'); } + else if (!this.isContinuousAsr && reason.startsWith('speech') && this._bufferedTranscripts.length) { + compileTranscripts(this.logger, evt, this._bufferedTranscripts); + this.logger.debug({evt}, 'TaskGather:resolve buffered results'); + } this.span.setAttributes({'stt.resolve': reason, 'stt.result': JSON.stringify(evt)}); if (this.ep && this.ep.connected) {