mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 16:50:39 +00:00
initial support for Rasa
This commit is contained in:
@@ -202,7 +202,6 @@ class CallSession extends Emitter {
|
||||
*/
|
||||
getSpeechCredentials(vendor, type) {
|
||||
const {writeAlerts, AlertType} = this.srf.locals;
|
||||
this.logger.debug({vendor, type, speech: this.accountInfo.speech}, `searching for speech for vendor ${vendor}`);
|
||||
if (this.accountInfo.speech && this.accountInfo.speech.length > 0) {
|
||||
const credential = this.accountInfo.speech.find((s) => s.vendor === vendor);
|
||||
if (credential && (
|
||||
|
||||
@@ -10,7 +10,7 @@ const makeTask = require('./make_task');
|
||||
const assert = require('assert');
|
||||
|
||||
class TaskGather extends Task {
|
||||
constructor(logger, opts) {
|
||||
constructor(logger, opts, parentTask) {
|
||||
super(logger, opts);
|
||||
this.preconditions = TaskPreconditions.Endpoint;
|
||||
|
||||
@@ -40,6 +40,8 @@ class TaskGather extends Task {
|
||||
|
||||
if (this.say) this.sayTask = makeTask(this.logger, {say: this.say}, this);
|
||||
if (this.play) this.playTask = makeTask(this.logger, {play: this.play}, this);
|
||||
|
||||
this.parentTask = parentTask;
|
||||
}
|
||||
|
||||
get name() { return TaskName.Gather; }
|
||||
@@ -154,7 +156,6 @@ class TaskGather extends Task {
|
||||
});
|
||||
ep.addCustomEventListener(AwsTranscriptionEvents.Transcription, this._onTranscription.bind(this, cs, ep));
|
||||
}
|
||||
this.logger.debug({vars: opts}, 'setting freeswitch vars');
|
||||
await ep.set(opts)
|
||||
.catch((err) => this.logger.info(err, 'Error setting channel variables'));
|
||||
|
||||
@@ -235,7 +236,11 @@ class TaskGather extends Task {
|
||||
await this.performAction({digits: this.digitBuffer});
|
||||
}
|
||||
else if (reason.startsWith('speech')) {
|
||||
await this.performAction({speech: evt});
|
||||
if (this.parentTask) this.parentTask.emit('transcription', evt);
|
||||
else await this.performAction({speech: evt});
|
||||
}
|
||||
else if (reason.startsWith('timeout') && this.parentTask) {
|
||||
this.parentTask.emit('timeout', evt);
|
||||
}
|
||||
this.notifyTaskDone();
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ function makeTask(logger, obj, parent) {
|
||||
case TaskName.Message:
|
||||
const TaskMessage = require('./message');
|
||||
return new TaskMessage(logger, data, parent);
|
||||
case TaskName.Rasa:
|
||||
const TaskRasa = require('./rasa');
|
||||
return new TaskRasa(logger, data, parent);
|
||||
case TaskName.Say:
|
||||
const TaskSay = require('./say');
|
||||
return new TaskSay(logger, data, parent);
|
||||
|
||||
109
lib/tasks/rasa.js
Normal file
109
lib/tasks/rasa.js
Normal file
@@ -0,0 +1,109 @@
|
||||
const Task = require('./task');
|
||||
const {TaskName, TaskPreconditions} = require('../utils/constants');
|
||||
const makeTask = require('./make_task');
|
||||
const bent = require('bent');
|
||||
|
||||
class Rasa extends Task {
|
||||
constructor(logger, opts) {
|
||||
super(logger, opts);
|
||||
this.preconditions = TaskPreconditions.Endpoint;
|
||||
|
||||
this.prompt = this.data.prompt;
|
||||
this.eventHook = this.data?.eventHook;
|
||||
this.actionHook = this.data?.actionHook;
|
||||
this.post = bent('POST', 'json', 200);
|
||||
}
|
||||
|
||||
get name() { return TaskName.Rasa; }
|
||||
|
||||
async exec(cs, ep) {
|
||||
await super.exec(cs);
|
||||
|
||||
this.ep = ep;
|
||||
try {
|
||||
/* set event handlers */
|
||||
this.on('transcription', this._onTranscription.bind(this, cs, ep));
|
||||
this.on('timeout', this._onTimeout.bind(this, cs, ep));
|
||||
|
||||
/* start the first gather */
|
||||
this.gatherTask = this._makeGatherTask(this.prompt);
|
||||
this.gatherTask.exec(cs, ep, this)
|
||||
.catch((err) => this.logger.info({err}, 'Rasa gather task returned error'));
|
||||
|
||||
await this.awaitTaskDone();
|
||||
} catch (err) {
|
||||
this.logger.error({err}, 'Rasa error');
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async kill(cs) {
|
||||
super.kill(cs);
|
||||
if (this.ep.connected) {
|
||||
this.logger.debug('Rasa:kill');
|
||||
|
||||
this.performAction({rasaResult: 'caller hungup'})
|
||||
.catch((err) => this.logger.error({err}, 'rasa - error w/ action webook'));
|
||||
|
||||
await this.ep.api('uuid_break', this.ep.uuid).catch((err) => this.logger.info(err, 'Error killing audio'));
|
||||
}
|
||||
this.removeAllListeners();
|
||||
this.notifyTaskDone();
|
||||
}
|
||||
|
||||
_makeGatherTask(prompt) {
|
||||
let opts = {
|
||||
input: ['speech'],
|
||||
timeout: this.data.timeout || 10,
|
||||
recognizer: this.data.recognizer || {
|
||||
vendor: 'default',
|
||||
language: 'default'
|
||||
}
|
||||
};
|
||||
if (prompt) {
|
||||
const sayOpts = this.data.tts ?
|
||||
{text: prompt, synthesizer: this.data.tts} :
|
||||
{text: prompt};
|
||||
|
||||
opts = {
|
||||
...opts,
|
||||
say: sayOpts
|
||||
};
|
||||
}
|
||||
this.logger.debug({opts}, 'constructing a nested gather object');
|
||||
const gather = makeTask(this.logger, {gather: opts}, this);
|
||||
return gather;
|
||||
}
|
||||
|
||||
async _onTranscription(cs, ep, evt) {
|
||||
this.logger.debug({evt}, `Rasa: got transcription for callSid ${cs.callSid}`);
|
||||
const utterance = evt.alternatives[0].transcript;
|
||||
try {
|
||||
const payload = {
|
||||
sender: cs.callSid,
|
||||
message: utterance
|
||||
};
|
||||
this.logger.debug({payload}, 'Rasa:_onTranscription - sending payload to Rasa');
|
||||
const response = await this.post(this.data.url, payload);
|
||||
this.logger.debug({response}, 'Rasa:_onTranscription - got response from Rasa');
|
||||
const botUtterance = Array.isArray(response) ?
|
||||
response.reduce((prev, current) => `${prev} ${current.text}`, '') :
|
||||
null;
|
||||
if (botUtterance) {
|
||||
this.logger.debug({botUtterance}, 'playing out bot utterance');
|
||||
this.gatherTask = this._makeGatherTask(botUtterance);
|
||||
this.gatherTask.exec(cs, ep, this)
|
||||
.catch((err) => this.logger.info({err}, 'Rasa gather task returned error'));
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error({err}, 'Error sending');
|
||||
}
|
||||
}
|
||||
_onTimeout(cs, ep, evt) {
|
||||
this.logger.debug({evt}, 'Rasa: got timeout');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = Rasa;
|
||||
@@ -78,7 +78,6 @@
|
||||
"say": "#say"
|
||||
},
|
||||
"required": [
|
||||
"actionHook"
|
||||
]
|
||||
},
|
||||
"conference": {
|
||||
@@ -228,6 +227,19 @@
|
||||
"length"
|
||||
]
|
||||
},
|
||||
"rasa": {
|
||||
"properties": {
|
||||
"url": "string",
|
||||
"recognizer": "#recognizer",
|
||||
"tts": "#synthesizer",
|
||||
"prompt": "string",
|
||||
"actionHook": "object|string",
|
||||
"eventHook": "object|string"
|
||||
},
|
||||
"required": [
|
||||
"url"
|
||||
]
|
||||
},
|
||||
"redirect": {
|
||||
"properties": {
|
||||
"actionHook": "object|string"
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"Message": "message",
|
||||
"Pause": "pause",
|
||||
"Play": "play",
|
||||
"Rasa": "rasa",
|
||||
"Redirect": "redirect",
|
||||
"RestDial": "rest:dial",
|
||||
"SipDecline": "sip:decline",
|
||||
|
||||
Reference in New Issue
Block a user