merge features from hosted branch (#32)

major merge of features from the hosted branch that was created temporarily during the initial launch of jambonz.org
This commit is contained in:
Dave Horton
2021-06-17 16:25:50 -04:00
committed by GitHub
parent 473a34ec9f
commit 9b59d08dcf
68 changed files with 3436 additions and 1066 deletions

View File

@@ -51,9 +51,23 @@ class TaskGather extends Task {
async exec(cs, ep) {
await super.exec(cs);
const {updateSpeechCredentialLastUsed} = require('../utils/db-utils')(this.logger, cs.srf);
this.ep = ep;
if ('default' === this.vendor || !this.vendor) this.vendor = cs.speechRecognizerVendor;
if ('default' === this.language || !this.language) this.language = cs.speechRecognizerLanguage;
this.sttCredentials = cs.getSpeechCredentials(this.vendor, 'stt');
if (!this.sttCredentials) {
const {writeAlerts, AlertType} = cs.srf.locals;
this.logger.info(`TaskGather:exec - ERROR stt using ${this.vendor} requested but not creds supplied`);
writeAlerts({
account_sid: cs.accountSid,
alert_type: AlertType.STT_NOT_PROVISIONED,
vendor: this.vendor
}).catch((err) => this.logger.info({err}, 'Error generating alert for no stt'));
throw new Error(`no speech-to-text service credentials for ${this.vendor} have been configured`);
}
try {
if (this.sayTask) {
@@ -71,8 +85,10 @@ class TaskGather extends Task {
else this._startTimer();
if (this.input.includes('speech')) {
await this._initSpeech(ep);
await this._initSpeech(cs, ep);
this._startTranscribing(ep);
updateSpeechCredentialLastUsed(this.sttCredentials.speech_credential_sid)
.catch(() => {/*already logged error */});
}
if (this.input.includes('digits')) {
@@ -105,10 +121,11 @@ class TaskGather extends Task {
this._killAudio();
}
async _initSpeech(ep) {
async _initSpeech(cs, ep) {
const opts = {};
if ('google' === this.vendor) {
if (this.sttCredentials) opts.GOOGLE_APPLICATION_CREDENTIALS = JSON.stringify(this.sttCredentials.credentials);
Object.assign(opts, {
GOOGLE_SPEECH_USE_ENHANCED: true,
GOOGLE_SPEECH_SINGLE_UTTERANCE: true,
@@ -121,6 +138,8 @@ class TaskGather extends Task {
if (this.profanityFilter === true) {
Object.assign(opts, {'GOOGLE_SPEECH_PROFANITY_FILTER': true});
}
ep.addCustomEventListener(GoogleTranscriptionEvents.Transcription, this._onTranscription.bind(this, cs, ep));
ep.addCustomEventListener(GoogleTranscriptionEvents.EndOfUtterance, this._onEndOfUtterance.bind(this, cs, ep));
}
else {
if (this.vocabularyName) opts.AWS_VOCABULARY_NAME = this.vocabularyName;
@@ -129,18 +148,16 @@ class TaskGather extends Task {
opts.AWS_VOCABULARY_FILTER_METHOD = this.filterMethod || 'mask';
}
Object.assign(opts, {
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
AWS_REGION: process.env.AWS_REGION
AWS_ACCESS_KEY_ID: this.sttCredentials.accessKeyId,
AWS_SECRET_ACCESS_KEY: this.sttCredentials.secretAccessKey,
AWS_REGION: this.sttCredentials.region
});
ep.addCustomEventListener(AwsTranscriptionEvents.Transcription, this._onTranscription.bind(this, cs, ep));
}
this.logger.debug(`setting freeswitch vars ${JSON.stringify(opts)}`);
this.logger.debug({vars: opts}, 'setting freeswitch vars');
await ep.set(opts)
.catch((err) => this.logger.info(err, 'Error setting channel variables'));
ep.addCustomEventListener(GoogleTranscriptionEvents.Transcription, this._onTranscription.bind(this, ep));
ep.addCustomEventListener(AwsTranscriptionEvents.Transcription, this._onTranscription.bind(this, ep));
ep.addCustomEventListener(GoogleTranscriptionEvents.EndOfUtterance, this._onEndOfUtterance.bind(this, ep));
}
_startTranscribing(ep) {
@@ -148,7 +165,16 @@ class TaskGather extends Task {
vendor: this.vendor,
locale: this.language,
interim: this.partialResultCallback ? true : false,
}).catch((err) => this.logger.error(err, 'TaskGather:_startTranscribing error'));
}).catch((err) => {
const {writeAlerts, AlertType} = this.cs.srf.locals;
this.logger.error(err, 'TaskGather:_startTranscribing error');
writeAlerts({
account_sid: this.cs.accountSid,
alert_type: AlertType.STT_FAILURE,
vendor: this.vendor,
detail: err.message
});
}).catch((err) => this.logger.info({err}, 'Error generating alert for tts failure'));
}
_startTimer() {
@@ -175,19 +201,23 @@ class TaskGather extends Task {
}
}
_onTranscription(ep, evt) {
_onTranscription(cs, ep, evt) {
if ('aws' === this.vendor && Array.isArray(evt) && evt.length > 0) evt = evt[0];
this.logger.debug(evt, 'TaskGather:_onTranscription');
const final = evt.is_final;
if (final) this._resolve('speech', evt);
if (final) {
this._resolve('speech', evt);
}
else 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'));
}
}
_onEndOfUtterance(ep, evt) {
this.logger.info(evt, 'TaskGather:_onEndOfUtterance');
this._startTranscribing(ep);
_onEndOfUtterance(cs, ep) {
this.logger.info('TaskGather:_onEndOfUtterance');
if (!this.resolved && !this.killed) {
this._startTranscribing(ep);
}
}
async _resolve(reason, evt) {
@@ -202,13 +232,10 @@ class TaskGather extends Task {
this._clearTimer();
if (reason.startsWith('dtmf')) {
await this.performAction({reason: 'dtmfDetected', digits: this.digitBuffer});
await this.performAction({digits: this.digitBuffer});
}
else if (reason.startsWith('speech')) {
await this.performAction({reason: 'speechDetected', speech: evt});
}
else if (reason.startsWith('timeout')) {
await this.performAction({reason: 'inputTimeout'});
await this.performAction({speech: evt});
}
this.notifyTaskDone();
}