From b07a9e21b363aa4305b2d30afd148c6db6f8ea0d Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 07:43:10 +0100 Subject: [PATCH 01/31] Testing dialog handler --- backend/helpers/amazon.js | 221 ++++++++++++++++++++++++++++---------- backend/models/alexa.js | 15 ++- 2 files changed, 174 insertions(+), 62 deletions(-) diff --git a/backend/helpers/amazon.js b/backend/helpers/amazon.js index d6c554b..6d1b553 100644 --- a/backend/helpers/amazon.js +++ b/backend/helpers/amazon.js @@ -37,15 +37,22 @@ var refreshTokens = function () { request (options, function (error, response, body) { if (error) { reject (error); - }else{ + } else { parsedResponse = JSON.parse (body); - if (parsedResponse.refresh_token){ - databaseHelper.updateTokens(parsedResponse.refresh_token, parsedResponse.access_token, parsedResponse.expires_in).then(()=>{ - resolve(); - }).catch(e=>{ - reject(e); - }); - }else{ + if (parsedResponse.refresh_token) { + databaseHelper + .updateTokens ( + parsedResponse.refresh_token, + parsedResponse.access_token, + parsedResponse.expires_in + ) + .then (() => { + resolve (); + }) + .catch (e => { + reject (e); + }); + } else { reject (body); } } @@ -56,81 +63,181 @@ var refreshTokens = function () { var generateInteractionModel = function (skill) { let result = {}; let allIntents = []; - let defaultIntents = [ - { - name: 'AMAZON.CancelIntent', - samples: [], - }, - { - name: 'AMAZON.HelpIntent', - samples: [], - }, - { - name: 'AMAZON.StopIntent', - samples: [], - }, - ]; - - /* - defaultIntents.map(intent=>{ - allIntents.push(intent); - }); - */ skill.intents.map (intent => { allIntents.push ({name: intent.intentName, samples: intent.questions}); }); - //Special Email Intents : - /* - allIntents.push ({ - name: 'EmailIntentLaunch', - slots: [], - samples: [ - 'I want to send a message', - 'I would like to send a message', - 'I would like to leave a message', - 'Leave a message', - ], - }); + //Special intent for sending message (Dialog) allIntents.push ({ - name: 'EmailIntent', + name: 'SendMessageIntent', + samples: [ + 'I would like to send a message', + 'I want to send a message', + 'Send message', + ], slots: [ { name: 'Name', type: 'AMAZON.US_FIRST_NAME', + samples: ['My name is {Name}', 'I am {Name}', '{Name}'], }, { name: 'Email', - type: 'AMAZON.LITERAL', + type: 'EmailSlot', + samples: ['My email is {Email}', '{Email}'], }, { name: 'Message', - type: 'AMAZON.LITERAL', + type: 'MessageSlot', + samples: ['{Message}'], }, - { - name: 'Data', - type: 'AMAZON.LITERAL', - }, - ], - - samples: [ - 'My name is {Name}', - 'I am {Name}', - '{exampleww at wwdwdw|Data}', - 'My email is {example at efefegedd|Email}', - 'Send replay to {example at abcdefg|Email}', - 'My message is {The quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.|Message}', ], }); - */ + + let customSlotTypes = [ + { + name: 'EmailSlot', + values: [ + { + id: null, + name: { + value: 'bla@bla.bla', + synonyms: [], + }, + }, + { + id: null, + name: { + value: 'bla.bla@bla.bla.bla', + synonyms: [], + }, + }, + { + id: null, + name: { + value: 'bla_bla@bla.bla', + synonyms: [], + }, + }, + ], + }, + { + name: 'MessageSlot', + values: [ + { + id: null, + name: { + value: 'Quick brown fox jumps over lazy dog', + synonyms: [], + }, + }, + { + id: null, + name: { + value: 'Quick brown fox jumps over lazy dog. Quick brown fox jumps over lazy dog.', + synonyms: [], + }, + }, + { + id: null, + name: { + value: 'Quick brown fox jumps over lazy dog. Quick brown fox jumps over lazy dog. Quick brown fox jumps over lazy dog.', + synonyms: [], + }, + }, + ], + }, + ]; + + let dialogPrompts = [ + { + id: 'Elicit.Intent-SendMessageIntent.IntentSlot-Name', + variations: [ + { + type: 'PlainText', + value: 'What is your name ?', + }, + { + type: 'PlainText', + value: 'Tell me your name', + }, + ], + }, + { + id: 'Elicit.Intent-SendMessageIntent.IntentSlot-Email', + variations: [ + { + type: 'PlainText', + value: 'What is your email ?', + }, + { + type: 'PlainText', + value: 'Tell me your email', + }, + ], + }, + { + id: 'Elicit.Intent-SendMessageIntent.IntentSlot-Message', + variations: [ + { + type: 'PlainText', + value: 'What is your message', + }, + ], + }, + ]; + + let dialogIntents = [ + { + name: 'SendMessageIntent', + confirmationRequired: false, + prompts: {}, + slots: [ + { + name: 'Name', + type: 'AMAZON.US_FIRST_NAME', + elicitationRequired: true, + confirmationRequired: false, + prompts: { + elicitation: 'Elicit.Intent-SendMessageIntent.IntentSlot-Name', + }, + }, + { + name: 'Email', + type: 'EmailSlot', + elicitationRequired: true, + confirmationRequired: false, + prompts: { + elicitation: 'Elicit.Intent-SendMessageIntent.IntentSlot-Email', + }, + }, + { + name: 'Message', + type: 'MessageSlot', + elicitationRequired: true, + confirmationRequired: false, + prompts: { + elicitation: 'Elicit.Intent-SendMessageIntent.IntentSlot-Message', + }, + }, + ], + }, + ]; + + let dialog = { + intents: dialogIntents, + }; result.interactionModel = {}; result.interactionModel.languageModel = { invocationName: skill.invocationName, + types: customSlotTypes, intents: allIntents, + prompts: dialogPrompts, + dialog: dialog, }; return JSON.stringify (result); diff --git a/backend/models/alexa.js b/backend/models/alexa.js index d95c855..ff303e6 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -53,19 +53,24 @@ module.exports = { }; }); + //Handler for sending message + handlers.SendMessageIntent = function () { + console.log("Dialog state : " + this.event.request.dialogState); + console.log("Intent object :"); + console.log(this.event.request.intent); + }; + //Default handlers for unknown questions and session close handlers.Unhandled = function () { this.response .speak (constants.voiceResponseStrings.QUESTION_NOT_FOUND) .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); - } + }; - handlers.SessionEndedRequest = function(){ + handlers.SessionEndedRequest = function () { //We don't care for now - } - - + }; }) .catch (e => { //Something is wrong, skill is not ready, use catch-all intent to inform user -- 2.47.3 From 4b594898b149fa796473b56fa4f61f5cb8216d72 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 08:00:51 +0100 Subject: [PATCH 02/31] Complete dialogtest --- backend/models/alexa.js | 52 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/backend/models/alexa.js b/backend/models/alexa.js index ff303e6..4079e98 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -55,9 +55,55 @@ module.exports = { //Handler for sending message handlers.SendMessageIntent = function () { - console.log("Dialog state : " + this.event.request.dialogState); - console.log("Intent object :"); - console.log(this.event.request.intent); + let intent = this.event.request.intent; + + console.log ('Dialog state : ' + this.event.request.dialogState); + console.log ('Intent object :'); + console.log (intent); + + if (this.event.request.dialogState === 'STARTED') { + //Should this be in constants ? + if (!intent.slots.Name.value) { + //Name not defined yet, ask user for name + const slotToElicit = 'Name'; + const speechOutput = 'What is your name'; + const repromptSpeech = speechOutput; + this.emit ( + ':elicitSlot', + slotToElicit, + speechOutput, + repromptSpeech + ); + } else if (!intent.slots.Email.value) { + //Name not defined yet, ask user for email + const slotToElicit = 'Email'; + const speechOutput = 'What is your email'; + const repromptSpeech = speechOutput; + this.emit ( + ':elicitSlot', + slotToElicit, + speechOutput, + repromptSpeech + ); + } else if (!intent.slots.Message.value) { + const slotToElicit = 'Message'; + const speechOutput = 'What is your message'; + const repromptSpeech = speechOutput; + this.emit ( + ':elicitSlot', + slotToElicit, + speechOutput, + repromptSpeech + ); + } else { + //all slots are filled + console.log ('Name : ' + intent.slots.Name.value); + console.log ('Email : ' + intent.slots.Email.value); + console.log ('Message : ' + intents.slots.Message.value); + this.response.speak ('Ok. Someone will contact you ASAP'); + this.emit (':responseReady'); + } + } }; //Default handlers for unknown questions and session close -- 2.47.3 From 2f82709f11f1ebb30b85abca2cfb7ec2e8dad3d5 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 16:29:47 +0100 Subject: [PATCH 03/31] improve dialog ; send email --- backend/config/constants.js | 2 +- backend/helpers/email.js | 58 ++++++++++++++++++++++ backend/models/alexa.js | 99 ++++++++++++++++++++++++------------- backend/package.json | 1 + 4 files changed, 126 insertions(+), 34 deletions(-) create mode 100644 backend/helpers/email.js diff --git a/backend/config/constants.js b/backend/config/constants.js index 6674956..c131195 100644 --- a/backend/config/constants.js +++ b/backend/config/constants.js @@ -27,7 +27,7 @@ constants.HTTPResultCodes = { constants.SKILL_ID_LENGTH = 24; constants.voiceResponseStrings = { - QUESTION_NOT_FOUND : 'Sorry, I didnt understan', + QUESTION_NOT_FOUND : 'Sorry, I didnt understand', GENERIC_CONTINUE : 'Would you like to continue' } diff --git a/backend/helpers/email.js b/backend/helpers/email.js new file mode 100644 index 0000000..575b75c --- /dev/null +++ b/backend/helpers/email.js @@ -0,0 +1,58 @@ +const nodemailer = require ('nodemailer'); + +module.exports = { + validateEmailFromAlexaResponse: function (email) { + //email from alexa response will contain words instead of symbols, like : + //at = @ + //underscore = _ + //dash = - + //dot = . + //TODO: This list should be longer + let transformedEmail = email + .replace (/at/gi, '@') + .replace (/underscore/gi, '_') + .replace (/dash/gi, '-') + .replace (/dot/gi, '.'); + + //Validate here with some email validation regex + + //return true if email is valid + return true; + }, + + sendEmal: function (name, fromEmail, message, toEmail) { + return new Promise ((resolve, reject) => { + let messageBody = + 'Hello. User ' + + name + + ' left you a message on Saburly service using Alexa. Content of the message : ' + + message; + + let transporter = nodemailer.createTransport ({ + host: 'smtp.yandex.com', + port: 465, + secure: true, + auth: { + user: 'saburly@yandex.com', + pass: 'WeAreSaburlyTeam', + }, + }); + + var mailOptions = { + from: fromEmail, + replyTo: fromEmail, + to: toEmail, + subject: 'Message from Saburly service', + text: messageBody, + }; + + transporter.sendMail (mailOptions, (error, info) => { + if (error) { + reject (error); + } else { + resolve (info); + } + }); + }); + }, +}; diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 4079e98..25c80ac 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -1,9 +1,11 @@ var Alexa = require ('alexa-sdk'); const config = require ('../config/config'); var databaseHelper = require ('../helpers/database'); +var emailHelper = require ('../helpers/email'); const constants = require ('../config/constants'); var handlers = {}; +var destinationEmail; module.exports = { run: function (req, res) { @@ -30,6 +32,7 @@ module.exports = { .getSkill (config.SKILL_DB_ID) .then (activeSkill => { handlers = {}; + destinationEmail = activeSkill.contactEmail; //Handler for launch request handlers = { @@ -58,36 +61,42 @@ module.exports = { let intent = this.event.request.intent; console.log ('Dialog state : ' + this.event.request.dialogState); - console.log ('Intent object :'); console.log (intent); + //STARTED, IN_PROGRESS - if (this.event.request.dialogState === 'STARTED') { - //Should this be in constants ? - if (!intent.slots.Name.value) { - //Name not defined yet, ask user for name - const slotToElicit = 'Name'; - const speechOutput = 'What is your name'; - const repromptSpeech = speechOutput; - this.emit ( - ':elicitSlot', - slotToElicit, - speechOutput, - repromptSpeech - ); - } else if (!intent.slots.Email.value) { - //Name not defined yet, ask user for email + if (!intent.slots.Name.value) { + //Name not defined yet, ask user for name + const slotToElicit = 'Name'; + const speechOutput = 'What is your name'; + const repromptSpeech = speechOutput; + this.emit ( + ':elicitSlot', + slotToElicit, + speechOutput, + repromptSpeech + ); + } else if (!intent.slots.Email.value) { + //Name not defined yet, ask user for email + const slotToElicit = 'Email'; + const speechOutput = + 'Ok ' + intent.slots.Name.value + '. What is your email'; + const repromptSpeech = speechOutput; + this.emit ( + ':elicitSlot', + slotToElicit, + speechOutput, + repromptSpeech + ); + } else if (!intent.slots.Message.value) { + if ( + !emailHelper.validateEmailFromAlexaResponse ( + intent.slots.Email.value + ) + ) { + //Email is not valid, ask again const slotToElicit = 'Email'; - const speechOutput = 'What is your email'; - const repromptSpeech = speechOutput; - this.emit ( - ':elicitSlot', - slotToElicit, - speechOutput, - repromptSpeech - ); - } else if (!intent.slots.Message.value) { - const slotToElicit = 'Message'; - const speechOutput = 'What is your message'; + const speechOutput = + 'Sorry, that was not valid email. What is your email'; const repromptSpeech = speechOutput; this.emit ( ':elicitSlot', @@ -96,13 +105,37 @@ module.exports = { repromptSpeech ); } else { - //all slots are filled - console.log ('Name : ' + intent.slots.Name.value); - console.log ('Email : ' + intent.slots.Email.value); - console.log ('Message : ' + intents.slots.Message.value); - this.response.speak ('Ok. Someone will contact you ASAP'); - this.emit (':responseReady'); + //Email is valid + const slotToElicit = 'Message'; + const speechOutput = 'Great. What is your message'; + const repromptSpeech = speechOutput; + this.emit ( + ':elicitSlot', + slotToElicit, + speechOutput, + repromptSpeech + ); } + } else { + //all slots are filled + console.log ('Name : ' + intent.slots.Name.value); + console.log ('Email : ' + intent.slots.Email.value); + console.log ('Message : ' + intent.slots.Message.value); + emailHelper.sendEmal ( + intent.slots.Name.value, + intent.slots.Email.value, + intent.slots.Message.value, + destinationEmail + ).then(info=>{ + this.response.speak ( + 'Ok. Message sent. Someone will contact you ASAP' + ); + }).catch(error=>{ + this.response.speak ( + 'Sorry, there was a problem with sending message.' + ); + }); + this.emit (':responseReady'); } }; diff --git a/backend/package.json b/backend/package.json index b0c0319..3b48add 100644 --- a/backend/package.json +++ b/backend/package.json @@ -10,6 +10,7 @@ "express": "^4.13.0", "isomorphic-fetch": "^2.2.1", "mongodb": "^2.2.33", + "nodemailer": "^4.4.1", "request": "^2.83.0" }, "author": "Matt Kruse (http://mattkruse.com/)", -- 2.47.3 From 9cff3cd9ae4f14f90857ea68a87c7c0e1dbf10f4 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 19:28:46 +0100 Subject: [PATCH 04/31] change email service --- backend/helpers/email.js | 10 +++++----- backend/models/alexa.js | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/backend/helpers/email.js b/backend/helpers/email.js index 575b75c..3f92a1c 100644 --- a/backend/helpers/email.js +++ b/backend/helpers/email.js @@ -29,12 +29,12 @@ module.exports = { message; let transporter = nodemailer.createTransport ({ - host: 'smtp.yandex.com', - port: 465, - secure: true, + host: 'smtp.mail.com', + port: 587, + secure: false, auth: { - user: 'saburly@yandex.com', - pass: 'WeAreSaburlyTeam', + user: 'saburly@mail.com', + pass: 'KeepSaburly', }, }); diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 25c80ac..271eb77 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -127,15 +127,18 @@ module.exports = { intent.slots.Message.value, destinationEmail ).then(info=>{ + console.log(info); this.response.speak ( 'Ok. Message sent. Someone will contact you ASAP' ); + this.emit (':responseReady'); }).catch(error=>{ + console.log(error); this.response.speak ( 'Sorry, there was a problem with sending message.' ); + this.emit (':responseReady'); }); - this.emit (':responseReady'); } }; -- 2.47.3 From e2d76ff03ee9358727b2075d502b346df97e6dbc Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 19:50:21 +0100 Subject: [PATCH 05/31] improve email preview --- backend/helpers/email.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/backend/helpers/email.js b/backend/helpers/email.js index 3f92a1c..749962a 100644 --- a/backend/helpers/email.js +++ b/backend/helpers/email.js @@ -23,10 +23,22 @@ module.exports = { sendEmal: function (name, fromEmail, message, toEmail) { return new Promise ((resolve, reject) => { let messageBody = - 'Hello. User ' + + 'Hello. User left you a message on Saburly service using Alexa skill. \r\nMessage : ' + + message + + '\r\nName : ' + name + - ' left you a message on Saburly service using Alexa. Content of the message : ' + - message; + '\r\nEmail : ' + + fromEmail + + '\r\nYour Saburly team'; + + let messageBodyHTML = + '

Hello. User left you a message on Saburly service using Alexa skill.


Message :

' + + message + + '


Name : ' + + name + + '


Email : ' + + fromEmail + + '


Your Saburly team'; let transporter = nodemailer.createTransport ({ host: 'smtp.mail.com', @@ -39,11 +51,12 @@ module.exports = { }); var mailOptions = { - from: fromEmail, + from: 'saburly@mail.com', replyTo: fromEmail, to: toEmail, subject: 'Message from Saburly service', text: messageBody, + html: messageBodyHTML }; transporter.sendMail (mailOptions, (error, info) => { -- 2.47.3 From 0727328e58e81b279244ab171c729278d69dadb4 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 19:53:49 +0100 Subject: [PATCH 06/31] improve email preview --- backend/helpers/email.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/helpers/email.js b/backend/helpers/email.js index 749962a..c2d6965 100644 --- a/backend/helpers/email.js +++ b/backend/helpers/email.js @@ -34,11 +34,11 @@ module.exports = { let messageBodyHTML = '

Hello. User left you a message on Saburly service using Alexa skill.


Message :

' + message + - '


Name : ' + + '


Name : ' + name + - '


Email : ' + + '
Email : ' + fromEmail + - '


Your Saburly team'; + '
Your Saburly team'; let transporter = nodemailer.createTransport ({ host: 'smtp.mail.com', -- 2.47.3 From 00272ec67d5e7cdadf424d94572736c5f9299acd Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 20:05:49 +0100 Subject: [PATCH 07/31] validate email using regex --- backend/helpers/email.js | 11 +++++++---- backend/models/alexa.js | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/backend/helpers/email.js b/backend/helpers/email.js index c2d6965..67d11aa 100644 --- a/backend/helpers/email.js +++ b/backend/helpers/email.js @@ -1,7 +1,7 @@ const nodemailer = require ('nodemailer'); module.exports = { - validateEmailFromAlexaResponse: function (email) { + transformEmailFromAlexaResponse: function (email) { //email from alexa response will contain words instead of symbols, like : //at = @ //underscore = _ @@ -14,10 +14,13 @@ module.exports = { .replace (/dash/gi, '-') .replace (/dot/gi, '.'); - //Validate here with some email validation regex + return transformedEmail; + }, - //return true if email is valid - return true; + isEmailValid : function(email){ + let validEmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + + return validEmailRegex.test(email); }, sendEmal: function (name, fromEmail, message, toEmail) { diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 271eb77..3ba0c56 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -88,8 +88,9 @@ module.exports = { repromptSpeech ); } else if (!intent.slots.Message.value) { + intent.slots.Email.value = emailHelper.transformEmailFromAlexaResponse(intent.slots.Message.value); if ( - !emailHelper.validateEmailFromAlexaResponse ( + !emailHelper.isEmailValid ( intent.slots.Email.value ) ) { -- 2.47.3 From 434d45248c99360882d6f5290fa76a1cb988e897 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 20:15:27 +0100 Subject: [PATCH 08/31] fix error in validation and undefined email value --- backend/helpers/email.js | 10 ++++++---- backend/models/alexa.js | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/helpers/email.js b/backend/helpers/email.js index 67d11aa..cf1bfb3 100644 --- a/backend/helpers/email.js +++ b/backend/helpers/email.js @@ -9,6 +9,7 @@ module.exports = { //dot = . //TODO: This list should be longer let transformedEmail = email + .replace (/\s/g, '') //remove all spaces .replace (/at/gi, '@') .replace (/underscore/gi, '_') .replace (/dash/gi, '-') @@ -17,10 +18,11 @@ module.exports = { return transformedEmail; }, - isEmailValid : function(email){ - let validEmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + isEmailValid: function (email) { + console.log ('Email to validate : ' + email); + let validEmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - return validEmailRegex.test(email); + return validEmailRegex.test (email); }, sendEmal: function (name, fromEmail, message, toEmail) { @@ -59,7 +61,7 @@ module.exports = { to: toEmail, subject: 'Message from Saburly service', text: messageBody, - html: messageBodyHTML + html: messageBodyHTML, }; transporter.sendMail (mailOptions, (error, info) => { diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 3ba0c56..92f0fac 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -88,7 +88,7 @@ module.exports = { repromptSpeech ); } else if (!intent.slots.Message.value) { - intent.slots.Email.value = emailHelper.transformEmailFromAlexaResponse(intent.slots.Message.value); + intent.slots.Email.value = emailHelper.transformEmailFromAlexaResponse(intent.slots.Email.value); if ( !emailHelper.isEmailValid ( intent.slots.Email.value -- 2.47.3 From b73086291c9c53192a6ab7d9bccb6896525d671d Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 20:23:50 +0100 Subject: [PATCH 09/31] code fix and improvements --- backend/config/email.js | 14 +++++++++++ backend/helpers/email.js | 18 +++++++------- backend/models/alexa.js | 52 +++++++++++++++++++++------------------- 3 files changed, 49 insertions(+), 35 deletions(-) create mode 100644 backend/config/email.js diff --git a/backend/config/email.js b/backend/config/email.js new file mode 100644 index 0000000..89e0ddc --- /dev/null +++ b/backend/config/email.js @@ -0,0 +1,14 @@ +var config = {}; + +config.PORT = 587; +config.SMTP_HOST = 'smtp.mail.com'; +config.SECURE = false; +config.AUTH = { + user: 'saburly@mail.com', + pass: 'KeepSaburly', +}; + +config.FROM_EMAIL = 'saburly@mail.com'; +config.SUBJECT = 'Message from Saburly service'; + +module.exports = config; diff --git a/backend/helpers/email.js b/backend/helpers/email.js index cf1bfb3..c70eadc 100644 --- a/backend/helpers/email.js +++ b/backend/helpers/email.js @@ -1,4 +1,5 @@ const nodemailer = require ('nodemailer'); +const emailConfig = require('../config/email'); module.exports = { transformEmailFromAlexaResponse: function (email) { @@ -43,23 +44,20 @@ module.exports = { name + '
Email : ' + fromEmail + - '
Your Saburly team'; + '

Your Saburly team'; let transporter = nodemailer.createTransport ({ - host: 'smtp.mail.com', - port: 587, - secure: false, - auth: { - user: 'saburly@mail.com', - pass: 'KeepSaburly', - }, + host: emailConfig.SMTP_HOST, + port: emailConfig.PORT, + secure: emailConfig.SECURE, + auth: emailConfig.AUTH, }); var mailOptions = { - from: 'saburly@mail.com', + from: emailConfig.FROM_EMAIL, replyTo: fromEmail, to: toEmail, - subject: 'Message from Saburly service', + subject: emailConfig.SUBJECT, text: messageBody, html: messageBodyHTML, }; diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 92f0fac..da282f3 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -88,12 +88,10 @@ module.exports = { repromptSpeech ); } else if (!intent.slots.Message.value) { - intent.slots.Email.value = emailHelper.transformEmailFromAlexaResponse(intent.slots.Email.value); - if ( - !emailHelper.isEmailValid ( - intent.slots.Email.value - ) - ) { + intent.slots.Email.value = emailHelper.transformEmailFromAlexaResponse ( + intent.slots.Email.value + ); + if (!emailHelper.isEmailValid (intent.slots.Email.value)) { //Email is not valid, ask again const slotToElicit = 'Email'; const speechOutput = @@ -103,7 +101,8 @@ module.exports = { ':elicitSlot', slotToElicit, speechOutput, - repromptSpeech + repromptSpeech, + intent ); } else { //Email is valid @@ -122,24 +121,27 @@ module.exports = { console.log ('Name : ' + intent.slots.Name.value); console.log ('Email : ' + intent.slots.Email.value); console.log ('Message : ' + intent.slots.Message.value); - emailHelper.sendEmal ( - intent.slots.Name.value, - intent.slots.Email.value, - intent.slots.Message.value, - destinationEmail - ).then(info=>{ - console.log(info); - this.response.speak ( - 'Ok. Message sent. Someone will contact you ASAP' - ); - this.emit (':responseReady'); - }).catch(error=>{ - console.log(error); - this.response.speak ( - 'Sorry, there was a problem with sending message.' - ); - this.emit (':responseReady'); - }); + emailHelper + .sendEmal ( + intent.slots.Name.value, + intent.slots.Email.value, + intent.slots.Message.value, + destinationEmail + ) + .then (info => { + console.log (info); + this.response.speak ( + 'Ok. Message sent. Someone will contact you ASAP' + ); + this.emit (':responseReady'); + }) + .catch (error => { + console.log (error); + this.response.speak ( + 'Sorry, there was a problem with sending message.' + ); + this.emit (':responseReady'); + }); } }; -- 2.47.3 From e2d648980b42962fa454719d974fcec8bf6b41e3 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 20:28:26 +0100 Subject: [PATCH 10/31] fix code --- backend/helpers/email.js | 1 + backend/models/alexa.js | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/helpers/email.js b/backend/helpers/email.js index c70eadc..76e109a 100644 --- a/backend/helpers/email.js +++ b/backend/helpers/email.js @@ -28,6 +28,7 @@ module.exports = { sendEmal: function (name, fromEmail, message, toEmail) { return new Promise ((resolve, reject) => { + fromEmail = this.transformEmailFromAlexaResponse(fromEmail); let messageBody = 'Hello. User left you a message on Saburly service using Alexa skill. \r\nMessage : ' + message + diff --git a/backend/models/alexa.js b/backend/models/alexa.js index da282f3..4074784 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -101,8 +101,7 @@ module.exports = { ':elicitSlot', slotToElicit, speechOutput, - repromptSpeech, - intent + repromptSpeech ); } else { //Email is valid -- 2.47.3 From 48578d3ffe8e99ba449768da6a06a90289c79fc6 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 22:42:37 +0100 Subject: [PATCH 11/31] Change UI --- README.md | 2 +- web/src/App.js | 349 ++++++++++++++++++---------- web/src/components/IntentDetails.js | 22 +- web/src/config/constants.js | 1 + 4 files changed, 252 insertions(+), 122 deletions(-) diff --git a/README.md b/README.md index caec0bf..fc36472 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Prerequests for step 3 (run on server): requires running mongodb service Database (tellall) with collection (skill_list) - * Insert dummy skill with : db.skill_list.insert({"skillID" : "amzn1.ask.skill.efbf0564-a732-4ba9-958f-57939138adae", "intents" : [ { "intentName" : "GetFirstQuestion", "questions" : [ "tell me something about projects", "tell me all about projects" ], "answer" : "blablabla bla bla" }, { "intentName" : "GetThirdQuestion", "questions" : [ "Give me third question" ], "answer" : "This is answer to the third question" } ], "invocationName" : "Saburly", "invocationAnswer" : "We are Saburly team one" }) + * Insert dummy skill with : db.skill_list.insert({"skillID" : "amzn1.ask.skill.efbf0564-a732-4ba9-958f-57939138adae", "intents" : [ { "intentName" : "GetFirstQuestion", "questionExplanation" : "", "questions" : [ "tell me something about projects", "tell me all about projects" ], "answer" : "blablabla bla bla" }, { "intentName" : "GetThirdQuestion", "questionExplanation" : "", "questions" : [ "Give me third question" ], "answer" : "This is answer to the third question" } ], "invocationName" : "Saburly", "invocationAnswer" : "We are Saburly team one" }) *obtain _id and change in web/src/App.js, and also skill_db_id in backend/config.js *enter web/ dir and run "npm run build" diff --git a/web/src/App.js b/web/src/App.js index 663d0ec..9f46a99 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, {Component} from 'react'; import './css/App.css'; import './css/popup.css'; import IntentList from './components/IntentList'; @@ -6,90 +6,117 @@ import IntentDetails from './components/IntentDetails'; import LaunchRequest from './components/LaunchRequest'; import Contact from './components/Contact'; import Popup from 'react-popup'; -import {getSkill, updateSkill} from './lib/api' +import {getSkill, updateSkill} from './lib/api'; import { - NEW_INTENT_SELECTED_INDEX, - LAUNCH_REQUEST_SELECTED_INDEX, - CONTACT_SELECTED_INDEX, - RESULT_CODES} from './config/constants' + NEW_INTENT_SELECTED_INDEX, + LAUNCH_REQUEST_SELECTED_INDEX, + CONTACT_SELECTED_INDEX, + RESULT_CODES, +} from './config/constants'; class App extends Component { + constructor (props) { + super (props); - constructor(props){ - super(props); + this.state = { + _id: '5a232fb86ce046c749739455', + skillID: '', + skillName: '', + invocationName: 'Saburly', + invocationAnswer: 'We are saburly', + allIntents: [], + selectedIntent: { + intentName: '', + intentExplanation: '', + questions: [''], + answer: '', + }, + selectedIndex: NEW_INTENT_SELECTED_INDEX, + contactEmail: '', + waiting: false, + }; - this.state={_id:'5a232fb86ce046c749739455', - skillID:'', - skillName:'', - invocationName:'Saburly', - invocationAnswer:'We are saburly', - allIntents:[], - selectedIntent: {intentName:'',questions:[''],answer:''}, - selectedIndex:NEW_INTENT_SELECTED_INDEX, - contactEmail:'', - waiting: false - }; + getSkill (this.state._id).then (l => l.json ()).then (result => { + if (result === undefined) return; + this.setState ({ + skillID: result.skillID, + skillName: result.skillName, + invocationName: result.invocationName, + invocationAnswer: result.invocationAnswer, + allIntents: result.intents, + contactEmail: result.contactEmail, + }); + }); - getSkill(this.state._id).then(l=>l.json()).then(result=>{ - if (result===undefined) return; - this.setState({ skillID:result.skillID,skillName:result.skillName, invocationName: result.invocationName, - invocationAnswer: result.invocationAnswer, - allIntents: result.intents, contactEmail: result.contactEmail}) - }) - - this.handleIntentClick = this.handleIntentClick.bind(this); - this.handleLaunchRequestClick = this.handleLaunchRequestClick.bind(this); - this.handleDeleteIntentClick = this.handleDeleteIntentClick.bind(this); - this.handleSaveIntentClick = this.handleSaveIntentClick.bind(this); - this.handleAddIntentClick = this.handleAddIntentClick.bind(this); - this.handleSaveLaunchRequestClick = this.handleSaveLaunchRequestClick.bind(this); - this.createSkill = this.createSkill.bind(this); - this.sendSkill = this.sendSkill.bind(this); - this.handleContactClick = this.handleContactClick.bind(this); - this.handleSaveEmailClick = this.handleSaveEmailClick.bind(this); + this.handleIntentClick = this.handleIntentClick.bind (this); + this.handleLaunchRequestClick = this.handleLaunchRequestClick.bind (this); + this.handleDeleteIntentClick = this.handleDeleteIntentClick.bind (this); + this.handleSaveIntentClick = this.handleSaveIntentClick.bind (this); + this.handleAddIntentClick = this.handleAddIntentClick.bind (this); + this.handleSaveLaunchRequestClick = this.handleSaveLaunchRequestClick.bind ( + this + ); + this.createSkill = this.createSkill.bind (this); + this.sendSkill = this.sendSkill.bind (this); + this.handleContactClick = this.handleContactClick.bind (this); + this.handleSaveEmailClick = this.handleSaveEmailClick.bind (this); } - render() { + render () { let rightPanel; switch (this.state.selectedIndex) { case LAUNCH_REQUEST_SELECTED_INDEX: - rightPanel = ; + rightPanel = ( + + ); break; case CONTACT_SELECTED_INDEX: - rightPanel = ; + rightPanel = ( + + ); break; default: - rightPanel = ; + rightPanel = ( + + ); } - return( + return (
- +

Tell All

- - + + {rightPanel}
); } - createSkill(intents, name, answer, email, updateOnAmazon){ + createSkill (intents, name, answer, email, updateOnAmazon) { return { _id: this.state._id, skillID: this.state.skillID, @@ -97,97 +124,181 @@ class App extends Component { invocationName: name, invocationAnswer: answer, contactEmail: email, - updateOnAmazon: updateOnAmazon + updateOnAmazon: updateOnAmazon, }; } - handleIntentClick(selectedIntent, index){ - this.setState({selectedIntent:selectedIntent, selectedIndex: index, launchRequest:false}); + handleIntentClick (selectedIntent, index) { + this.setState ({ + selectedIntent: selectedIntent, + selectedIndex: index, + launchRequest: false, + }); } - handleLaunchRequestClick(){ - this.setState({selectedIndex: LAUNCH_REQUEST_SELECTED_INDEX}); + handleLaunchRequestClick () { + this.setState ({selectedIndex: LAUNCH_REQUEST_SELECTED_INDEX}); } - handleContactClick(){ - this.setState({selectedIndex: CONTACT_SELECTED_INDEX}) + handleContactClick () { + this.setState ({selectedIndex: CONTACT_SELECTED_INDEX}); } - handleSaveLaunchRequestClick(name, answer){ - this.setState({waiting:true, invocationName:name, invocationAnswer: answer}); - this.sendSkill(this.state.allIntents,true,{waiting:false},{waiting:false},name,answer,this.state.contactEmail,true); + handleSaveLaunchRequestClick (name, answer) { + this.setState ({ + waiting: true, + invocationName: name, + invocationAnswer: answer, + }); + this.sendSkill ( + this.state.allIntents, + true, + {waiting: false}, + {waiting: false}, + name, + answer, + this.state.contactEmail, + true + ); } - handleSaveEmailClick(email){ - this.setState({waiting:true}); - this.sendSkill(this.state.allIntents,true,{contactEmail: email, waiting:false},{waiting:false},this.state.invocationName,this.state.invocationAnswer,email,false); + handleSaveEmailClick (email) { + this.setState ({waiting: true}); + this.sendSkill ( + this.state.allIntents, + true, + {contactEmail: email, waiting: false}, + {waiting: false}, + this.state.invocationName, + this.state.invocationAnswer, + email, + false + ); } - handleDeleteIntentClick(selectedIntent){ + handleDeleteIntentClick (selectedIntent) { let id = -1; //TODO : Change comparsion method ! Same object with different proeprty sorting will not be same string - this.state.allIntents.map((intent,index)=>{ - if ((id===-1) && (JSON.stringify(selectedIntent)===JSON.stringify(intent))) - id = index; + this.state.allIntents.map ((intent, index) => { + if ( + id === -1 && + JSON.stringify (selectedIntent) === JSON.stringify (intent) + ) + id = index; }); - if (id!==-1){ - try{ - let newAllIntentsJSON = JSON.stringify(this.state.allIntents); - let newAllIntents = JSON.parse(newAllIntentsJSON); - newAllIntents.splice(id,1); - this.setState({waiting:true}); + if (id !== -1) { + try { + let newAllIntentsJSON = JSON.stringify (this.state.allIntents); + let newAllIntents = JSON.parse (newAllIntentsJSON); + newAllIntents.splice (id, 1); + this.setState ({waiting: true}); - let newState = {allIntents: newAllIntents, selectedIntent: {intentName:'', questions:[''],answer:''}, waiting:false}; - this.sendSkill(newAllIntents,true,newState,{waiting:false},this.state.invocationName,this.state.invocationAnswer,this.state.contactEmail,true); - - }catch(e){ - console.log("error : " + e); + let newState = { + allIntents: newAllIntents, + selectedIntent: {intentName: '', questions: [''], answer: ''}, + waiting: false, + }; + this.sendSkill ( + newAllIntents, + true, + newState, + {waiting: false}, + this.state.invocationName, + this.state.invocationAnswer, + this.state.contactEmail, + true + ); + } catch (e) { + console.log ('error : ' + e); } } } - - handleSaveIntentClick(selectedIntent){ - let newAllIntentsJSON = JSON.stringify(this.state.allIntents); - let newAllIntents = JSON.parse(newAllIntentsJSON); + handleSaveIntentClick (selectedIntent) { + let newAllIntentsJSON = JSON.stringify (this.state.allIntents); + let newAllIntents = JSON.parse (newAllIntentsJSON); let newState = null; - if (this.state.selectedIndex === NEW_INTENT_SELECTED_INDEX){ + if (this.state.selectedIndex === NEW_INTENT_SELECTED_INDEX) { //new intent - newAllIntents.push(selectedIntent); - newState = {allIntents: newAllIntents, selectedIntent: selectedIntent, selectedIndex: newAllIntents.length-1, waiting:false}; - }else{ + newAllIntents.push (selectedIntent); + newState = { + allIntents: newAllIntents, + selectedIntent: selectedIntent, + selectedIndex: newAllIntents.length - 1, + waiting: false, + }; + } else { newAllIntents[this.state.selectedIndex] = selectedIntent; - newState = {allIntents: newAllIntents, selectedIntent: selectedIntent, waiting: false}; + newState = { + allIntents: newAllIntents, + selectedIntent: selectedIntent, + waiting: false, + }; } - this.setState({waiting:true}); - this.sendSkill(newAllIntents, true, newState, {waiting:false}, this.state.invocationName,this.state.invocationAnswer,this.state.contactEmail, true); + this.setState ({waiting: true}); + this.sendSkill ( + newAllIntents, + true, + newState, + {waiting: false}, + this.state.invocationName, + this.state.invocationAnswer, + this.state.contactEmail, + true + ); } - handleAddIntentClick(){ - this.setState({allIntents: this.state.allIntents, selectedIndex: NEW_INTENT_SELECTED_INDEX,launchRequest:false,selectedIntent: {intentName:'',questions:[''], answer:''}}); + handleAddIntentClick () { + this.setState ({ + allIntents: this.state.allIntents, + selectedIndex: NEW_INTENT_SELECTED_INDEX, + launchRequest: false, + selectedIntent: {intentName: '', questions: [''], answer: ''}, + }); } - sendSkill(newAllIntents, showPopUp, resolveState, rejectState, newName, newAnswer, email, updateOnAmazon){ - return new Promise((resolve,reject)=>{ - updateSkill(this.createSkill(newAllIntents,newName,newAnswer,email,updateOnAmazon)).then(l=>l.json()).then(result=>{ - if (result.result !== RESULT_CODES.OK){ - console.log(result.result); - if (showPopUp) Popup.alert('Model was not saved. Please try again'); - this.setState(rejectState); - //reject('Error code : ' + jResult.result); - }else{ - if (showPopUp) Popup.alert('Saved'); - this.setState(resolveState); - resolve(); - } - }).catch(e=>{ - console.log('error : ' + e); - if (showPopUp) Popup.alert('Model was not saved. Please try again'); - this.setState(rejectState); - //reject(e); - }); + sendSkill ( + newAllIntents, + showPopUp, + resolveState, + rejectState, + newName, + newAnswer, + email, + updateOnAmazon + ) { + return new Promise ((resolve, reject) => { + updateSkill ( + this.createSkill ( + newAllIntents, + newName, + newAnswer, + email, + updateOnAmazon + ) + ) + .then (l => l.json ()) + .then (result => { + if (result.result !== RESULT_CODES.OK) { + console.log (result); + if (showPopUp) + Popup.alert ('Model was not saved. Please try again'); + this.setState (rejectState); + //reject('Error code : ' + jResult.result); + } else { + if (showPopUp) Popup.alert ('Saved'); + this.setState (resolveState); + resolve (); + } + }) + .catch (e => { + console.log ('error : ' + e); + if (showPopUp) Popup.alert ('Model was not saved. Please try again'); + this.setState (rejectState); + //reject(e); + }); }); } } diff --git a/web/src/components/IntentDetails.js b/web/src/components/IntentDetails.js index e5c6066..8e76100 100644 --- a/web/src/components/IntentDetails.js +++ b/web/src/components/IntentDetails.js @@ -1,7 +1,8 @@ import React, { Component } from 'react'; import {Button, SVGIcon, TextField} from 'react-md'; import '../css/components/IntentDetails.css'; -import {QUESTION_MAX_LENGTH, ANSWER_MAX_LENGTH, INTENT_NAME_MAX_LENGTH} from '../config/constants'; +import '../css/Common.css'; +import {QUESTION_MAX_LENGTH, ANSWER_MAX_LENGTH, INTENT_NAME_MAX_LENGTH, INTENT_EXPLANATION_MAX_LENGTH} from '../config/constants'; class IntentDetails extends Component { constructor(props){ @@ -14,6 +15,7 @@ class IntentDetails extends Component { this.handleQuestionEdit = this.handleQuestionEdit.bind(this); this.handleAnswerEdit = this.handleAnswerEdit.bind(this); this.handleIntentNameEdit = this.handleIntentNameEdit.bind(this); + this.handleIntentExplanationEdit = this.handleIntentExplanationEdit.bind(this); } componentWillReceiveProps(props){ @@ -24,10 +26,19 @@ class IntentDetails extends Component { return (
+
In introduction, Alexa will help users to ask her the right questions about your business. For Example, she will say : "To ask us about our services, say : What do you do ? ". What do you do ? is defined in question field. Alexa will use first variation of question in intro.
+ +
Date: Fri, 19 Jan 2018 22:54:50 +0100 Subject: [PATCH 12/31] fix reverting skill on failed update --- backend/config/constants.js | 2 +- backend/controllers/skill.js | 86 +++++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/backend/config/constants.js b/backend/config/constants.js index c131195..b60f24b 100644 --- a/backend/config/constants.js +++ b/backend/config/constants.js @@ -17,7 +17,7 @@ constants.apiResultCodes = { AMAZON_FAIL:2, //amazon api doesn't work DATABASE_ERROR:3, NO_SKILL:4, - INCONSISTEN_STATE:5, + INCONSISTENT_STATE:5, } constants.HTTPResultCodes = { diff --git a/backend/controllers/skill.js b/backend/controllers/skill.js index 6cc36e7..a0c2f5f 100644 --- a/backend/controllers/skill.js +++ b/backend/controllers/skill.js @@ -41,6 +41,7 @@ router.put ('/:id', bodyParser.json (), async (req, res, next) => { .then (() => { //Ok, done, now update skill on Amazon (if needed) if (updateOnAmazon) { + //We need to update skill on Amazon amazonHelper .updateSkill (skill) .then (amazonResult => { @@ -51,45 +52,78 @@ router.put ('/:id', bodyParser.json (), async (req, res, next) => { res.json ({result: constants.apiResultCodes.OK, message: ''}); alexa.updateModel (); } else { - res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({ - result: constants.apiResultCodes.AMAZON_ERROR, - message: amazonResult, - }); + //Update on amazon failed, revert changes in database and send error to user + databaseHelper + .updateSkill (id, currentSkillState) + .then (() => { + res + .status ( + constants.HTTPResultCodes.INTERNAL_SERVER_ERROR + ) + .json ({ + result: constants.apiResultCodes.AMAZON_ERROR, + message: amazonResult, + }); + }) + .catch (() => { + //This should never happen, something is seriously wrong, like no database connection + res + .status ( + constants.HTTPResultCodes.INTERNAL_SERVER_ERROR + ) + .json ({ + result: constants.apiResultCodes.INCONSISTENT_STATE, + message: '', + }); + }); } }) .catch (e => { - res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({ - result: constants.apiResultCodes.AMAZON_FAIL, - message: e, - }); + //Update on amazon failed, revert changes in database and send error to user + databaseHelper + .updateSkill (id, currentSkillState) + .then (() => { + res + .status (constants.HTTPResultCodes.INTERNAL_SERVER_ERROR) + .json ({ + result: constants.apiResultCodes.AMAZON_FAIL, + message: e, + }); + }) + .catch (() => { + //This should never happen, something is seriously wrong, like no database connection + res + .status (constants.HTTPResultCodes.INTERNAL_SERVER_ERROR) + .json ({ + result: constants.apiResultCodes.INCONSISTENT_STATE, + message: '', + }); + }); }); - }else{ + } else { + //No need to update on Amazon, tell to user it's ok res.json ({result: constants.apiResultCodes.OK, message: ''}); alexa.updateModel (); } }) .catch (() => { - //Update in database didn't go well, revert changes - databaseHelper - .updateSkill (id, currentSkillState) - .then (() => { - res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({ - result: constants.apiResultCodes.DATABASE_ERROR, - message: '', - }); - }) - .catch (() => { - //This should never happen, something is seriously wrong, like no database connection - res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({ - result: constants.apiResultCodes.INCONSISTEN_STATE, - message: '', - }); - }); + //Update in database didn't go well, no need to revert since it failed to write in the first place + //just send error to user + res + .status ( + constants.HTTPResultCodes.INTERNAL_SERVER_ERROR + ) + .json ({ + result: constants.apiResultCodes.DATABASE_ERROR, + message: '', + }); }); }) .catch (e => { //I don't know why, but something went wrong, possibly ID of skill is wrong, doesn't exist in DB - res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({result: constants.apiResultCodes.NO_SKILL, message: ''}); + res + .status (constants.HTTPResultCodes.INTERNAL_SERVER_ERROR) + .json ({result: constants.apiResultCodes.NO_SKILL, message: ''}); }); }); -- 2.47.3 From d8799fa40d32fb80a9d63d46dc20c0bf0338f9ea Mon Sep 17 00:00:00 2001 From: GotPPay Date: Fri, 19 Jan 2018 23:26:59 +0100 Subject: [PATCH 13/31] fix JSON model --- backend/helpers/amazon.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/helpers/amazon.js b/backend/helpers/amazon.js index 6d1b553..2839f40 100644 --- a/backend/helpers/amazon.js +++ b/backend/helpers/amazon.js @@ -236,10 +236,12 @@ var generateInteractionModel = function (skill) { invocationName: skill.invocationName, types: customSlotTypes, intents: allIntents, - prompts: dialogPrompts, - dialog: dialog, }; + result.prompts = dialogPrompts; + result.dialog = dialog; + + console.log(JSON.stringify(result)); return JSON.stringify (result); }; -- 2.47.3 From 085a0324b3a9681e0be11e1df3a001b42ce20386 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Mon, 22 Jan 2018 20:12:16 +0100 Subject: [PATCH 14/31] . --- backend/helpers/amazon.js | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/backend/helpers/amazon.js b/backend/helpers/amazon.js index 2839f40..fa414ac 100644 --- a/backend/helpers/amazon.js +++ b/backend/helpers/amazon.js @@ -64,12 +64,25 @@ var generateInteractionModel = function (skill) { let result = {}; let allIntents = []; + allIntents.push({ + "name": "AMAZON.CancelIntent", + "samples": [] + }, + { + "name": "AMAZON.HelpIntent", + "samples": [] + }, + { + "name": "AMAZON.StopIntent", + "samples": [] + },); + skill.intents.map (intent => { - allIntents.push ({name: intent.intentName, samples: intent.questions}); + allIntents.push ({name: intent.intentName, samples: intent.questions, slots:[]}); }); //Special intent for sending message (Dialog) - +/* allIntents.push ({ name: 'SendMessageIntent', samples: [ @@ -95,7 +108,7 @@ var generateInteractionModel = function (skill) { }, ], }); - +*/ let customSlotTypes = [ { name: 'EmailSlot', @@ -230,16 +243,14 @@ var generateInteractionModel = function (skill) { intents: dialogIntents, }; - result.interactionModel = {}; - - result.interactionModel.languageModel = { + result.languageModel = { invocationName: skill.invocationName, - types: customSlotTypes, + //types: customSlotTypes, intents: allIntents, }; - result.prompts = dialogPrompts; - result.dialog = dialog; + //result.prompts = dialogPrompts; + //result.dialog = dialog; console.log(JSON.stringify(result)); return JSON.stringify (result); -- 2.47.3 From a00859c5944127e932add03841c818c03b2b0535 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Mon, 22 Jan 2018 22:34:13 +0100 Subject: [PATCH 15/31] fix InteractionModel generator --- backend/controllers/skill.js | 1 + backend/helpers/amazon.js | 43 ++++++++++++++---------------------- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/backend/controllers/skill.js b/backend/controllers/skill.js index a0c2f5f..921e45b 100644 --- a/backend/controllers/skill.js +++ b/backend/controllers/skill.js @@ -79,6 +79,7 @@ router.put ('/:id', bodyParser.json (), async (req, res, next) => { } }) .catch (e => { + console.log(e); //Update on amazon failed, revert changes in database and send error to user databaseHelper .updateSkill (id, currentSkillState) diff --git a/backend/helpers/amazon.js b/backend/helpers/amazon.js index fa414ac..486f1ab 100644 --- a/backend/helpers/amazon.js +++ b/backend/helpers/amazon.js @@ -64,25 +64,12 @@ var generateInteractionModel = function (skill) { let result = {}; let allIntents = []; - allIntents.push({ - "name": "AMAZON.CancelIntent", - "samples": [] - }, - { - "name": "AMAZON.HelpIntent", - "samples": [] - }, - { - "name": "AMAZON.StopIntent", - "samples": [] - },); - skill.intents.map (intent => { - allIntents.push ({name: intent.intentName, samples: intent.questions, slots:[]}); + allIntents.push ({name: intent.intentName, samples: intent.questions}); }); //Special intent for sending message (Dialog) -/* + allIntents.push ({ name: 'SendMessageIntent', samples: [ @@ -108,7 +95,9 @@ var generateInteractionModel = function (skill) { }, ], }); -*/ + + + let customSlotTypes = [ { name: 'EmailSlot', @@ -163,7 +152,7 @@ var generateInteractionModel = function (skill) { ], }, ]; - + let dialogPrompts = [ { id: 'Elicit.Intent-SendMessageIntent.IntentSlot-Name', @@ -201,7 +190,7 @@ var generateInteractionModel = function (skill) { ], }, ]; - + let dialogIntents = [ { name: 'SendMessageIntent', @@ -239,24 +228,24 @@ var generateInteractionModel = function (skill) { }, ]; - let dialog = { - intents: dialogIntents, - }; + result.interactionModel = {}; - result.languageModel = { + result.interactionModel.languageModel = { invocationName: skill.invocationName, - //types: customSlotTypes, + types: customSlotTypes, intents: allIntents, }; - //result.prompts = dialogPrompts; - //result.dialog = dialog; + result.interactionModel.prompts = dialogPrompts; + result.interactionModel.dialog = {}; + result.interactionModel.dialog.intents = dialogIntents; - console.log(JSON.stringify(result)); return JSON.stringify (result); }; var uploadSkill = function (skill) { + let generatedInteractionModel = generateInteractionModel(skill); + console.log(generatedInteractionModel); return fetch ( `https://api.amazonalexa.com/v0/skills/${skill.skillID}/interactionModel/locales/en-US`, { @@ -264,7 +253,7 @@ var uploadSkill = function (skill) { headers: { Authorization: config.TOKEN, }, - body: generateInteractionModel (skill), + body: generatedInteractionModel, } ); }; -- 2.47.3 From af19108e9ced5d214b649cc615e2844054d34d73 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Mon, 22 Jan 2018 22:34:58 +0100 Subject: [PATCH 16/31] fix InteractionModel generator --- backend/controllers/skill.js | 1 - backend/helpers/amazon.js | 1 - 2 files changed, 2 deletions(-) diff --git a/backend/controllers/skill.js b/backend/controllers/skill.js index 921e45b..a0c2f5f 100644 --- a/backend/controllers/skill.js +++ b/backend/controllers/skill.js @@ -79,7 +79,6 @@ router.put ('/:id', bodyParser.json (), async (req, res, next) => { } }) .catch (e => { - console.log(e); //Update on amazon failed, revert changes in database and send error to user databaseHelper .updateSkill (id, currentSkillState) diff --git a/backend/helpers/amazon.js b/backend/helpers/amazon.js index 486f1ab..9cc046f 100644 --- a/backend/helpers/amazon.js +++ b/backend/helpers/amazon.js @@ -245,7 +245,6 @@ var generateInteractionModel = function (skill) { var uploadSkill = function (skill) { let generatedInteractionModel = generateInteractionModel(skill); - console.log(generatedInteractionModel); return fetch ( `https://api.amazonalexa.com/v0/skills/${skill.skillID}/interactionModel/locales/en-US`, { -- 2.47.3 From 2c6953fe97721bc16086dfea7bda55c994af836b Mon Sep 17 00:00:00 2001 From: GotPPay Date: Mon, 22 Jan 2018 23:35:25 +0100 Subject: [PATCH 17/31] list all questions on Launch --- backend/models/alexa.js | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 4074784..0ff79d8 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -34,14 +34,42 @@ module.exports = { handlers = {}; destinationEmail = activeSkill.contactEmail; + //Defaul Amazon handlers (some of them) + + handlers.NewSession = function () { + this.attributes['WantToHearQuestions'] = false; + }; + + handlers['AMAZON.YesIntent'] = function () { + if (this.attributes['WantToHearQuestions']) { + let listOfPossibleQuestions = ''; + activeSkill.intents.map (intent => { + if (intent.questions.length > 0) { + listOfPossibleQuestions += + intent.intentExplanation + + intent.questions[0] + + ''; + } + }); + this.response + .speak (listOfPossibleQuestions) + .listen(listOfPossibleQuestions); + this.emit(':responseReady'); + } + }; + //Handler for launch request handlers = { LaunchRequest: function () { this.response .speak (activeSkill.invocationAnswer) + .speak ( + 'Would you like to hear questions that you can ask me ?' + ) .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! - //TODO : Maybe to ask user does he want to hear possible intents - //For this functionality, we need explanation text for each intent (Question) + + this.attributes['WantToHearQuestions'] = true; + this.emit (':responseReady'); }, }; -- 2.47.3 From d58d4b89e3b33342b292d9fe85e3171b97e9c55c Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 00:08:39 +0100 Subject: [PATCH 18/31] experiment with yes intent --- backend/models/alexa.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 0ff79d8..271b528 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -12,7 +12,6 @@ module.exports = { // Build the context manually, because Amazon Lambda is missing var context = { succeed: function (result) { - console.log (result); res.json (result); }, fail: function (error) { @@ -34,6 +33,17 @@ module.exports = { handlers = {}; destinationEmail = activeSkill.contactEmail; + let listOfPossibleQuestions = ''; + activeSkill.intents.map (intent => { + if (intent.questions.length > 0) { + listOfPossibleQuestions += + intent.intentExplanation + + intent.questions[0] + + ''; + } + }); + console.log(listOfPossibleQuestions); + //Defaul Amazon handlers (some of them) handlers.NewSession = function () { @@ -41,16 +51,8 @@ module.exports = { }; handlers['AMAZON.YesIntent'] = function () { + console.log("yes intent"); if (this.attributes['WantToHearQuestions']) { - let listOfPossibleQuestions = ''; - activeSkill.intents.map (intent => { - if (intent.questions.length > 0) { - listOfPossibleQuestions += - intent.intentExplanation + - intent.questions[0] + - ''; - } - }); this.response .speak (listOfPossibleQuestions) .listen(listOfPossibleQuestions); @@ -63,9 +65,6 @@ module.exports = { LaunchRequest: function () { this.response .speak (activeSkill.invocationAnswer) - .speak ( - 'Would you like to hear questions that you can ask me ?' - ) .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! this.attributes['WantToHearQuestions'] = true; -- 2.47.3 From b1a853c3631e46ecddb80b2ea6359ad17f047e0c Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 00:20:50 +0100 Subject: [PATCH 19/31] experiment with Yes and No intents --- backend/helpers/amazon.js | 23 +++++++++++++++++------ backend/models/alexa.js | 15 +++++++++++---- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/backend/helpers/amazon.js b/backend/helpers/amazon.js index 9cc046f..f280ed4 100644 --- a/backend/helpers/amazon.js +++ b/backend/helpers/amazon.js @@ -64,12 +64,25 @@ var generateInteractionModel = function (skill) { let result = {}; let allIntents = []; + //Special Amazon intent + + allIntents.push ( + { + name: 'AMAZON.YesIntent', + samples: [], + }, + { + name: 'AMAZON.NoIntent', + samples: [], + } + ); + skill.intents.map (intent => { allIntents.push ({name: intent.intentName, samples: intent.questions}); }); //Special intent for sending message (Dialog) - + allIntents.push ({ name: 'SendMessageIntent', samples: [ @@ -95,9 +108,7 @@ var generateInteractionModel = function (skill) { }, ], }); - - let customSlotTypes = [ { name: 'EmailSlot', @@ -152,7 +163,7 @@ var generateInteractionModel = function (skill) { ], }, ]; - + let dialogPrompts = [ { id: 'Elicit.Intent-SendMessageIntent.IntentSlot-Name', @@ -190,7 +201,7 @@ var generateInteractionModel = function (skill) { ], }, ]; - + let dialogIntents = [ { name: 'SendMessageIntent', @@ -244,7 +255,7 @@ var generateInteractionModel = function (skill) { }; var uploadSkill = function (skill) { - let generatedInteractionModel = generateInteractionModel(skill); + let generatedInteractionModel = generateInteractionModel (skill); return fetch ( `https://api.amazonalexa.com/v0/skills/${skill.skillID}/interactionModel/locales/en-US`, { diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 271b528..9723c1f 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -47,24 +47,31 @@ module.exports = { //Defaul Amazon handlers (some of them) handlers.NewSession = function () { - this.attributes['WantToHearQuestions'] = false; + this.attributes['WaitingQuestions'] = false; }; handlers['AMAZON.YesIntent'] = function () { console.log("yes intent"); - if (this.attributes['WantToHearQuestions']) { + if (this.attributes['WaitingQuestions']) { this.response .speak (listOfPossibleQuestions) - .listen(listOfPossibleQuestions); + .listen(constants.voiceResponseStrings.GENERIC_CONTINUE); this.emit(':responseReady'); } }; + handlers['AMAZON.NoIntent'] = function () { + console.log("No intent"); + if (this.attributes['WaitingQuestions']) { + this.attributes['WaitingQuestions'] = false; + } + }; + //Handler for launch request handlers = { LaunchRequest: function () { this.response - .speak (activeSkill.invocationAnswer) + .speak (activeSkill.invocationAnswer + ' Would you like to hear possible questions ?') .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! this.attributes['WantToHearQuestions'] = true; -- 2.47.3 From 2ae983d211a857d9a6c5dc7d371e696389173eef Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 00:40:19 +0100 Subject: [PATCH 20/31] Experiment with Yes and No intent --- backend/helpers/amazon.js | 21 +++++++++++---------- backend/models/alexa.js | 6 +++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/backend/helpers/amazon.js b/backend/helpers/amazon.js index f280ed4..13bf567 100644 --- a/backend/helpers/amazon.js +++ b/backend/helpers/amazon.js @@ -66,16 +66,17 @@ var generateInteractionModel = function (skill) { //Special Amazon intent - allIntents.push ( - { - name: 'AMAZON.YesIntent', - samples: [], - }, - { - name: 'AMAZON.NoIntent', - samples: [], - } - ); + allIntents.push ({ + name: 'YesIntent', + samples: ['Yes', 'Yes please', 'Sure'], + slots: [], + }); + + allIntents.push ({ + name: 'NoIntent', + samples: ['No', 'No thank you'], + slots: [], + }); skill.intents.map (intent => { allIntents.push ({name: intent.intentName, samples: intent.questions}); diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 9723c1f..22cbdc7 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -50,7 +50,7 @@ module.exports = { this.attributes['WaitingQuestions'] = false; }; - handlers['AMAZON.YesIntent'] = function () { + handlers['YesIntent'] = function () { console.log("yes intent"); if (this.attributes['WaitingQuestions']) { this.response @@ -60,7 +60,7 @@ module.exports = { } }; - handlers['AMAZON.NoIntent'] = function () { + handlers['NoIntent'] = function () { console.log("No intent"); if (this.attributes['WaitingQuestions']) { this.attributes['WaitingQuestions'] = false; @@ -71,7 +71,7 @@ module.exports = { handlers = { LaunchRequest: function () { this.response - .speak (activeSkill.invocationAnswer + ' Would you like to hear possible questions ?') + .speak (activeSkill.invocationAnswer + ' Would you like to hear possible questions ?') .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! this.attributes['WantToHearQuestions'] = true; -- 2.47.3 From b2386ea0d6520796aef77c04e9dca5456333ecde Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 01:03:59 +0100 Subject: [PATCH 21/31] Yes and No intent dont work with dialog --- backend/helpers/amazon.js | 14 -------------- backend/models/alexa.js | 31 ++++++------------------------- 2 files changed, 6 insertions(+), 39 deletions(-) diff --git a/backend/helpers/amazon.js b/backend/helpers/amazon.js index 13bf567..fcc781e 100644 --- a/backend/helpers/amazon.js +++ b/backend/helpers/amazon.js @@ -64,20 +64,6 @@ var generateInteractionModel = function (skill) { let result = {}; let allIntents = []; - //Special Amazon intent - - allIntents.push ({ - name: 'YesIntent', - samples: ['Yes', 'Yes please', 'Sure'], - slots: [], - }); - - allIntents.push ({ - name: 'NoIntent', - samples: ['No', 'No thank you'], - slots: [], - }); - skill.intents.map (intent => { allIntents.push ({name: intent.intentName, samples: intent.questions}); }); diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 22cbdc7..a08f6fb 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -42,40 +42,21 @@ module.exports = { ''; } }); - console.log(listOfPossibleQuestions); //Defaul Amazon handlers (some of them) - handlers.NewSession = function () { - this.attributes['WaitingQuestions'] = false; - }; - - handlers['YesIntent'] = function () { - console.log("yes intent"); - if (this.attributes['WaitingQuestions']) { - this.response - .speak (listOfPossibleQuestions) - .listen(constants.voiceResponseStrings.GENERIC_CONTINUE); - this.emit(':responseReady'); - } - }; - - handlers['NoIntent'] = function () { - console.log("No intent"); - if (this.attributes['WaitingQuestions']) { - this.attributes['WaitingQuestions'] = false; - } - }; + handlers.NewSession = function () {}; //Handler for launch request handlers = { LaunchRequest: function () { this.response - .speak (activeSkill.invocationAnswer + ' Would you like to hear possible questions ?') + .speak ( + activeSkill.invocationAnswer + + '' + + listOfPossibleQuestions + ) .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! - - this.attributes['WantToHearQuestions'] = true; - this.emit (':responseReady'); }, }; -- 2.47.3 From 97b6755f2f9cccdcf3bdf6b4fc0320966acd8af2 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 01:40:19 +0100 Subject: [PATCH 22/31] No magic numbers --- backend/config/constants.js | 6 ++++++ backend/models/alexa.js | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/config/constants.js b/backend/config/constants.js index b60f24b..299010e 100644 --- a/backend/config/constants.js +++ b/backend/config/constants.js @@ -31,6 +31,12 @@ constants.voiceResponseStrings = { GENERIC_CONTINUE : 'Would you like to continue' } +//Timing is given in [ms] +constats.voiceResponseTimings = { + PAUSE_BETWEEN_QUESTIONS : 650, + PAUSE_AFTER_WELCOME_MESSAGE : 650, +} + module.exports = constants; \ No newline at end of file diff --git a/backend/models/alexa.js b/backend/models/alexa.js index a08f6fb..801c5f9 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -39,7 +39,7 @@ module.exports = { listOfPossibleQuestions += intent.intentExplanation + intent.questions[0] + - ''; + ''; } }); @@ -53,7 +53,7 @@ module.exports = { this.response .speak ( activeSkill.invocationAnswer + - '' + + '' + listOfPossibleQuestions ) .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! -- 2.47.3 From c6cd49a66f6281339f05d77490f071174f725f6c Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 01:41:34 +0100 Subject: [PATCH 23/31] fix typo --- backend/config/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/config/constants.js b/backend/config/constants.js index 299010e..7c3a7df 100644 --- a/backend/config/constants.js +++ b/backend/config/constants.js @@ -32,7 +32,7 @@ constants.voiceResponseStrings = { } //Timing is given in [ms] -constats.voiceResponseTimings = { +constants.voiceResponseTimings = { PAUSE_BETWEEN_QUESTIONS : 650, PAUSE_AFTER_WELCOME_MESSAGE : 650, } -- 2.47.3 From 0d858ad1c7431349bec469cb5990a169bd21c10e Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 01:46:02 +0100 Subject: [PATCH 24/31] List only questions with explanation --- backend/models/alexa.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 801c5f9..3301a8e 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -35,7 +35,7 @@ module.exports = { let listOfPossibleQuestions = ''; activeSkill.intents.map (intent => { - if (intent.questions.length > 0) { + if (intent.questions.length > 0 && intent.intentExplanation) { listOfPossibleQuestions += intent.intentExplanation + intent.questions[0] + -- 2.47.3 From 370edd6ef0c4f9a107241a34350e7e027944957a Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 01:51:36 +0100 Subject: [PATCH 25/31] fix inherited explanation bug --- web/src/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/App.js b/web/src/App.js index 9f46a99..a91c5f6 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -255,7 +255,7 @@ class App extends Component { allIntents: this.state.allIntents, selectedIndex: NEW_INTENT_SELECTED_INDEX, launchRequest: false, - selectedIntent: {intentName: '', questions: [''], answer: ''}, + selectedIntent: {intentName: '', questions: [''], answer: '', intentExplanation:''}, }); } -- 2.47.3 From 3202bf5f0ba2981cf22c9d8cbcb35513416b0091 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 01:56:07 +0100 Subject: [PATCH 26/31] Implement help intent --- backend/models/alexa.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 3301a8e..87d1b95 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -39,7 +39,9 @@ module.exports = { listOfPossibleQuestions += intent.intentExplanation + intent.questions[0] + - ''; + ''; } }); @@ -47,13 +49,22 @@ module.exports = { handlers.NewSession = function () {}; + handlers['AMAZON.HelpIntent'] = function () { + console.log ('Help intent'); + this.response + .speak (listOfPossibleQuestions) + .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! + }; + //Handler for launch request handlers = { LaunchRequest: function () { this.response .speak ( activeSkill.invocationAnswer + - '' + + '' + listOfPossibleQuestions ) .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! -- 2.47.3 From 6b26db3d18b6ea6d376157f11db30abd61f4266b Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 02:15:44 +0100 Subject: [PATCH 27/31] fix code --- backend/models/alexa.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 87d1b95..51ac02e 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -45,18 +45,7 @@ module.exports = { } }); - //Defaul Amazon handlers (some of them) - - handlers.NewSession = function () {}; - - handlers['AMAZON.HelpIntent'] = function () { - console.log ('Help intent'); - this.response - .speak (listOfPossibleQuestions) - .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! - }; - - //Handler for launch request + //Handler for launch requestconsole.log() handlers = { LaunchRequest: function () { this.response @@ -170,6 +159,19 @@ module.exports = { } }; + //Defaul Amazon handlers (some of them) + + handlers.NewSession = function () { + console.log(this.event.request); + }; + + handlers['AMAZON.HelpIntent'] = function () { + console.log ('Help intent'); + this.response + .speak (listOfPossibleQuestions) + .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! + }; + //Default handlers for unknown questions and session close handlers.Unhandled = function () { -- 2.47.3 From 0a8eb2e280146f3cda62932e77ac6494437f4a6e Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 02:18:08 +0100 Subject: [PATCH 28/31] fix code --- backend/models/alexa.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 51ac02e..63d9f16 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -161,10 +161,6 @@ module.exports = { //Defaul Amazon handlers (some of them) - handlers.NewSession = function () { - console.log(this.event.request); - }; - handlers['AMAZON.HelpIntent'] = function () { console.log ('Help intent'); this.response -- 2.47.3 From cc579133c0688076636b38b8328097611b1f4bce Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 02:23:59 +0100 Subject: [PATCH 29/31] Amazon default intents not working with dialog --- backend/models/alexa.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 63d9f16..61b390c 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -159,15 +159,6 @@ module.exports = { } }; - //Defaul Amazon handlers (some of them) - - handlers['AMAZON.HelpIntent'] = function () { - console.log ('Help intent'); - this.response - .speak (listOfPossibleQuestions) - .listen (constants.voiceResponseStrings.GENERIC_CONTINUE); //Phrase from listen doesn't work !!! - }; - //Default handlers for unknown questions and session close handlers.Unhandled = function () { -- 2.47.3 From dc2c8f384e6ed1a9fb5a0a9af65aa3e27fab8536 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 12:15:04 +0100 Subject: [PATCH 30/31] use foreach instead of map --- backend/models/alexa.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 61b390c..c9a32e2 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -34,7 +34,7 @@ module.exports = { destinationEmail = activeSkill.contactEmail; let listOfPossibleQuestions = ''; - activeSkill.intents.map (intent => { + activeSkill.intents.forEach(intent => { if (intent.questions.length > 0 && intent.intentExplanation) { listOfPossibleQuestions += intent.intentExplanation + @@ -45,6 +45,8 @@ module.exports = { } }); + console.log(listOfPossibleQuestions); + //Handler for launch requestconsole.log() handlers = { LaunchRequest: function () { -- 2.47.3 From d8b2f5f0b4e3efb36a771d569b6d944e84c737c7 Mon Sep 17 00:00:00 2001 From: GotPPay Date: Tue, 23 Jan 2018 12:18:20 +0100 Subject: [PATCH 31/31] fix typo --- backend/helpers/email.js | 2 +- backend/models/alexa.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/helpers/email.js b/backend/helpers/email.js index 76e109a..f13a0ce 100644 --- a/backend/helpers/email.js +++ b/backend/helpers/email.js @@ -26,7 +26,7 @@ module.exports = { return validEmailRegex.test (email); }, - sendEmal: function (name, fromEmail, message, toEmail) { + sendEmail: function (name, fromEmail, message, toEmail) { return new Promise ((resolve, reject) => { fromEmail = this.transformEmailFromAlexaResponse(fromEmail); let messageBody = diff --git a/backend/models/alexa.js b/backend/models/alexa.js index 4074784..309e210 100644 --- a/backend/models/alexa.js +++ b/backend/models/alexa.js @@ -121,7 +121,7 @@ module.exports = { console.log ('Email : ' + intent.slots.Email.value); console.log ('Message : ' + intent.slots.Message.value); emailHelper - .sendEmal ( + .sendEmail ( intent.slots.Name.value, intent.slots.Email.value, intent.slots.Message.value, -- 2.47.3