diff --git a/lib/tasks/lex.js b/lib/tasks/lex.js index 811049ac..a8703220 100644 --- a/lib/tasks/lex.js +++ b/lib/tasks/lex.js @@ -7,10 +7,16 @@ class Lex extends Task { super(logger, opts); this.preconditions = TaskPreconditions.Endpoint; - this.credentials = this.data.credentials; - this.bot = this.data.bot; - this.alias = this.data.alias; + if (this.data.credentials) { + this.awsAccessKeyId = this.data.credentials.accessKey; + this.awsSecretAccessKey = this.data.credentials.secretAccessKey; + } + this.bot = this.data.botId; + this.alias = this.data.botAlias; this.region = this.data.region; + this.locale = this.data.locale || 'en_US'; + this.intent = this.data.intent; + this.welcomeMessage = this.data.welcomeMessage; this.bargein = this.data.bargein || false; this.passDtmf = this.data.passDtmf || false; if (this.data.noInputTimeout) this.noInputTimeout = this.data.noInputTimeout * 1000; @@ -22,12 +28,8 @@ class Lex extends Task { this.botName = `${this.bot}:${this.alias}:${this.region}`; if (this.data.eventHook) this.eventHook = this.data.eventHook; - if (this.eventHook && Array.isArray(this.data.events)) { - this.events = this.data.events; - } - else if (this.eventHook) { - // send all events by default - except interim transcripts - this.events = [ + this.events = this.eventHook ? + [ 'intent', 'transcription', 'dtmf', @@ -35,11 +37,7 @@ class Lex extends Task { 'stop-play', 'play-interrupted', 'response-text' - ]; - } - else { - this.events = []; - } + ] : []; if (this.data.actionHook) this.actionHook = this.data.actionHook; } @@ -51,10 +49,10 @@ class Lex extends Task { try { await this.init(cs, ep); - this.logger.debug(`starting lex bot ${this.botName}`); + this.logger.debug(`starting lex bot ${this.botName} with locale ${this.locale}`); // kick it off - this.ep.api('aws_lex_start', `${this.ep.uuid} ${this.bot} ${this.alias} ${this.region}`) + this.ep.api('aws_lex_start', `${this.ep.uuid} ${this.bot} ${this.alias} ${this.region} ${this.locale}`) .catch((err) => { this.logger.error({err}, `Error starting lex bot ${this.botName}`); this.notifyTaskDone(); @@ -102,12 +100,25 @@ class Lex extends Task { this.ep.addCustomEventListener('lex::error', this._onError.bind(this, ep, cs)); this.ep.on('dtmf', this._onDtmf.bind(this, ep, cs)); + const channelVars = {}; if (this.bargein) { - await this.ep.set('x-amz-lex:barge-in-enabled', 1); + Object.assign(channelVars, {'x-amz-lex:barge-in-enabled': 1}); } if (this.noInputTimeout) { - await this.ep.set('x-amz-lex:start-silence-threshold-ms', this.noInputTimeout); + Object.assign(channelVars, {'x-amz-lex:audio:start-timeout-ms': this.noInputTimeout}); } + if (this.awsAccessKeyId && this.awsSecretAccessKey) { + Object.assign(channelVars, { + AWS_ACCESS_KEY_ID: this.awsAccessKeyId, + AWS_SECRET_ACCESS_KEY: this.awsSecretAccessKey + }); + } + if (this.vendor) Object.assign(channelVars, {LEX_USE_TTS: 1}); + if (this.intent && this.intent.length) Object.assign(channelVars, {LEX_WELCOME_INTENT: this.intent}); + if (this.welcomeMessage && this.welcomeMessage.length) { + Object.assign(channelVars, {LEX_WELCOME_MESSAGE: this.welcomeMessage}); + } + if (Object.keys(channelVars).length) await this.ep.set(channelVars); } catch (err) { this.logger.error({err}, 'Error setting listeners'); @@ -149,37 +160,42 @@ class Lex extends Task { */ async _onTextResponse(ep, cs, evt) { this.logger.debug({evt}, `got text response for ${this.botName}`); + const messages = evt.messages; if (this.events.includes('response-text')) { this._performHook(cs, this.eventHook, {event: 'response-text', data: evt}); } - if (this.vendor && ['PlainText', 'SSML'].includes(evt.type) && evt.msg) { - const {srf} = cs; - const {synthAudio} = srf.locals.dbHelpers; + if (this.vendor && Array.isArray(messages) && messages.length) { + const msg = messages[0].msg; + const type = messages[0].type; + if (['PlainText', 'SSML'].includes(type) && msg) { + const {srf} = cs; + const {synthAudio} = srf.locals.dbHelpers; - try { - this.logger.debug(`tts with ${this.vendor} ${this.voice}`); - const fp = await synthAudio({ - text: evt.msg, - vendor: this.vendor, - language: this.language, - voice: this.voice, - salt: cs.callSid - }); - if (fp) cs.trackTmpFile(fp); - if (this.events.includes('start-play')) { - this._performHook(cs, this.eventHook, {event: 'start-play', data: {path: fp}}); - } - await ep.play(fp); - if (this.events.includes('stop-play')) { - this._performHook(cs, this.eventHook, {event: 'stop-play', data: {path: fp}}); - } - this.logger.debug(`finished tts, sending play_done ${this.vendor} ${this.voice}`); - this.ep.api('aws_lex_play_done', this.ep.uuid) - .catch((err) => { - this.logger.error({err}, `Error sending play_done ${this.botName}`); + try { + this.logger.debug(`tts with ${this.vendor} ${this.voice}`); + const fp = await synthAudio({ + text: msg, + vendor: this.vendor, + language: this.language, + voice: this.voice, + salt: cs.callSid }); - } catch (err) { - this.logger.error({err}, 'Lex:_onTextResponse - error playing tts'); + if (fp) cs.trackTmpFile(fp); + if (this.events.includes('start-play')) { + this._performHook(cs, this.eventHook, {event: 'start-play', data: {path: fp}}); + } + await ep.play(fp); + if (this.events.includes('stop-play')) { + this._performHook(cs, this.eventHook, {event: 'stop-play', data: {path: fp}}); + } + this.logger.debug(`finished tts, sending play_done ${this.vendor} ${this.voice}`); + this.ep.api('aws_lex_play_done', this.ep.uuid) + .catch((err) => { + this.logger.error({err}, `Error sending play_done ${this.botName}`); + }); + } catch (err) { + this.logger.error({err}, 'Lex:_onTextResponse - error playing tts'); + } } } } diff --git a/lib/tasks/specs.json b/lib/tasks/specs.json index 6bee22a1..0c610818 100644 --- a/lib/tasks/specs.json +++ b/lib/tasks/specs.json @@ -152,14 +152,17 @@ }, "lex": { "properties": { - "bot": "string", - "alias": "string", + "botId": "string", + "botAlias": "string", + "credentials": "object", "region": "string", + "locale": "string", + "intent": "string", + "welcomeMessage": "string", "bargein": "boolean", "passDtmf": "boolean", "actionHook": "object|string", "eventHook": "object|string", - "events": "[string]", "prompt": { "type": "string", "enum": ["lex", "tts"] @@ -168,8 +171,8 @@ "tts": "#synthesizer" }, "required": [ - "bot", - "alias", + "botId", + "botAlias", "region", "prompt" ] diff --git a/package-lock.json b/package-lock.json index dce753e3..3cfb91f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -376,12 +376,12 @@ } }, "@jambonz/realtimedb-helpers": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.2.17.tgz", - "integrity": "sha512-ferdg3ze4juzHKB8ZkR5s9c31V6YDZPwFQIoHWne2DG2ZhKL9dNwWyHBBjT0jdUjzWCGDM8Ly9o9VPbQC+fbOA==", + "version": "0.2.18", + "resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.2.18.tgz", + "integrity": "sha512-OihQ6/mx8yXv8D8pVOnGWAe4VNiS7Iu7UGmFA6X/iVefs4DZAnlGsGcNpY6lxTqrPgirPF3tFQWY+4gQmhzKqg==", "requires": { "@google-cloud/text-to-speech": "^3.1.1", - "@jambonz/stats-collector": "0.0.4", + "@jambonz/stats-collector": "0.1.0", "aws-sdk": "^2.631.0", "bluebird": "^3.7.2", "debug": "^4.1.1", @@ -390,12 +390,12 @@ } }, "@jambonz/stats-collector": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@jambonz/stats-collector/-/stats-collector-0.0.4.tgz", - "integrity": "sha512-HgkdJmxNk0LcQ/eB6CTh9C+mxMnFhoR8ykY2CHnEa8IC8wymv2WqeIi9IZ/lKfzUVVzH+EpYqw7GBVghHjdYxQ==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@jambonz/stats-collector/-/stats-collector-0.1.0.tgz", + "integrity": "sha512-5ChS8x4ACAxXv0dNphV27bR3LKJk5wrkljpNW7xUWPmY4UpdGC5GhTlqlxumMYwBOy1N1nw3P50unQNTppm5Vw==", "requires": { - "debug": "^4.1.1", - "hot-shots": "^6.8.7" + "debug": "^4.2.0", + "hot-shots": "^8.2.0" } }, "@protobufjs/aspromise": { @@ -463,9 +463,9 @@ "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, "@types/node": { - "version": "12.12.62", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.62.tgz", - "integrity": "sha512-qAfo81CsD7yQIM9mVyh6B/U47li5g7cfpVQEDMfQeF8pSZVwzbhwU3crc0qG4DmpsebpJPR49AKOExQyJ05Cpg==" + "version": "12.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.1.tgz", + "integrity": "sha512-/xaVmBBjOGh55WCqumLAHXU9VhjGtmyTGqJzFBXRWZzByOXI5JAJNx9xPVGEsNizrNwcec92fQMj458MWfjN1A==" }, "abort-controller": { "version": "3.0.0", @@ -497,9 +497,9 @@ "dev": true }, "agent-base": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz", - "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { "debug": "4" } @@ -602,9 +602,9 @@ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" }, "aws-sdk": { - "version": "2.765.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.765.0.tgz", - "integrity": "sha512-FQdPKJ5LAhNxkpqwrjQ+hiEqEOezV/PfZBn5RcBG6vu8K3VuT4dE12mGTY3qkdHy7lhymeRS5rWcagTmabKFtA==", + "version": "2.778.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.778.0.tgz", + "integrity": "sha512-sIJRO7tMaztLs+gvHF/Wo+iek/rhH99+2OzharQJMS0HATPl5/EdhKgWGv1n/bNpVH+kD3n0QMQgdFu0FNUt0Q==", "requires": { "buffer": "4.9.2", "events": "1.1.1", @@ -1855,25 +1855,25 @@ } }, "google-auth-library": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.0.tgz", - "integrity": "sha512-GbalszIADE1YPWhUyfFMrkLhFHnlAgoRcqGVW+MsLDPsuaOB5MRPk7NNafPDv9SherNE4EKzcYuxMJjaxzXMOw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.2.tgz", + "integrity": "sha512-X9EUX8R+kIpsf55KdSPhFWF0RNyBGuBc1zeYc/5Sjuk65eIYqq91rINJVBD22pp+w/PuM2fasHiA6H2xYjxTIQ==", "requires": { "arrify": "^2.0.0", "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "fast-text-encoding": "^1.0.0", "gaxios": "^3.0.0", - "gcp-metadata": "^4.1.0", - "gtoken": "^5.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", "jws": "^4.0.0", "lru-cache": "^6.0.0" } }, "google-gax": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.9.0.tgz", - "integrity": "sha512-MFMwA7Fb8PEwjnYwfGXjZMidCNyMl3gSnvS/+kS8TQioJZQDpzK+W3dmwyNyig/U13+kbABqDnbkkAXJ5NiUkw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.9.1.tgz", + "integrity": "sha512-KQ7HiMTB/PAzKv3OU00x6tC1H7MHvSxQfon5BSyW5o+lkMgRA8xoqvlxZCBC1dlW1azOPGF8vScy8QgFmhaQ9Q==", "requires": { "@grpc/grpc-js": "~1.1.1", "@grpc/proto-loader": "^0.5.1", @@ -1901,12 +1901,12 @@ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, "gtoken": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", - "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", + "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", "requires": { "gaxios": "^3.0.0", - "google-p12-pem": "^3.0.0", + "google-p12-pem": "^3.0.3", "jws": "^4.0.0", "mime": "^2.2.0" }, @@ -1967,9 +1967,9 @@ } }, "hot-shots": { - "version": "6.8.7", - "resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-6.8.7.tgz", - "integrity": "sha512-XH8iezBSZgVw2jegu96pUfF1Zv0VZ/iXjb7L5yE3F7mn7/bdhf4qeniXjO0wQWeefe433rhOsazNKLxM+XMI9w==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-8.2.0.tgz", + "integrity": "sha512-k0J7QAMGWAawZr8b+Bgornns9IlBaV1p0X6Ju/OTye2QLf+u1KuD9NEbSU4IShviyr1tSOUBUxrEm2QSlx2Nfw==", "requires": { "unix-dgram": "2.0.x" } @@ -2604,9 +2604,9 @@ } }, "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", "optional": true }, "natural-compare": { @@ -2968,9 +2968,9 @@ }, "dependencies": { "@types/node": { - "version": "13.13.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.21.tgz", - "integrity": "sha512-tlFWakSzBITITJSxHV4hg4KvrhR/7h3xbJdSFbYJBVzKubrASbnnIFuSgolUh7qKGo/ZeJPKUfbZ0WS6Jp14DQ==" + "version": "13.13.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.28.tgz", + "integrity": "sha512-EM/qFeRH8ZCD+TlsaIPULyyFm9vOhFIvgskY2JmHbEsWsOPgN+rtjSXrcHGgJpob4Nu17VfO95FKewr0XY7iOQ==" } } }, @@ -3858,9 +3858,9 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, "unix-dgram": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unix-dgram/-/unix-dgram-2.0.3.tgz", - "integrity": "sha512-Bay5CkSLcdypcBCsxvHEvaG3mftzT5FlUnRToPWEAVxwYI8NI/8zSJ/Gknlp86MPhV6hBA8I8TBsETj2tssoHQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/unix-dgram/-/unix-dgram-2.0.4.tgz", + "integrity": "sha512-7tpK6x7ls7J7pDrrAU63h93R0dVhRbPwiRRCawR10cl+2e1VOvF3bHlVJc6WI1dl/8qk5He673QU+Ogv7bPNaw==", "optional": true, "requires": { "bindings": "^1.3.0", diff --git a/package.json b/package.json index 48a4ece4..fe12e306 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,8 @@ }, "dependencies": { "@jambonz/db-helpers": "^0.5.1", - "@jambonz/realtimedb-helpers": "^0.2.17", - "@jambonz/stats-collector": "^0.0.4", + "@jambonz/realtimedb-helpers": "^0.2.18", + "@jambonz/stats-collector": "^0.1.0", "bent": "^7.3.12", "cidr-matcher": "^2.1.1", "debug": "^4.2.0",