diff --git a/backend/express.js b/backend/express.js index 4177ee6..3a32745 100644 --- a/backend/express.js +++ b/backend/express.js @@ -12,8 +12,19 @@ const router = express.Router (); var app = express (); +//User data for sending message, this is skill-related and will be in some skill container +var Name = null; +var Email = null; +var Message = null; +var State = 0; // states should be defined in seperate file. (Not sending message, Waiting for name, Waiting for email, Waiting for message) +//For now : +// 0 : Not sending Message +// 1 : Waiting for name +// 2 : Waiting for email +// 3 : Waiting for message + // ALWAYS setup the alexa app and attach it to express before anything else. -var alexaApp = new alexa.app ('step3'); // this means we still work with one skill +var alexaApp = new alexa.app ('saburly'); // this means we still work with one skill alexaApp.express ({ expressApp: app, @@ -39,6 +50,7 @@ var updateIntentsJSON = function () { .loadSkill (config.SKILL_DB_ID) .then (skill => { skill.intents.map (intent => { + alexaApp.intent ( intent.intentName, { @@ -50,9 +62,93 @@ var updateIntentsJSON = function () { } ); }); + alexaApp.launch ((request, response) => { return response.say (skill.invocationAnswer).shouldEndSession(false); }); + + alexaApp.intent('EmailIntentLaunch',{ + slots:[], + utterances: [ + 'I want to send a message', + 'I would like to send a message', + 'I would like to leave a message', + 'Leave a message' + ] + }, + function(request,response){ + Name = null; + Email = null; + Message = null; + State = 1; + + return response.say('Ok. What is your name').shouldEndSession(false); + } + ); + + //TODO : Watch out for this intent. It will make trouble with other regular intents + //if other intents have utterance with just one slot like {Data} + //It should be taken care somwhere before this, to check if Email Intent is invoked + //This is problem only if we introduce slot options for regular intents for users + alexaApp.intent('EmailIntent',{ + slots:{ + 'Name':'AMAZON.Person', + 'Email' : 'AMAZON.LITERAL', + 'Message': 'AMAZON.LITERAL', + 'Data': 'AMAZON.LITERAL' + }, + utterances: [ + 'My name is {Name}', + 'I am {Name}', + '{Data}', + 'My email is {Email}', + 'Send replay to {Email}', + 'My message is {Message}' + ] + }, + function(request,response){ + if (!Name) Name = response.slots['Name']; + if (!Email) Email = response.slots['Email']; + if (!Message) Message = response.slots['Message']; + let Data = reponse.slots['Data']; + + //TODO : Responses could be configurable for each skill ? + + if (State === 1){ + //Was waiting for name, so if Name is null, name is probably in Data + if ((!Name && Data) || Name){ + //got the name, let's continue for the email + State = 2; + return response.say('Ok ' + Name + '. What is your email ?').shouldEndSession(false); + }else{ + //Something is wrong, ask for name again + return response.say('Sorry, I didnt understand your name. Can you say it again ?').shouldEndSession(false); + } + }else if (State === 2){ + //was waiting for email, so if Email is null, email is probably in Data + if ((!Email && Data) || Email){ + //Got the email, first verify email and than continue to message + + //TODO : verify email + State = 3; + return response.say('Great. Whats the message ?').shouldEndSession(false); + }else{ + //Something is wrong, ask for the email again + return response.say('Sorry, I didnt understan you email. Can you say it again ?').shouldEndSession(false); + } + }else if (State === 3){ + //Was waiting for message, so if Message is null, message is probably in Data + if ((!Message && Data) || Message){ + //Ok, we got all informations. Exit email intent + State = 0; + //TODO : Send email + return response.say('Message sent. Someone will contact you ASAP'); + } + } + + } + ); + }) .catch (err => { console.log (err); @@ -92,14 +188,15 @@ router.get ('/deleteSkill/:skillID', async (req, res, next) => { router.post ('/updateSkill/:id', async (req, res, next) => { let id = req.params.id; - let skill = req.body; + let dataFromWeb = JSON.stringify(req.body); + let skill = JSON.parse(dataFromWeb); + let updateOnAmazon = skill.updateOnAmazon; + delete skill.updateOnAmazon; delete skill._id; console.log('id = ' + id); if (id !== '-1') { - amazonHelper - .updateSkill (skill) - .then (amazonResult => { - console.log('amazon result : ' + amazonResult); + if (updateOnAmazon){ + amazonHelper.updateSkill(skill).then(amazonResult=>{ if (amazonResult === 200 || amazonResult === 202) { //Skill uploaded, it's ok to update databaseI databaseHelper @@ -109,16 +206,24 @@ router.post ('/updateSkill/:id', async (req, res, next) => { updateIntentsJSON (); }) .catch (e => { - res.json ({result: -1, message: 'ok'}); + res.json ({result: -1, message: 'error'}); }); - } else { - res.json ({result: -1, message: 'Amazon result ' + amazonResult}); } - }) - .catch (e => { - //skill upload went wrong, don't update database, send error + }).catch(e=>{ res.json ({result: -1, message: e}); }); + }else{ + databaseHelper + .updateSkill (id, skill) + .then (result => { + res.json ({result: 0, message: 'ok'}); + updateIntentsJSON (); + }) + .catch (e => { + res.json ({result: -1, message: 'error'}); + }); + } + } else { //no new skills for now } diff --git a/backend/helpers/amazon.js b/backend/helpers/amazon.js index 26ee7e2..24900e0 100644 --- a/backend/helpers/amazon.js +++ b/backend/helpers/amazon.js @@ -81,6 +81,47 @@ var generateInteractionModel = function (skill) { 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' + ] + }); + allIntents.push({ + name: 'EmailIntent', + slots:[ + { + name: 'Name', + type: 'AMAZON.Person' + }, + { + name: 'Email', + type: 'AMAZON.LITERAL' + }, + { + name: 'Message', + type: 'AMAZON.LITERAL' + }, + { + name: 'Data', + type: 'AMAZON.LITERAL' + } + ], + samples: [ + 'My name is {Name}', + 'I am {Name}', + '{Data}', + 'My email is {Email}', + 'Send replay to {Email}', + 'My message is {Message}' + ] + }); + result.interactionModel = {}; result.interactionModel.languageModel = { diff --git a/web/src/App.js b/web/src/App.js index 856efac..1a08693 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -4,9 +4,13 @@ import './css/popup.css'; import IntentList from './components/IntentList'; 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 { + NEW_INTENT_SELECTED_INDEX, + LAUNCH_REQUEST_SELECTED_INDEX, + CONTACT_SELECTED_INDEX} from './config' class App extends Component { @@ -20,8 +24,8 @@ class App extends Component { invocationAnswer:'We are saburly', allIntents:[], selectedIntent: {intentName:'',questions:[''],answer:''}, - selectedIndex:-1, - launchRequest:false, + selectedIndex:NEW_INTENT_SELECTED_INDEX, + contactEmail:'', waiting: false }; @@ -30,7 +34,7 @@ class App extends Component { if (jResult===undefined) return; this.setState({ skillID:jResult.skillID,skillName:jResult.skillName, invocationName: jResult.invocationName, invocationAnswer: jResult.invocationAnswer, - allIntents: jResult.intents}) + allIntents: jResult.intents, contactEmail: jResult.contactEmail}) }) this.handleIntentClick = this.handleIntentClick.bind(this); @@ -41,62 +45,67 @@ class App extends Component { 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() { - - if(this.state.launchRequest){ - return ( -