mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 16:50:39 +00:00
Transcribe background task (#576)
* first draft * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * update verb-specification * fix comment reviews * provide bugname when stopping transcription, otherwise it will continue --------- Co-authored-by: Dave Horton <daveh@beachdognet.com>
This commit is contained in:
@@ -20,10 +20,8 @@ const WsRequestor = require('../utils/ws-requestor');
|
||||
const {
|
||||
JAMBONES_INJECT_CONTENT,
|
||||
AWS_REGION,
|
||||
JAMBONZ_RECORD_WS_BASE_URL,
|
||||
JAMBONZ_RECORD_WS_USERNAME,
|
||||
JAMBONZ_RECORD_WS_PASSWORD,
|
||||
} = require('../config');
|
||||
const BackgroundTaskManager = require('../utils/background-task-manager');
|
||||
const BADPRECONDITIONS = 'preconditions not met';
|
||||
const CALLER_CANCELLED_ERR_MSG = 'Response not sent due to unknown transaction';
|
||||
|
||||
@@ -66,6 +64,11 @@ class CallSession extends Emitter {
|
||||
this.callGone = false;
|
||||
this.notifiedComplete = false;
|
||||
this.rootSpan = rootSpan;
|
||||
this.backgroundTaskManager = new BackgroundTaskManager({
|
||||
cs: this,
|
||||
logger,
|
||||
rootSpan
|
||||
});
|
||||
|
||||
this._origRecognizerSettings = {
|
||||
vendor: this.application?.speech_recognizer_vendor,
|
||||
@@ -136,8 +139,7 @@ class CallSession extends Emitter {
|
||||
}
|
||||
|
||||
get isBackGroundListen() {
|
||||
return !(this.backgroundListenTask === null ||
|
||||
this.backgroundListenTask === undefined);
|
||||
return this.backgroundTaskManager.isTaskRunning('listen');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -379,11 +381,11 @@ class CallSession extends Emitter {
|
||||
}
|
||||
|
||||
get isBotModeEnabled() {
|
||||
return this.backgroundGatherTask;
|
||||
return this.backgroundTaskManager.isTaskRunning('bargeIn');
|
||||
}
|
||||
|
||||
get isListenEnabled() {
|
||||
return this.backgroundListenTask;
|
||||
return this.backgroundTaskManager.isTaskRunning('listen');
|
||||
}
|
||||
|
||||
get b3() {
|
||||
@@ -612,117 +614,41 @@ class CallSession extends Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
async startBackgroundListen(opts, bugname) {
|
||||
if (this.isListenEnabled) {
|
||||
this.logger.info('CallSession:startBackgroundListen - listen is already enabled, ignoring request');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.logger.debug({opts}, 'CallSession:startBackgroundListen');
|
||||
const t = normalizeJambones(this.logger, [opts]);
|
||||
this.backgroundListenTask = makeTask(this.logger, t[0]);
|
||||
this.backgroundListenTask.bugname = bugname;
|
||||
// Remove unneeded customer data to be sent to api server.
|
||||
this.backgroundListenTask.ignoreCustomerData = true;
|
||||
const resources = await this._evaluatePreconditions(this.backgroundListenTask);
|
||||
const {span, ctx} = this.rootSpan.startChildSpan(`background-listen:${this.backgroundListenTask.summary}`);
|
||||
this.backgroundListenTask.span = span;
|
||||
this.backgroundListenTask.ctx = ctx;
|
||||
this.backgroundListenTask.exec(this, resources)
|
||||
.then(() => {
|
||||
this.logger.info('CallSession:startBackgroundListen: listen completed');
|
||||
this.backgroundListenTask && this.backgroundListenTask.removeAllListeners();
|
||||
this.backgroundListenTask && this.backgroundListenTask.span.end();
|
||||
this.backgroundListenTask = null;
|
||||
return;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.logger.info({err}, 'CallSession:startBackgroundListen: listen threw error');
|
||||
this.backgroundListenTask && this.backgroundListenTask.removeAllListeners();
|
||||
this.backgroundListenTask && this.backgroundListenTask.span.end();
|
||||
this.backgroundListenTask = null;
|
||||
});
|
||||
} catch (err) {
|
||||
this.logger.info({err, opts}, 'CallSession:startBackgroundListen - Error creating listen task');
|
||||
}
|
||||
}
|
||||
|
||||
async stopBackgroundListen() {
|
||||
this.logger.debug('CallSession:stopBackgroundListen');
|
||||
try {
|
||||
if (this.backgroundListenTask) {
|
||||
this.backgroundListenTask.removeAllListeners();
|
||||
this.backgroundListenTask.kill().catch(() => {});
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.info({err}, 'CallSession:stopBackgroundListen - Error stopping listen task');
|
||||
}
|
||||
}
|
||||
|
||||
async enableBotMode(gather, autoEnable) {
|
||||
try {
|
||||
const t = normalizeJambones(this.logger, [gather]);
|
||||
const task = makeTask(this.logger, t[0]);
|
||||
|
||||
let task;
|
||||
if (this.isBotModeEnabled) {
|
||||
const currInput = this.backgroundGatherTask.input;
|
||||
const newInput = task.input;
|
||||
task = this.backgroundTaskManager.getTask('bargeIn');
|
||||
const currInput = task.input;
|
||||
const t = normalizeJambones(this.logger, [gather]);
|
||||
const tmpTask = makeTask(this.logger, t[0]);
|
||||
const newInput = tmpTask.input;
|
||||
if (JSON.stringify(currInput) === JSON.stringify(newInput)) {
|
||||
this.logger.info('CallSession:enableBotMode - bot mode currently enabled, ignoring request to start again');
|
||||
return;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.logger.info({currInput, newInput},
|
||||
'CallSession:enableBotMode - restarting background gather to apply new input type');
|
||||
this.backgroundGatherTask.sticky = false;
|
||||
'CallSession:enableBotMode - restarting background bargeIn to apply new input type');
|
||||
task.sticky = false;
|
||||
await this.disableBotMode();
|
||||
}
|
||||
}
|
||||
this.backgroundGatherTask = task;
|
||||
this._bargeInEnabled = true;
|
||||
this.backgroundGatherTask
|
||||
.once('dtmf', this._clearTasks.bind(this, this.backgroundGatherTask))
|
||||
.once('vad', this._clearTasks.bind(this, this.backgroundGatherTask))
|
||||
.once('transcription', this._clearTasks.bind(this, this.backgroundGatherTask))
|
||||
.once('timeout', this._clearTasks.bind(this, this.backgroundGatherTask));
|
||||
this.logger.info({gather}, 'CallSession:enableBotMode - starting background gather');
|
||||
const resources = await this._evaluatePreconditions(this.backgroundGatherTask);
|
||||
const {span, ctx} = this.rootSpan.startChildSpan(`background-gather:${this.backgroundGatherTask.summary}`);
|
||||
this.backgroundGatherTask.span = span;
|
||||
this.backgroundGatherTask.ctx = ctx;
|
||||
this.backgroundGatherTask.sticky = autoEnable;
|
||||
this.backgroundGatherTask.exec(this, resources)
|
||||
.then(() => {
|
||||
this.logger.info('CallSession:enableBotMode: gather completed');
|
||||
this.backgroundGatherTask && this.backgroundGatherTask.removeAllListeners();
|
||||
this.backgroundGatherTask && this.backgroundGatherTask.span.end();
|
||||
const sticky = this.backgroundGatherTask?.sticky;
|
||||
this.backgroundGatherTask = null;
|
||||
if (sticky && !this.callGone && !this._stopping && this._bargeInEnabled) {
|
||||
this.logger.info('CallSession:enableBotMode: restarting background gather');
|
||||
setImmediate(() => this.enableBotMode(gather, true));
|
||||
}
|
||||
return;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.logger.info({err}, 'CallSession:enableBotMode: gather threw error');
|
||||
this.backgroundGatherTask && this.backgroundGatherTask.removeAllListeners();
|
||||
this.backgroundGatherTask && this.backgroundGatherTask.span.end();
|
||||
this.backgroundGatherTask = null;
|
||||
});
|
||||
task = await this.backgroundTaskManager.newTask('bargeIn', gather);
|
||||
task.sticky = autoEnable;
|
||||
task.once('bargeIn-done', () => {
|
||||
if (this.requestor instanceof WsRequestor) {
|
||||
try {
|
||||
this.kill(true);
|
||||
} catch (err) {}
|
||||
}
|
||||
});
|
||||
this.logger.info({gather}, 'CallSession:enableBotMode - starting background bargeIn');
|
||||
} catch (err) {
|
||||
this.logger.info({err, gather}, 'CallSession:enableBotMode - Error creating gather task');
|
||||
this.logger.info({err, gather}, 'CallSession:enableBotMode - Error creating bargeIn task');
|
||||
}
|
||||
}
|
||||
async disableBotMode() {
|
||||
this._bargeInEnabled = false;
|
||||
if (this.backgroundGatherTask) {
|
||||
try {
|
||||
this.backgroundGatherTask.removeAllListeners();
|
||||
await this.backgroundGatherTask.kill();
|
||||
} catch (err) {}
|
||||
this.backgroundGatherTask = null;
|
||||
}
|
||||
this.backgroundTaskManager.stop('bargeIn');
|
||||
}
|
||||
|
||||
setConferenceDetails(memberId, confName, confUuid) {
|
||||
@@ -906,7 +832,7 @@ class CallSession extends Emitter {
|
||||
let skip = false;
|
||||
this.currentTask = task;
|
||||
if (TaskName.Gather === task.name && this.isBotModeEnabled) {
|
||||
if (this.backgroundGatherTask.updateTaskInProgress(task) !== false) {
|
||||
if (this.backgroundTaskManager.getTask('bargeIn').updateTaskInProgress(task) !== false) {
|
||||
this.logger.info(`CallSession:exec skipping #${stackNum}:${taskNum}: ${task.name}`);
|
||||
skip = true;
|
||||
}
|
||||
@@ -942,7 +868,7 @@ class CallSession extends Emitter {
|
||||
this.requestor instanceof WsRequestor &&
|
||||
!this.requestor.closedGracefully &&
|
||||
!this.callGone &&
|
||||
!this.disableWaitCommand
|
||||
!this.isConfirmCallSession
|
||||
) {
|
||||
try {
|
||||
await this._awaitCommandsOrHangup();
|
||||
@@ -1394,7 +1320,6 @@ Duration=${duration} `
|
||||
get the full transcription.
|
||||
*/
|
||||
delete t.bargeIn.enable;
|
||||
this._bargeInEnabled = false;
|
||||
this.logger.info('CallSession:kill - found bargein disabled in the stack, clearing to that point');
|
||||
break;
|
||||
}
|
||||
@@ -1700,6 +1625,8 @@ Duration=${duration} `
|
||||
this.notifier && this.notifier.close();
|
||||
|
||||
this.rootSpan && this.rootSpan.end();
|
||||
// close all background tasks
|
||||
this.backgroundTaskManager.stopAll();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2016,12 +1943,14 @@ Duration=${duration} `
|
||||
async _notifyCallStatusChange({callStatus, sipStatus, sipReason, duration}) {
|
||||
if (this.callMoved) return;
|
||||
|
||||
// manage record all call.
|
||||
if (callStatus === CallStatus.InProgress) {
|
||||
// nice, call is in progress, good time to enable record
|
||||
await this.enableRecordAllCall();
|
||||
} else if (callStatus == CallStatus.Completed && this.isBackGroundListen) {
|
||||
this.stopBackgroundListen().catch((err) => this.logger.error(
|
||||
{err}, 'CallSession:_notifyCallStatusChange - error stopping background listen'));
|
||||
if (this.accountInfo.account.record_all_calls ||
|
||||
this.application.record_all_calls) {
|
||||
this.backgroundTaskManager.newTask('record');
|
||||
}
|
||||
} else if (callStatus == CallStatus.Completed) {
|
||||
this.backgroundTaskManager.stop('record');
|
||||
}
|
||||
|
||||
/* race condition: we hang up at the same time as the caller */
|
||||
@@ -2058,29 +1987,6 @@ Duration=${duration} `
|
||||
}
|
||||
}
|
||||
|
||||
async enableRecordAllCall() {
|
||||
if (this.accountInfo.account.record_all_calls || this.application.record_all_calls) {
|
||||
if (!JAMBONZ_RECORD_WS_BASE_URL || !this.accountInfo.account.bucket_credential) {
|
||||
this.logger.error('Record all calls: invalid configuration');
|
||||
return;
|
||||
}
|
||||
const listenOpts = {
|
||||
url: `${JAMBONZ_RECORD_WS_BASE_URL}/record/${this.accountInfo.account.bucket_credential.vendor}`,
|
||||
disableBidirectionalAudio: true,
|
||||
mixType : 'stereo',
|
||||
passDtmf: true
|
||||
};
|
||||
if (JAMBONZ_RECORD_WS_USERNAME && JAMBONZ_RECORD_WS_PASSWORD) {
|
||||
listenOpts.wsAuth = {
|
||||
username: JAMBONZ_RECORD_WS_USERNAME,
|
||||
password: JAMBONZ_RECORD_WS_PASSWORD
|
||||
};
|
||||
}
|
||||
this.logger.debug({listenOpts}, 'Record all calls: enabling listen');
|
||||
await this.startBackgroundListen({verb: 'listen', ...listenOpts}, 'jambonz-session-record');
|
||||
}
|
||||
}
|
||||
|
||||
_configMsEndpoint() {
|
||||
if (this.onHoldMusic) {
|
||||
this.ep.set({hold_music: `shout://${this.onHoldMusic.replace(/^https?:\/\//, '')}`});
|
||||
@@ -2123,6 +2029,18 @@ Duration=${duration} `
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* startBackgroundTask - Start background task
|
||||
*/
|
||||
|
||||
async startBackgroundTask(type, opts) {
|
||||
await this.backgroundTaskManager.newTask(type, opts);
|
||||
}
|
||||
|
||||
stopBackgroundTask(type) {
|
||||
this.backgroundTaskManager.stop(type);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CallSession;
|
||||
|
||||
@@ -23,7 +23,6 @@ class ConfirmCallSession extends CallSession {
|
||||
});
|
||||
this.dlg = dlg;
|
||||
this.ep = ep;
|
||||
this.disableWaitCommand = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user