diff --git a/Readme.md b/Readme.md index c5a8dec..083a531 100644 --- a/Readme.md +++ b/Readme.md @@ -7,7 +7,7 @@ A node.js client for the [Dialog](https://dialoganalytics.com) API. ## Examples -- Amazon Alexa (soon) +- [Amazon Alexa](https://github.com/dialoganalytics/alexa-node-example) - Google Actions (soon) - [Facebook Messenger with Botkit](https://github.com/dialoganalytics/botkit-messenger-example) - [Twilio Programmable Chat with Botkit](https://github.com/dialoganalytics/botkit-twilio-ipm-example) diff --git a/lib/alexa/incoming.js b/lib/alexa/incoming.js new file mode 100644 index 0000000..252a87f --- /dev/null +++ b/lib/alexa/incoming.js @@ -0,0 +1,68 @@ +'use strict'; + +var locale = require('./locale') + +// Incoming payload for Dialog API +// +// { +// "session": { +// "sessionId": "SessionId.5531df55-fed9-4a8e-9217-afb2b1deb955", +// "application": { +// "applicationId": "amzn1.ask.skill.1b83076b-8262-4da4-a773-43a58ee9a821" +// }, +// "attributes": {}, +// "user": { +// "userId": "amzn1.ask.account.AFLTEFO4OZJWRSSB5QRZ7GPQAGY72ZW4CIGRDXMWUXAUN6SYTTX2GRD4GER6GJ3GNGTFSOEDP56MJMFPQCYIGPSCTQHA33ZOKQWDDU2TXFOPM5F3WFEG5SBJXEZYN7K45UH63NXC65C77KAW4RX52OR7ESPNBYQF4SEEB4CVEQH6FR4YVNMIMS5PW4IVTO245XKD7VF2M4UHVQY" +// }, +// "new": true +// }, +// "request": { +// "type": "IntentRequest", +// "requestId": "EdwRequestId.03f17ea3-e95f-43a5-96f9-428cca0cdd87", +// "locale": "en-US", +// "timestamp": "2017-01-20T16:47:18Z", +// "intent": { +// "name": "GetName", +// "slots": { +// "Name": { +// "name": "Name", +// "value": "Nick" +// } +// } +// } +// }, +// "version": "1.0" +// } +// +// @param {Object} payload +function incomingPayload(payload) { + return { + message: { + distinct_id: payload.request.requestId, + platform: 'alexa', + provider: 'dialog-node', + mtype: 'text', + sent_at: Date.parse(payload.request.timestamp) / 1000, + properties: { + text: "TODO" + } + }, + conversation: { + distinct_id: payload.session.sessionId + }, + creator: { + distinct_id: payload.user.userId, + type: 'interlocutor', + locale: locale(payload.request.locale) + } + }; +} + +// @param {Object} client +// @param {Object} payload Payload received from Alexa +// @param {Function} callback +function incoming(that.client, payload, callback) { + return client.track(incomingPayload(payload), callback); +}; + +module.exports = incoming; diff --git a/lib/alexa/index.js b/lib/alexa/index.js new file mode 100644 index 0000000..719debe --- /dev/null +++ b/lib/alexa/index.js @@ -0,0 +1,99 @@ +'use strict'; + +var Client = require("../client"); + +var incomingHandler = require("./incoming"); +var outgoingHandler = require("./outgoing"); + +module.exports = function(apiToken, botId) { + var that = this; + + this.client = new Client(apiToken, botId); + + this.incoming = function(payload, callback) { + incomingHandler(that.client, payload, callback) + }; + + this.outgoing = function(payload, response, callback) { + outgoingHandler(that.client, payload, response, callback) + }; + + return this; +}; + +// Valid event types +// INITIALIZE +// INSTALL +// SESSION_START +// SPEECH +// SESSION_END + +/** +* Fires the track event and executes the callback +* function with the speech output SSML + response +* @param {String} intentName The intent string +* @param {Object} intentMetadata Object containing intent metadata like slots +* @param {String} speechText String speech out by Alexa +* @param {Function} cb Callback function for success +* @return {Void} +*/ +track: function(intentName, intentMetadata, speechText, cb){ + var error = false; + + //Error check to make sure we have everything we need + if(!config.app_token || !config.app_token.length || !_.isString(config.app_token)){ + console.error(errors.noTokenError); + error = true; + } + + if(!config.session_id){ + console.error(errors.invalidSessionId); + error = true; + } + + if(!config.user_hashed_id){ + console.error(errors.invalidUserError); + error = true; + } + + if(!intentName) { + console.error(errors.invalidIntentNameError); + error = true; + } + + if(error){ + if(_.isFunction(cb)){ + cb({ + error: 'Invalid arguments passed to track(). See standard error for details.' + }); + } + + return; + } + + var payload = { + app_token: config.app_token, + user_hashed_id: config.user_hashed_id, + session_id: config.session_id, + intent: intentName, + data: { + metadata: intentMetadata, + speech: speechText, + }, + }; + + // check if session exists + if(!initialized){ + initialized = true; + config.agent = 'alexa'; + + // trigger session event + trigger(Enums.eventTypes.INITIALIZE, config, function(){ + // trigger speech event + trigger(Enums.eventTypes.SPEECH, payload, cb); + }); + }else{ + // trigger speech event + trigger(Enums.eventTypes.SPEECH, payload, cb); + } +} diff --git a/lib/alexa/locale.js b/lib/alexa/locale.js new file mode 100644 index 0000000..d5ad32e --- /dev/null +++ b/lib/alexa/locale.js @@ -0,0 +1,10 @@ +'use strict'; + +// Converts a Amazon locale into ISO 639-1 format +// @param {String} Amazon locale formated like 'en-US' +// @returns {String} ISO 639-1 locale. Example: 'en' +function locale(locale) { + return locale.split('-')[0]; +}; + +module.exports = locale; diff --git a/lib/alexa/outgoing.js b/lib/alexa/outgoing.js new file mode 100644 index 0000000..19506aa --- /dev/null +++ b/lib/alexa/outgoing.js @@ -0,0 +1,54 @@ +'use strict'; + +{ + "version": "1.0", + "response": { + // "outputSpeech": { + // "type": "SSML", + // "ssml": " Hello World! " + // }, + "outputSpeech": { + "type": "PlainText", + "text": "I think Nick is a good old pal" + }, + "card": { + "content": "I think Nick is a good old pal", + "title": "Dialog", + "type": "Simple" + }, + "shouldEndSession": false + }, + "sessionAttributes": {} +} + +function outgoingPayload(payload) { + return { + message: { + distinct_id: , + provider: , + platform: , + mtype: 'text', + sent_at: , + properties: { + + } + }, + conversation: { + distinct_id: + }, + creator: { + distinct_id: '', + type: 'bot' + } + }; +} + +// @param {Object} client +// @param {Object} data Payload sent to Alexa API +// @param {Object} event Response from Alexa API +// @param {Function} callback +function outgoing(that.client, payload, response, callback) { + return client.track(outgoingPayload(payload), callback); +}; + +module.exports = outgoing;