what is the difference between this.emit(:ask) and this.response(:speak) in amazon alexa
EG:
let handler = {
'PlayVideoIntent' : function() {
// VideoApp.Play directives can be added to the response
if (this.event.context.System.device.supportedInterfaces.VideoApp) {
this.response.playVideo('http://path/to/my/video.mp4');
} else {
this.response.speak("The video cannot be played on your device. " +
"To watch this video, try launching the skill from your echo show device.");
}
this.emit(':responseReady');
}
}
Alexa Skills Kit documentation have a detailed explanation.
From Response vs ResponseBuilder section:
Currently, there are two ways to generate the response objects in Node.js SDK. The first way is using the syntax follows the format this.emit(:${action}, 'responseContent').
If you want to manually create your own responses, you can use this.response to help. this.response contains a series of functions, that you can use to set the different properties of the response. This allows you to take advantage of the Alexa Skills Kit's built-in audio and video player support. Once you've set up your response, you can just call this.emit(':responseReady') to send your response to Alexa. The functions within this.response are also chainable, so you can use as many as you want in a row.
When you have finished set up your response, simply call this.emit(':responseReady') to send your response off. Below are two examples that build response with several response objects:
Example1:
this.response.speak(speechOutput)
.listen(repromptSpeech);
this.emit(':responseReady');
Example 2
this.response.speak(speechOutput)
.cardRenderer(cardTitle, cardContent, cardImage)
.renderTemplate(template)
.hint(hintText, hintType);
this.emit(':responseReady');
Since responseBuilder is more flexible to build rich response objects, we prefer using this method to build the response.
Welcome to StackOverflow. The answer is available in the question itself.
When you have an ask it essentially means that the session is still maintained and Alexa is expecting something from the user. And on the other hand if you are going with a tell, it means that there is no session available. below example will be helpful.
tell
User: Alexa, how are you doing.
Alexa: I'm doing good thank you.
--Conversation ended
ask
User: Alexa set an alarm
Alexa: sure, at what time? <-- This is where we use ask, as the conversation is incomplete
User: at 5:30 AM
Alexa: Alarm set <-- This is where we use tell, as the task is done and there is no use of user's input anymore.
Hope this helps you.
Happy Coding!!!
Related
I am trying to develop an Alexa Skill with ASK node.js SDK. I am trying to build a game where the Alexa and the user take turns counting (not a great game, but useful educationally for me). Alexa starts with one, then the user two, then Alexa says three, and so on until the user says an incorrect number. In this case, I hope to implement logic to end the game.I am struggling to figure out how to get Alexa to respond differently after each time the user says a number. Is this a situation where I need multiple intent handlers? It seems like that would be silly, as the general logic does not change. I'm struggling to find up to date example code of game logic generally, so any resources that I can learn from would be greatly appreciated. The code I have as of yet is as follows--
const MyGameIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'MyGameIntent';
},
handle(handlerInput) {
const speechText = 'One';
return handlerInput.responseBuilder
.speak(speechText).listen()
.getResponse();
}
};
Obviously, I have not gotten very far. I have successfully created an intent and tested that Alexa will respond with 'One' when I ask to start a game. Where I am stuck is how to get Alexa to say 'One', then wait for a user to say 'Two', and depending on if they said the correct number, Alexa would say 'Three' or 'Game over' and end the game. The Codecademy course for ASK uses a different and outdated syntax, but it is the closest I have come yet to an answer. It suggests to chain a .listen() after speak, but does not provide information about whether this .listen() will re-prompt the same intent handler
To make it work as you wish, you need to keep the state of the game in Session Attributes between utterances. Please read it to better understand how it works.
If about your game, I would suggest to follow those steps:
You speak "start the game", the skill responses with "One" (you have already implemented this part) AND stores the game state (ie. by saving next expected answer)
When it's your turn, the skill should check if received answer is equal to expected and react - continue and store next expected answer or finish the game. For this step you'll need another handler for intent which expects just a number.
There is an example from Alexa team that shows how to create a game and store the state between utterances - Trivia Game.
I am developing a Bot using NodeJs which should ask the user a set of questions and then after a break, ask the same another of questions again.
I am using await sleep(milliseconds) in between.
While testing using the Emulator, I noticed that the questions from the first set are sent one by one, saving the user's response. The second set is sent all at once without allowing the user to respond to each question of the second set individually.
await turnContext.sendActivity(askFirstSetOfQuestions(question));
await sleep(60000);
await turnContext.sendActivity(askSecondSetOfQuestions(question));
await next();
image - screen capture from emulator
Quite lost here..
any help would be appreciated.
There are two things to consider here. First, if you truly need a delay, it is better to await a promise than use sleep. You can do this via await new Promise (resolve => setTimeout(resolve, DELAY_LENGTH);. I use this frequently in conjunction with typing indicator to give the bot a more natural feeling conversation flow when it sends two or more discrete messages without waiting for user input.
However, as Eric mentioned, it seems like you might want a waterfall dialog instead for your use case. This sample from botbuilder-samples is a good example. Each step would be a prompt, and it will wait for user input before proceeding. I won't try to write an entire bot here, but a single question-answer step would look something like:
async firstQuestion(stepContext) {
return await stepContext.prompt(TEXT_PROMPT, 'Question 1');
}
async secondQuestion(stepContext) {
stepContext.values.firstAnswer = stepContext.result;
return await stepContext.prompt(TEXT_PROMPT, 'Question 2');
}
and so forth. Not sure what you are doing with the responses, but in the example above I'm saving it to stepContext.values so that the answers are all available in later steps as part of the context object.
If you can detail more of what your use case/expected behavior and share what askFirstSetOfQuestions is, we could provide further assistance.
I'm still a novice web developer, so please bear with me if I miss something fundamental !
I'm creating a backoffice for a Strapi backend, using react-admin.
React-admin library uses a 'data provider' to link itself with an API. Luckily someone already wrote a data provider for Strapi. I had no problem with step 1 and 2 of this README, and I can authenticate to Strapi within my React app.
I now want to fetch and display my Strapi data, starting with Users. In order to do that, quoting Step 3 of this readme : 'In controllers I need to set the Content-Range header with the total number of results to build the pagination'.
So far I tried to do this in my User controller, with no success.
What I try to achieve:
First, I'd like it to simply work with the ctx.set('Content-Range', ...) hard-coded in the controller like aforementioned Step 3.
Second, I've thought it would be very dirty to c/p this logic in every controller (not to mention in any future controllers), instead of having some callback function dynamically appending the Content-Range header to any fetchAll request. Ultimately that's what I aim for, because with ~40 Strapi objects to administrate already and plenty more to come, it has to scale.
Technical infos
node -v: 11.13.0
npm -v: 6.7.0
strapi version: 3.0.0-alpha.25.2
uname -r output: Linux 4.14.106-97.85.amzn2.x86_64
DB: mySQL v2.16
So far I've tried accessing the count() method of User model like aforementioned step3, but my controller doesn't look like the example as I'm working with users-permissions plugin.
This is the action I've tried to edit (located in project/plugins/users-permissions/controllers/User.js)
find: async (ctx) => {
let data = await strapi.plugins['users-permissions'].services.user.fetchAll(ctx.query);
data.reduce((acc, user) => {
acc.push(_.omit(user.toJSON ? user.toJSON() : user, ['password', 'resetPasswordToken']));
return acc;
}, []);
// Send 200 `ok`
ctx.send(data);
},
From what I've gathered on Strapi documentation (here and also here), context is a sort of wrapper object. I only worked with Express-generated APIs before, so I understood this snippet as 'use fetchAll method of the User model object, with ctx.query as an argument', but I had no luck logging this ctx.query. And as I can't log stuff, I'm kinda blocked.
In my exploration, I naively tried to log the full ctx object and work from there:
// Send 200 `ok`
ctx.send(data);
strapi.log.info(ctx.query, ' were query');
strapi.log.info(ctx.request, 'were request');
strapi.log.info(ctx.response, 'were response');
strapi.log.info(ctx.res, 'were res');
strapi.log.info(ctx.req, 'were req');
strapi.log.info(ctx, 'is full context')
},
Unfortunately, I fear I miss something obvious, as it gives me no input at all. Making a fetchAll request from my React app with these console.logs print this in my terminal:
[2019-09-19T12:43:03.409Z] info were query
[2019-09-19T12:43:03.410Z] info were request
[2019-09-19T12:43:03.418Z] info were response
[2019-09-19T12:43:03.419Z] info were res
[2019-09-19T12:43:03.419Z] info were req
[2019-09-19T12:43:03.419Z] info is full context
[2019-09-19T12:43:03.435Z] debug GET /users?_sort=id:DESC&_start=0&_limit=10& (74 ms)
While in my frontend I get the good ol' The Content-Range header is missing in the HTTP Response message I'm trying to solve.
After writing this wall of text I realize the logging issue is separated from my original problem, but if I was able to at least log ctx properly, maybe I'd be able to find the solution myself.
Trying to summarize:
Actual problem is, how do I set my Content-Range properly in my strapi controller ? (partially answered cf. edit 3)
Collateral problem n°1: Can't even log ctx object (cf. edit 2)
Collateral problem n°2: Once I figure out the actual problem, is it feasible to address it dynamically (basically some callback function for index/fetchAll routes, in which the model is a variable, on which I'd call the appropriate count() method, and finally append the result to my response header)? I'm not asking for the code here, just if you think it's feasible and/or know a more elegant way.
Thank you for reading through and excuse me if it was confuse; I wasn't sure which infos would be relevant, so I thought the more the better.
/edit1: forgot to mention, in my controller I also tried to log strapi.plugins['users-permissions'].services.user object to see if it actually has a count() method but got no luck with that either. Also tried the original snippet (Step 3 of aforementioned README), but failed as expected as afaik I don't see the User model being imported anywhere (the only import in User.js being lodash)
/edit2: About the logs, my bad, I just misunderstood the documentation. I now do:
ctx.send(data);
strapi.log.info('ctx should be : ', {ctx});
strapi.log.info('ctx.req = ', {...ctx.req});
strapi.log.info('ctx.res = ', {...ctx.res});
strapi.log.info('ctx.request = ', {...ctx.request});
ctrapi.log.info('ctx.response = ', {...ctx.response});
Ctx logs this way; also it seems that it needs the spread operator to display nested objects ({ctx.req} crash the server, {...ctx.req} is okay). Cool, because it narrows the question to what's interesting.
/edit3: As expected, having logs helps big time. I've managed to display my users (although in the dirty way). Couldn't find any count() method, but watching the data object that is passed to ctx.send(), it's equivalent to your typical 'res.data' i.e a pure JSON with my user list. So a simple .length did the trick:
let data = await strapi.plugins['users-permissions'].services.user.fetchAll(ctx.query);
data.reduce((acc, user) => {
acc.push(_.omit(user.toJSON ? user.toJSON() : user, ['password', 'resetPasswordToken']));
return acc;
}, []);
ctx.set('Content-Range', data.length) // <-- it did the trick
// Send 200 `ok`
ctx.send(data);
Now starting to work on the hard part: the dynamic callback function that will do that for any index/fetchAll call. Will update once I figure it out
I'm using React Admin and Strapi together and installed ra-strapi-provider.
A little boring to paste Content-Range header into all of my controllers, so I searched for a better solution. Then I've found middleware concept and created one that fits my needs. It's probably not the best solution, but do its job well:
const _ = require("lodash");
module.exports = strapi => {
return {
// can also be async
initialize() {
strapi.app.use(async (ctx, next) => {
await next();
if (_.isArray(ctx.response.body))
ctx.set("Content-Range", ctx.response.body.length);
});
}
};
};
I hope it helps
For people still landing on this page:
Strapi has been updated from #alpha to #beta. Care, as some of the code in my OP is no longer valid; also some of their documentation is not up to date.
I failed to find a "clever" way to solve this problem; in the end I copy/pasted the ctx.set('Content-Range', data.length) bit in all relevant controllers and it just worked.
If somebody comes with a clever solution for that problem I'll happily accept his answer. With the current Strapi version I don't think it's doable with policies or lifecycle callbacks.
The "quick & easy fix" is still to customize each relevant Strapi controller.
With strapi#beta you don't have direct access to controller's code: you'll first need to "rewrite" one with the help of this doc. Then add the ctx.set('Content-Range', data.length) bit. Test it properly with RA, so for the other controllers, you'll just have to create the folder, name the file, copy/paste your code + "Search & Replace" on model name.
The "longer & cleaner fix" would be to dive into the react-admin source code and refactorize so the lack of "Content-Range" header doesn't break pagination.
You'll now have to maintain your own react-admin fork, so make sure you're already committed into this library and have A LOT of tables to manage through it (so much that customizing every Strapi controller will be too tedious).
Before forking RA, please remember all the stuff you can do with the Strapi backoffice alone (including embedding your custom React app into it) and ensure it will be worth the trouble.
For demonstrations purposes I should devolop an Alexa Skill on a dialogue basis.
All the alexa responses are hardcoded.
The template of the skill is like:
Part 1:
User: Alexa, ask MySkill {Question1}.
Alexa: Hardcoded answer.
Part 2:
User: Alexa, ask MySkill {Question2.1}
Alexa: Hardcoded answer for Question2.1.
User: Alexa, ask MySkill {Qeustion2.2}
Alexa: Hardcoded answer.
I was able to create part 1. But in Part 2 i have some problems.
Do I need seperate Intents for questions 2.1 and 2.2. Or is there a possiblity to keep the skill alive?
I'm going to first assume that you're using the alexa-sdk during your development. If you don't know that that is, please check out this link:
https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs
There are multiple ways you can break up questions to your skill in your intent schema. They can either be individual intents, such as "QuestionOneIntent" and "QuestionTwoIntent", or a single intent "QuestionIntent" where the slot values in those intents correspond to individual questions. As the original post hasn't given much information, I can't say which structure would be the best setup.
There are two general types of responses in the alexa-sdk. ":tell" will make Alexa say a response and immediately go back to her idle state (not listening to you). ":ask" will say a response, wait 8 seconds, and follow up with a reprompt message all while waiting for you to give another command.
As for keeping the session alive in a conversation, you could simply emit your response by using
var speechOutput = "This is the answer to Question"
var speechOutputReprompt = "Do you have any more questions?"
this.emit(":ask", speechOutput, speechOutputReprompt)
This will allow for your session to stay open and the user can continue to ask more questions. You will have to make another intent that will close the session if you answer "No" to the reprompt, thus making the shouldEndSession variable true. Here is an example of how I might structure the code:
"QuestionIntent": function(){
var responseName = ""
var slots = this.event.request.intent.slots
for (var slot in slots){
if(slots[slot].value != undefined){
responseName = slots[slot].name;
switch(responseName){
case "QuestionOneIntent":
var QuestionOneAnswer = "Answer to question one";
this.emit(":tell", QuestionOneAnswer);
break;
case "QuestionTwoIntent":
var QuestionTwoAnswer = "Answer to question two";
this.emit(":ask", QuestionTwoAnswer, QuestionTwoAnswerReprompt);
break;
default:
console.log("error");
break;
}
}
}
}
Looks like you are using single-turn interactions (i.e. you don't keep the session open, check shouldEndSession https://www.npmjs.com/package/alexa-app). Regardless, you need to either save the current state in the session object or store it somewhere else (tied to the unique request.userId).
Using different intents may be another solution but its prone to fail if you have similar utterances that may be incorrectly mis-mapped to one another.
If anyone here is familiar with the node-cloudfiles module for node.js, I could use some help in several different areas. Unfortunately, is seems the authors are nearly impossible to reach via their github repo (EDIT: nevermind, someone did reach out to me, I'll send an update when I have an answer of some sort prepared.)
I'll start with my most basic challenge: is there a way to track the progress of the upload? I have tried many things, but the object returned from the .addFile command does not seem to hold any sort of progress stats.
Here is a basic outline of what I am working with.
var readStream = fs.createReadStream(path+'.'+extension, streamopts);
var upOpts = {
headers: {
'content-type': 'video/'+extension,
'content-length': totalBytes
},
remote: CDNfilename,
stream: readStream
};
//reqStream is the object returned from the 'request' module,
//which is used by the 'cloudfiles' module.
var reqStream = cloudClient.addFile(Container.name, upOpts, function (err, uploaded) {
if (err) { console.log(err); }
});
At first I thought I could just use the .bytesWritten property connected to an interval timer, but the object is not a normal node writeStream, so there is no such property.
Charlie (the author of the module) told me that this is possible because it's using a pipe and you just check the data events from the object returned from .addFile, like so:
reqStream.on('data', function () {
/* track progress /*
});
Whenever you need to contact somebody from the nodejitsu team, join the #nodejitsu channel on IRC, they're really active.
At the time of writing this answer, there isn't really a good way to get upload progress for files being sent to cloudfiles. However, one of the nodejitsu geniuses implemented chunked uploading, which in my case, eliminates the need for progress reports. Thanks Bradley.