How to program a decision tree with Alexa? - javascript

I am currently trying to program an alexa skill. I am very stuck... trying to see if I can get Alexa to ask the user 'How they are feeling' and then use this to ask further questions. Not sure if I should make a variable or attribute... any help please.
For example, once the user says "SAD" for the emotion - I want to be able to ask further questions, like "Is it from your past or present?"
(AWS code)
const GREETING = [
'What emotion are you feeling today?',
'Hello, what emotion are you feeling right now?'
];
const SKILL_NAME = 'March Test';
const GET_FEEL = "That is unfortunate to hear?";
const HELP_MESSAGE = 'I can give you more information if you tell me
how you are feeling';
const HELP_REPROMPT = 'How are you feeling currently?';
const STOP_MESSAGE = 'Goodbye!';
const FeelingsList = [
{
Emotion: "SAD",
suggestion: "My suggestion for sad is dry your tears and find a
distraction"
},
{
Emotion: "HAPPY",
suggestion: "My suggestion for happy is keep smiling and keep shining"
},
{
Emotion: "ANGRY",
suggestion: "My suggestion for angry is count to ten and cool down"
}
];
const handlers = {
'LaunchRequest': function () {
const greetingArr = GREETING;
const greetingIndex = Math.floor(Math.random() *
greetingArr.length);
this.emit(':ask',greetingArr[greetingIndex]); //first action that
will be fired
},
'EmotionalState': function () {
var stateSlot = this.event.request.intent.slots.Emotion.value;
this.emit(':ask', EmotionalResponse(FeelingsList, 'Emotion',
stateSlot.toUpperCase()).suggestion);
},
'AMAZON.HelpIntent': function () {
const speechOutput = HELP_MESSAGE;
const reprompt = HELP_REPROMPT;
this.response.speak(speechOutput).listen(reprompt);
this.emit(':responseReady');
},
'AMAZON.CancelIntent': function () {
this.response.speak(STOP_MESSAGE);
this.emit(':responseReady');
},
'AMAZON.StopIntent': function () {
this.response.speak(STOP_MESSAGE);
this.emit(':responseReady');
},

Okay, thanks for answering my questions in comments, the EmotionalResponse function looks good. The way you have it set up currently should work well for a single response. If that is all you want Alexa to do here then just change ':ask' to ':tell' (which will respond and not expect the user to reply) so the line would become:
this.emit(':tell', EmotionalResponse(FeelingsList, 'Emotion', stateSlot.toUpperCase()).suggestion );
However, you want to be able to continue the conversation with multiple questions and response handlings. You might already have this but it's not in your code above, and you need it to use the Alexa SDK, so make sure you have this line at the very beginning:
const Alexa = require('alexa-sdk');
You also need this, preferably at the end:
exports.handler = function(event, context, callback) {
const alexa = Alexa.handler(event, context, callback);
alexa.registerHandlers(handlers);
alexa.execute();
};
Next, some things to know about continuing a conversation using Alexa SDK:
':ask'
will respond with the speechOutput sentence and expect a reply from the user, but if the user does not reply, then Alexa will "reprompt" the user with the repromptSpeech sentence.
':delegate'
will tell Alexa to determine which required slot to ask the user for, and use the prompt (set up in the Alexa developer console) to elicit the slot information from the user.
':elicitSlot'
will give Alexa the specific instructions of which slot to elicit and the exact prompt to use.
There are many ways to continue an Alexa conversation and build your logic of handling the user's input and build an appropriate response. But to use your example of requesting more information from the user such as "Is it from your past or present?", here is one way I would suggest:
First, create another slot for this intent (anytime you want to hold user input information you'll need another slot). Let's call it Timeframe.
The simplest way is to "delegate" to Alexa to elicit this slot, so in the console make the slot required and add a prompt message such as, "Are you feeling this way because of something in your past or present?" You can even get fancy and use the emotion slot in that message like this: "Are you feeling {Emotion} because of something in your past or present?" Alexa will auto fill that and it will sound more intelligent and conversational.
Next you'll want to improve the logic of this intent inside const handlers:
const handlers = {
...
'EmotionalState': function () {
var emotion = this.event.request.intent.slots.Emotion.value;
var timeframe = this.event.request.intent.slots.Timeframe.value;
if (!timeframe){
this.emit(':delegate');
} else {
var response = responseBuilder(emotion, timeframe);
this.emit(':tell', response);
}
},
...
} //<<--------------your code seems to be missing this to close handlers
function responseBuilder(emotion, timeframe) {
// compare emotion with timeframe to build the appropriate response
// just for example
if (emotion=="sad" && timeframe=="past") {
return "My suggestion for feeling sadness about the past is, dry your tears and find a distraction.";
}
}
That's just a rough idea, but should certainly get you progressing again. Good luck!

Create a global object emotions and have all the emotions as properties and the corresponding suggestions as the value for them. Something like this,
const emotions = {"Happy" : "Keep smiling and shining", "Angry" : "count to 10 and cool down"}
Then, access the global object with the varibale to which you got the slot value from the user utterance and add it along with your response.
For instance,
var stateSlot = this.event.request.intent.slots.Emotion.value;
var suggestion = emotions[stateSlot];
Use the square bracket to get the property in the emotions object that matches for the value in the variable stateSlot.

Related

Object scoping rules seem to change due to seemingly irrelevant library?

So, I'm familiar with the general gist of JavaScript's features regarding objects. They're refcounted and if they go to zero, they die. Additionally, apple = banana where both are objects doesn't copy banana to apple but makes apple a reference to banana.
That being said, some of my code has something like this:
// imagine ws require() and setup here...
var RateLimit = require("ws-rate-limit")('10s', 80);
SickWebsocketServer.on("connection", function(mysocket, req){
// blahblahblah...
RateLimit(mysocket); // See below...
mysocket.on("limited", function(){console.log("someone was limited!"});
mysocket.on("message", function(data){
if(JSON.parse(msg).MyFlagToMessageASpecificWebsocketClient){ // obvs dont do this lol
findme = MyArr.find(guy=>guy.Socket==mysocket);
if(findme) console.log("TRIGGER PLS :)"); // GOAL
else console.log("DON'T TRIGGER"); // SOMETHING WENT WRONG
}
});
MyArr.push({MyName:"my SICK object", MyNumber:MyArr.length, Socket:mysocket})
}
The library used for rate limiting is called ws-rate-limit and I have pasted a shortened (non-code removed) version down below (since it's tiny). Imagine it to be in a package called ws-rate-limit (because it is :D).
const duration = require('css-duration')
module.exports = rateLimit
function rateLimit (rate, max) {
const clients = []
// Create an interval that resets message counts
setInterval(() => {
let i = clients.length
while (i--) clients[i].messageCount = 0
}, duration(rate))
// Apply limiting to client:
return function limit (client) {
client.messageCount = 0
client.on('newListener', function (name, listener) {
if (name !== 'message' || listener._rated) return
// Rate limiting wrapper over listener:
function ratedListener (data, flags) {
if (client.messageCount++ < max) listener(data, flags)
else client.emit('limited', data, flags)
}
ratedListener._rated = true
client.on('message', ratedListener)
// Unset user's listener:
process.nextTick(() => client.removeListener('message', listener))
})
// Push on clients array, and add handler to remove from array:
clients.push(client)
client.on('close', () => clients.splice(clients.indexOf(client), 1))
}
}
My issue is that, when I do use the RateLimit function, the "DON'T TRIGGER" code triggers. If I literally remove that one single line (RateLimit(mysocket)) it goes into "TRIGGER PLS :)".
The above is obviously logically simplified from my actual application but I think you get the gist. Apologies for any misspellings that may lead to undefineds or stuff like that; I promise you my code works if not for the RateLimit(mysocket) line.
When I add console.logs into the find function to log both the guy.Socket object and the mysocket object, with the RateLimit(mysocket) line, the mysocket object's .toString() returns [object global] rather than [object Object]. I know that this is some complicated JavaScript object scoping problem, but I have no clue where to start in terms of investigating it.
Thank you! :)
I'll take a random shot in the dark based on intuition. My best guess is that your issue is with the guy.Socket==mysocket line. Comparing objects that way will only check if they both point to the same heap memory location, even if it's two different stack variables. In your example I can only assume that the RateLimit(mysocket) line is somehow creating a new heap location for that stack variable (creating a new object from it) and because of that your == comparison is then no longer equal (even if they have the exact same values) because they're pointing to different locations.
Try using: JSON.stringify(guy.socket) === JSON.stringify(mysocket).

How to create a command that only who have one of the roles can use?

let staffrole = ['383874699941117952', '149622819158884353', '149622998180036608'];
How do you make a command that only people who have one of the roles can use it?
Thank you!
What you can do is that, on a message event, you run the command, and you can check the member's roles for one of the ones in the array.
Heres what that would look like:
client.on("message", msg => {
if(command === "whateverItIs") {
let staffrole = ['383874699941117952', '149622819158884353', '149622998180036608'];
for(i=0;i<staffrole.length;i++) {
if(msg.member.roles.filter((role) => role.id == staffrole[i]).size > 0) {
//run the code
return;
}
}
}
})
On a message event, with the determined command, the bot will check through each of the staff roles and if the message author 's roles includes one of the staffrole's then the command will run.
I would recommend doing something like this:
First, set your command name in the client's message listener:
// ... (in client message listener)
switch(command) {
case '<your command>':
runIfRoleIncluded(message);
break;
}
Next, get the role Id from the message that was sent and check if that message's role Id is in your staffrole array:
function runIfRoleIncluded(message) {
let rolesCollection = message.member.roles;
let staffrole = ['383874699941117952', '149622819158884353', '149622998180036608'];
// only 1 member can send a message, so get role collection's first key (id)
let messageRoleId = rolesCollection.firstKey();
// check if message's role id is in staff role array
if (staffrole.includes(messageRoleId)) {
// do stuff here
// ...
}
}
The .roles property of the .member object is a Collection, which is why you have to use the .firstKey() method. You can also turn the Collection into a normal js Array, but the way I outlined above is easier.
Started looking at this... Don't know the discord space very well but got an example bot and with a hello world ping, also found this pretty sweet Github gist that lays out fairly well how to build what amounts to a command switch statement. Making a lot of guesses here -- as a note for future questions it would be very helpful for you to add in some code on what you are trying to do -- a single variable set to an array isn't much to go on...
After Reading what #Raymond Zhang said, because, yeh that's what I was doing...
this is straight out of the Github gist I linked ->
...
if(command === "kick") {
if(!message.member.roles.some(r=>["Administrator","Moderator"].includes(r.name)) )
return message.reply("Sorry, you don't have permissions to use this!");
...
I have tested this and it works great, although it checks against the roles name not a number. It would help if you updated you answer to explain your process. More info = better answer. :)

Setting & saving a pointer in a certain class in parse.com with JavaScript

I am trying to create two pointers to store in a class called appointments. One pointer is for a teacher & other for the student. I have used a global variable for selectedTeacherId in another event to store the selected teachers user id as a string. below is my code. I get an error message 400 bad request. Why isn't my pointers & class saving?
$('#final-submit').on('click', function() {
var day= $('div#apt-detail-time li span#day').text();
var time= $('div#apt-detail-time li span#time').text();
var currentUser = Parse.User.current();
var currentUserId = currentUser.id;
var userPointer = {
__type: 'Pointer',
className: '_User',
objectId: currentUserId
}
var teacherPointer = {
__type: 'Pointer',
className: '_User',
objectId: selectedTeacherId
}
var appointment = Parse.Object.extend("Appoinments");
var newAppointment = new appointment();
newAppointment.set('day', day);
newAppointment.set('time', time);
newAppointment.set('type', 'pending');
newAppointment.set('student', userPointer);
newAppointment.set('teacher', teacherPointer);
newAppointment.save();
}); `
A few things may be causing your problems:
Where is selectedTeacherId coming from? It's not defined in your function. Depending on how this is implemented, this may be the cause of your error.
You spelled "Appointments" wrong in var appointment = Parse.Object.extend("Appoinments");
I recommend that you always pass a success and error callback to any .save() calls. You can check on the Parse Javascript SDK documentations for idiomatic examples of this. By passing success and error callbacks, if you get a bad request or other error, you will be able to invoke an alert() or console.log() function to display the cause of the errors. Furthermore, there are bugs that might cause you to make an infinite number of requests to Parse. Because Parse charges money above a certain rate of requests, you may be charged unintentionally if you are not careful.

Manageable timers in node

I'm looking for a way to create named timers in node that can be started, stopped/paused and have their intervals or functionality changed.
I am making an IRC bot that I want to have say certain general messages on a timer.
I have this messages.js setup with a handful of objects like so
module.exports = [
{
title: "donate",
message: "If you would like to help the stream out, donate at https://www.twitchalerts.com/donate/matax91 . All donations go toward the stream!",
interval: 1,
active: true
},
...
]
And in my app.js I have this setup
var Messages = require('./messages');
var activeMessages = [];
client.addListener('join', function(){
for(var id in Messages){
if(Messages[id].active){
console.log('set interval');
activeMessages[Messages[id].title] = setInterval(function(){
console.log('sent message');
client.say(config.channels[0], Messages[id].message);
},(Messages[id].interval * 60000));
}
}
});
The problem I see is that it's going to be really hard to pause these messages, or make changes to their intervals if I want to. I feel like there is a module that may be able to help me do this, but my searches aren't turning up much. Any advice would be great!

Introducing a circular dependency via JavaScript constructors

I have a javascript app that I'm developing where I'm building an action tree on the fly and I've found myself in the curious situation of wanting to purposefully introduce a circular dependency. After an initial very hacky attempt, I discovered that JavaScript variable scoping actually introduces a a pretty reasonable way to solve this. I'm still no expert at JavaScript, so I wanted to get some input on best practices. Here is a snippet of working code:
var Step = function(title, instructions, action) {
this.title = ko.observable(title);
this.instructions = instructions;
this.action = action;
};
var Action = function(cancelText, cancelDescription, cancelStep, nextDescription, addText, addStep, continueText, continueStep) {
this.cancelText = cancelText;
this.cancelDescription = cancelDescription;
this.cancelStep = cancelStep;
this.nextDescription = nextDescription;
this.addText = addText;
this.addStep = addStep;
this.continueText = continueText;
this.continueStep = continueStep;
};
var PersonalStep = new Step(
"Contact Information",
"How can we contact you about your awesome assortment of vehicles? Fill out the form below",
new Action(null, null, null, null, null, null, null, null)
);
var AddVehicleStep = new Step(
"Additional Vehicle",
"You have another car? Great, tell us about it too!",
new Action("Cancel",
"No, nevermind about this vehicle.",
PersonalStep,
"Add another vehicle?",
"+ Add",
AddVehicleStep, // This is the weird bit to me
"No, continue on",
PersonalStep)
);
var VehicleStep = new Step(
"Vehicle Details",
"Tell us about your primary vehicle by filling out the form below.",
new Action(null, null, null,
"Add another vehicle?",
"+ Add",
AddVehicleStep,
"No, continue on",
PersonalStep)
);
So in effect, the AddVehicleStep can continuously add additional vehicles when the user chooses the 'Add' action on the form. In most languages (that I'm familiar with, anyways), the AddVehicleStep variable would fail to parse from within its own constructor. This is very strange to me and I would like to learn more about this idiom of JS. Is there a better way to do object trees like this on the fly?
It also got me to thinking, I had been purposefully declaring my step variables in reverse order so they would be parseable. My discovery about referencing the variable in its own constructor led me to believe that this wasn't necessary. But I just tested it and if I move the AddVehicleStep var after the VehicleStep, VehicleStep gets null for its action.addStep. Is there a way to get around this limitation and let my variables be declared in any order? Would using blank declarations and later setting them work? e.g.
var a;
var b;
var a = new Step(b);
var b = new Step(b);
// a should now have the full instantiated object of b within it, right?
// (provided the step constructor assigned it, of course)
This has probably been answered elsewhere, I just haven't found the keyword to bring it up...
Also, I'm using these steps as part of a Knockout.js app which is essentially implementing a dialog/form wizard - I hope the example code stands on its own for posing the conundrum, but in case you were curious.
Update
I had this working in a JS fiddle last night. Turns out that there is something about how the js memory is handled between subsequent runs on jsfiddle that caused it work in the particular window I had been working in (Chrome, latest version). However, opening it in a new window or new browser and it stops working.
The really weird part is that I can't replicate the behavior in any browser. Maybe one of my edits had it declared differently and got it lodged in memory somehow. I really wish I could replicate it, just to prove I'm not crazy...
Thanks for the help!
Since steps can have actions that refer to the same step, I think it'd be simplest to just allow yourself the ability too add the action after the step has been constructed. So, something like this.
var Step = function(title, instructions, action) {
this.title = ko.observable(title);
this.instructions = instructions;
if (action === undefined)
this.action = null; //action was not passed
else
this.action = action;
};
//set the action after constructor invocation
Step.prototype.SetAction = function(action) {
this.action = action;
};
var AddVehicleStep = new Step(
"Additional Vehicle",
"You have another car? Great, tell us about it too!"
);
//AddVehicleStep is now instantiated with a new Step,
// so we can now set its action refering to that step
AddVehicleStep.SetAction(new Action("Cancel",
"No, nevermind about this vehicle.",
PersonalStep,
"Add another vehicle?",
"+ Add",
AddVehicleStep, // This is the weird bit to me
"No, continue on",
PersonalStep));
or hell, forget the method and do it directly
AddVehicleStep.action = new Action(...);
but then if you start doing that you loose the ability to always determine what happens when you set your action without rewriting your code.
Why do this? You have to understand order of operations and how that effects things here.
in
a = b(c(a))
the order of operations is
c(a) -> result1
b(result1) -> result2
a gets the value of result2
assuming a (in the local scope) was not assigned to before, then c(a) is equivalent to c(undefined)
Have a look at the below code:
function b(data, ref) {
alert("instantiated B with : " + data + " and " + ref);
}
function c(ref){
alert("instantiated C with : " + ref + " ... this doesnt work");
}
var a = new b('blah', new c(a));
'b' is initialized properly. But alert you get in initializing 'c' is as follows:
"instantiated C with : undefined ... this doesnt work"
This is because by the time 'c' is initiated, 'a' is not initiated and referenced properly.
Try on jsfiddle:
http://jsfiddle.net/sNbm5/

Categories