mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 08:40:38 +00:00
rasa: add support for eventhook which provides user and bot messages in realtime and supports redirecting to a new app
This commit is contained in:
@@ -45,7 +45,7 @@ module.exports = function(srf, logger) {
|
|||||||
// TODO: alert
|
// TODO: alert
|
||||||
return res.send(503, {headers: {'X-Reason': 'Account exists but is inactive'}});
|
return res.send(503, {headers: {'X-Reason': 'Account exists but is inactive'}});
|
||||||
}
|
}
|
||||||
logger.debug({accountInfo: req.locals.accountInfo}, `retrieved account info for ${account_sid}`);
|
logger.debug({accountInfo: req.locals?.accountInfo?.account}, `retrieved account info for ${account_sid}`);
|
||||||
next();
|
next();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.info({err}, `Error retrieving account details for account ${account_sid}`);
|
logger.info({err}, `Error retrieving account details for account ${account_sid}`);
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ class Rasa extends Task {
|
|||||||
|
|
||||||
get name() { return TaskName.Rasa; }
|
get name() { return TaskName.Rasa; }
|
||||||
|
|
||||||
|
get hasReportedFinalAction() {
|
||||||
|
return this.reportedFinalAction || this.isReplacingApplication;
|
||||||
|
}
|
||||||
|
|
||||||
async exec(cs, ep) {
|
async exec(cs, ep) {
|
||||||
await super.exec(cs);
|
await super.exec(cs);
|
||||||
|
|
||||||
@@ -39,12 +43,15 @@ class Rasa extends Task {
|
|||||||
|
|
||||||
async kill(cs) {
|
async kill(cs) {
|
||||||
super.kill(cs);
|
super.kill(cs);
|
||||||
if (this.ep.connected) {
|
this.logger.debug('Rasa:kill');
|
||||||
this.logger.debug('Rasa:kill');
|
|
||||||
|
|
||||||
|
if (!this.hasReportedFinalAction) {
|
||||||
|
this.reportedFinalAction = true;
|
||||||
this.performAction({rasaResult: 'caller hungup'})
|
this.performAction({rasaResult: 'caller hungup'})
|
||||||
.catch((err) => this.logger.error({err}, 'rasa - error w/ action webook'));
|
.catch((err) => this.logger.info({err}, 'rasa - error w/ action webook'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.ep.connected) {
|
||||||
await this.ep.api('uuid_break', this.ep.uuid).catch((err) => this.logger.info(err, 'Error killing audio'));
|
await this.ep.api('uuid_break', this.ep.uuid).catch((err) => this.logger.info(err, 'Error killing audio'));
|
||||||
}
|
}
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
@@ -70,14 +77,31 @@ class Rasa extends Task {
|
|||||||
say: sayOpts
|
say: sayOpts
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.logger.debug({opts}, 'constructing a nested gather object');
|
//this.logger.debug({opts}, 'constructing a nested gather object');
|
||||||
const gather = makeTask(this.logger, {gather: opts}, this);
|
const gather = makeTask(this.logger, {gather: opts}, this);
|
||||||
return gather;
|
return gather;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onTranscription(cs, ep, evt) {
|
async _onTranscription(cs, ep, evt) {
|
||||||
this.logger.debug({evt}, `Rasa: got transcription for callSid ${cs.callSid}`);
|
//this.logger.debug({evt}, `Rasa: got transcription for callSid ${cs.callSid}`);
|
||||||
const utterance = evt.alternatives[0].transcript;
|
const utterance = evt.alternatives[0].transcript;
|
||||||
|
|
||||||
|
if (this.eventHook) {
|
||||||
|
this.performHook(cs, this.eventHook, {event: 'userMessage', message: utterance})
|
||||||
|
.then((redirected) => {
|
||||||
|
if (redirected) {
|
||||||
|
this.logger.info('Rasa_onTranscription: event handler for user message redirected us to new webhook');
|
||||||
|
this.reportedFinalAction = true;
|
||||||
|
this.performAction({rasaResult: 'redirect'}, false);
|
||||||
|
if (this.gatherTask) this.gatherTask.kill(cs);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
})
|
||||||
|
.catch(({err}) => {
|
||||||
|
this.logger.info({err}, 'Rasa_onTranscription: error sending event hook');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = {
|
const payload = {
|
||||||
sender: cs.callSid,
|
sender: cs.callSid,
|
||||||
@@ -90,17 +114,38 @@ class Rasa extends Task {
|
|||||||
response.reduce((prev, current) => `${prev} ${current.text}`, '') :
|
response.reduce((prev, current) => `${prev} ${current.text}`, '') :
|
||||||
null;
|
null;
|
||||||
if (botUtterance) {
|
if (botUtterance) {
|
||||||
this.logger.debug({botUtterance}, 'playing out bot utterance');
|
this.logger.debug({botUtterance}, 'Rasa:_onTranscription: got user utterance');
|
||||||
this.gatherTask = this._makeGatherTask(botUtterance);
|
this.gatherTask = this._makeGatherTask(botUtterance);
|
||||||
this.gatherTask.exec(cs, ep, this)
|
this.gatherTask.exec(cs, ep, this)
|
||||||
.catch((err) => this.logger.info({err}, 'Rasa gather task returned error'));
|
.catch((err) => this.logger.info({err}, 'Rasa gather task returned error'));
|
||||||
|
if (this.eventHook) {
|
||||||
|
this.performHook(cs, this.eventHook, {event: 'botMessage', message: botUtterance})
|
||||||
|
.then((redirected) => {
|
||||||
|
if (redirected) {
|
||||||
|
this.logger.info('Rasa_onTranscription: event handler for bot message redirected us to new webhook');
|
||||||
|
this.reportedFinalAction = true;
|
||||||
|
this.performAction({rasaResult: 'redirect'}, false);
|
||||||
|
if (this.gatherTask) this.gatherTask.kill(cs);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
})
|
||||||
|
.catch(({err}) => {
|
||||||
|
this.logger.info({err}, 'Rasa_onTranscription: error sending event hook');
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error({err}, 'Error sending');
|
this.logger.error({err}, 'Rasa_onTranscription: Error sending user utterance to Rasa - ending task');
|
||||||
|
this.performAction({rasaResult: 'webhookError'});
|
||||||
|
this.reportedFinalAction = true;
|
||||||
|
this.notifyTaskDone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_onTimeout(cs, ep, evt) {
|
_onTimeout(cs, ep, evt) {
|
||||||
this.logger.debug({evt}, 'Rasa: got timeout');
|
this.logger.debug({evt}, 'Rasa: got timeout');
|
||||||
|
if (!this.hasReportedFinalAction) this.performAction({rasaResult: 'timeout'});
|
||||||
|
this.reportedFinalAction = true;
|
||||||
|
this.notifyTaskDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,25 @@ class Task extends Emitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async performHook(cs, hook, results) {
|
||||||
|
const json = await cs.requestor.request(hook, results);
|
||||||
|
if (json && Array.isArray(json)) {
|
||||||
|
const makeTask = require('./make_task');
|
||||||
|
const tasks = normalizeJambones(this.logger, json).map((tdata) => makeTask(this.logger, tdata));
|
||||||
|
if (tasks && tasks.length > 0) {
|
||||||
|
this.redirect(cs, tasks);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect(cs, tasks) {
|
||||||
|
this.logger.info({tasks: tasks}, `${this.name} replacing application with ${tasks.length} tasks`);
|
||||||
|
this.isReplacingApplication = true;
|
||||||
|
cs.replaceApplication(tasks);
|
||||||
|
}
|
||||||
|
|
||||||
async transferCallToFeatureServer(cs, sipAddress, opts) {
|
async transferCallToFeatureServer(cs, sipAddress, opts) {
|
||||||
const uuid = uuidv4();
|
const uuid = uuidv4();
|
||||||
const {addKey} = cs.srf.locals.dbHelpers;
|
const {addKey} = cs.srf.locals.dbHelpers;
|
||||||
|
|||||||
Reference in New Issue
Block a user