mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-22 01:27:55 +00:00
gather: support for min/max digits and interdigit timeout
This commit is contained in:
@@ -9,6 +9,7 @@ const {
|
||||
|
||||
const makeTask = require('./make_task');
|
||||
const assert = require('assert');
|
||||
const GATHER_STABILITY_THRESHOLD = Number(process.env.JAMBONZ_GATHER_STABILITY_THRESHOLD || 0.7);
|
||||
|
||||
class TaskGather extends Task {
|
||||
constructor(logger, opts, parentTask) {
|
||||
@@ -16,11 +17,14 @@ class TaskGather extends Task {
|
||||
this.preconditions = TaskPreconditions.Endpoint;
|
||||
|
||||
[
|
||||
'finishOnKey', 'hints', 'input', 'numDigits',
|
||||
'partialResultHook', 'bargein',
|
||||
'finishOnKey', 'hints', 'input', 'numDigits', 'minDigits', 'maxDigits',
|
||||
'interDigitTimeout', 'partialResultHook', 'bargein', 'dtmfBargein',
|
||||
'speechTimeout', 'timeout', 'say', 'play'
|
||||
].forEach((k) => this[k] = this.data[k]);
|
||||
|
||||
/* when collecting dtmf, bargein on dtmf is true unless explicitly set to false */
|
||||
if (this.dtmfBargein !== false && this.input.includes('digits')) this.dtmfBargein = true;
|
||||
|
||||
this.timeout = (this.timeout || 15) * 1000;
|
||||
this.interim = this.partialResultCallback;
|
||||
if (this.data.recognizer) {
|
||||
@@ -123,7 +127,7 @@ class TaskGather extends Task {
|
||||
.catch(() => {/*already logged error */});
|
||||
}
|
||||
|
||||
if (this.input.includes('digits')) {
|
||||
if (this.input.includes('digits') || this.dtmfBargein) {
|
||||
ep.on('dtmf', this._onDtmf.bind(this, cs, ep));
|
||||
}
|
||||
|
||||
@@ -142,17 +146,33 @@ class TaskGather extends Task {
|
||||
super.kill(cs);
|
||||
this._killAudio(cs);
|
||||
this.ep.removeAllListeners('dtmf');
|
||||
clearTimeout(this.interDigitTimer);
|
||||
this._resolve('killed');
|
||||
}
|
||||
|
||||
_onDtmf(cs, ep, evt) {
|
||||
this.logger.debug(evt, 'TaskGather:_onDtmf');
|
||||
if (evt.dtmf === this.finishOnKey) this._resolve('dtmf-terminator-key');
|
||||
clearTimeout(this.interDigitTimer);
|
||||
let resolved = false;
|
||||
if (this.dtmfBargein) this._killAudio(cs);
|
||||
if (evt.dtmf === this.finishOnKey && this.input.includes('digits')) {
|
||||
resolved = true;
|
||||
this._resolve('dtmf-terminator-key');
|
||||
}
|
||||
else {
|
||||
this.digitBuffer += evt.dtmf;
|
||||
if (this.digitBuffer.length === this.numDigits) this._resolve('dtmf-num-digits');
|
||||
const len = this.digitBuffer.length;
|
||||
if (len === this.numDigits || len === this.maxDigits) {
|
||||
resolved = true;
|
||||
this._resolve('dtmf-num-digits');
|
||||
}
|
||||
}
|
||||
if (!resolved && this.interDigitTimeout > 0 && this.digitBuffer.length >= this.minDigits) {
|
||||
/* start interDigitTimer */
|
||||
const ms = this.interDigitTimeout * 1000;
|
||||
this.logger.debug(`starting interdigit timer of ${ms}`);
|
||||
this.interDigitTimer = setTimeout(() => this._resolve('dtmf-interdigit-timeout'), ms);
|
||||
}
|
||||
this._killAudio(cs);
|
||||
}
|
||||
|
||||
async _initSpeech(cs, ep) {
|
||||
@@ -292,19 +312,20 @@ class TaskGather extends Task {
|
||||
}
|
||||
if (evt.is_final) this._resolve('speech', evt);
|
||||
else {
|
||||
if (this.bargein && evt.alternatives[0].transcript.split(' ').length >= this.minBargeinWordCount) {
|
||||
this.logger.debug('Gather:_onTranscription - killing audio due to bargein');
|
||||
/* google has a measure of stability:
|
||||
https://cloud.google.com/speech-to-text/docs/basics#streaming_responses
|
||||
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) {
|
||||
this.logger.debug('Gather:_onTranscription - killing audio due to speech bargein');
|
||||
this._killAudio(cs);
|
||||
}
|
||||
else {
|
||||
if (this.bargein && evt.alternatives[0].transcript.split(' ').length >= this.minBargeinWordCount) {
|
||||
this.logger.debug('Gather:_onTranscription - killing audio due to bargein');
|
||||
this._killAudio(cs);
|
||||
}
|
||||
if (this.partialResultHook) {
|
||||
this.cs.requestor.request(this.partialResultHook, Object.assign({speech: evt}, this.cs.callInfo))
|
||||
.catch((err) => this.logger.info(err, 'GatherTask:_onTranscription error'));
|
||||
}
|
||||
if (this.partialResultHook) {
|
||||
this.cs.requestor.request(this.partialResultHook, Object.assign({speech: evt}, this.cs.callInfo))
|
||||
.catch((err) => this.logger.info(err, 'GatherTask:_onTranscription error'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,6 +344,7 @@ class TaskGather extends Task {
|
||||
if (this.resolved) return;
|
||||
this.resolved = true;
|
||||
this.logger.debug(`TaskGather:resolve with reason ${reason}`);
|
||||
clearTimeout(this.interDigitTimer);
|
||||
|
||||
if (this.ep && this.ep.connected) {
|
||||
this.ep.stopTranscription({vendor: this.vendor})
|
||||
|
||||
Reference in New Issue
Block a user