Calling Another Alexa intent from within LaunchRequest - node.js

I am working on an Alexa skill where I would like to redirect user to one intent when he opens the skill via LaunchRequest.
User says Open xyz skill
LaunchRequest receives this and forwards the request to another intent.this.emit('AnotherIntent')
AnotherIntent has a SLOT which is required for its functioning.
I have setup the SLOT as required and AnotherIntent does work perfectly fine when invoked on its own.
However when I Launch the skill and tries to call AnotherIntent from within it as mentioned in Step 2 above, Alexa skill fails to launch.
One more thing to note is when I Test the same Alexa skill from within the skill builder for this scenario, the output json correctly shows me the SLOT being elicited. Not sure what is happening when I am trying to run it from Echo device.
I am using NodeJS and Lambda to deploy my Alexa handlers.
Any help would be appreciated.
Further reference based on the comment -
Handlers -
var handlers = {
'LaunchRequest': function () {
console.log("LaunchRequest::" + JSON.stringify(this.event.request));
this.emit('fooIntent');
},
'SessionEndedRequest': function () {
console.log('session ended!');
},
'fooIntent': function () {
const intentObj = this.event.request.intent;
if (!intentObj || (intentObj && !intentObj.slots.WHEN.value)) {
console.log('fooIntent::UserId' + this.event.session.user.userId);
const slotToElicit = 'WHEN';
const speechOutput = 'Ask a question here ?';
const repromptSpeech = speechOutput;
console.log("emitting elict now");
this.emit(':elicitSlot', slotToElicit, speechOutput, repromptSpeech);
} else {
// SLOT is filled, let's query the database to get the value for the slot.
console.log("fooIntent intent:something is requested for " + this.event.request.intent.slots.WHEN.value);
// All the slots are filled (And confirmed if you choose to confirm slot/intent)
fooIntentFunction(this,this.event.request.intent.slots.WHEN.value);
}
},
'AMAZON.HelpIntent': function () {
var speechOutput = "Need to come up with one.";
var reprompt = "What can I help you with?";
this.emit(':ask', speechOutput, reprompt);
},
'AMAZON.CancelIntent': function () {
this.emit(':tell', 'Goodbye!');
},
'AMAZON.StopIntent': function () {
this.emit(':tell', 'Goodbye!');
}
};
JSON Request captured in LaunchRequest
{
"type": "LaunchRequest",
"requestId": "amzn1.echo-api.request.972bb705-d181-495e-bf60-991f2bd8fbb1",
"timestamp": "2017-12-30T21:35:21Z",
"locale": "en-US"
}
JSON Request captured in the Intent when invoked from LaunchRequest. It shows that intent is not set then. I believe that is why it keeps failing when I try to emit elicit in the fooIntent implementation as shown above.
{
"type": "LaunchRequest",
"requestId": "amzn1.echo-api.request.972bb705-d181-495e-bf60-991f2bd8fbb1",
"timestamp": "2017-12-30T21:35:21Z",
"locale": "en-US"
}
Amit

As specified in Amazon's documentation, the dialog interface is meant to fill all required slots of a specific intent:
The questions and answers are intended to gather and confirm values for all of the intent’s required slots. The conversation continues until all slots needed for the intent are filled and confirmed.
In your case, the user's request is not an intent (i.e. of the IntentRequest type), but a LaunchRequest. As such,it has no interaction model and no slots to elicit, even though it is processed by an intent handler.
You should get your Skill to work as intended with a deep invocation, like
Alexa, tell xyz skill to make me a sandwich
(if the sandwich intent, or in your case the fooIntent, has a WHEN slot to elicit).
Hope this helps!

try this,
this.emitWithState("IntentName");
Hope this helps. all the best :)

Calling an intent from another intent can be simply done using the following snippet - \
this.emit("Intent name")
In the response of your first intent, give the name of the intent you wish to call.

Related

Amazon Lex V2 Lambda not progressing to next slot

I have a LEX V2 bot configured, which has two slots and a confirmation slot. The two slots ask for dateFrom and dateTo. Now I have a Lambda that I use for fulfilment but also needs to fire on every single event. After the initial utterance, the Lambda takes the event.proposedNextState.dialogAction.slotToElicit and returns that inside dialogAction.slotToElicit along with dialogAction.type set to "Delegate". Now that works fine, however after providing the dateFrom value, even though the lambda responds with
{
sessionState: { dialogAction: { type: 'Delegate', slotToElicit: 'dateTo' } }
}
the next slot is not dateTo, but rather dateFrom again. Anyone has any ideas why it might not work like that? I don't understand why it is like that, maybe I am supposed to send a different type on dialog action? Below is the full Lambda function which handles events that are of type DialogCodeHook:
const response: LexResponse = {
sessionState: {
dialogAction: {
type: LexDialogActionType.Delegate,
slotToElicit: event.proposedNextState.dialogAction.slotToElicit,
},
},
};
console.log("EVENT", event);
console.log("RESPONSE", response);
callback(null, response);
Intent is mandatory in the Lambda response if dialogAction.type=Delegate.
However, AWS documentation about response format is misleading. It says "intent – The name of the intent that Amazon Lex V2 should use". Actually, it's a structure. Set it to event.sessionState.intent.
Although not mandatory, consider forwarding sessionAttributes too.

How to tell Alexa to jump to a specific intent from LaunchRequest based on user input

I am quite new in Alexa development so please excuse my ignorance. The Alexa skill I am developing requires the following:
Users will awake the skill along with a question, e.g.
Alexa, ask marketing platform about result of last campaign
I am referring to https://developer.amazon.com/docs/custom-skills/understanding-how-users-invoke-custom-skills.html#cert-invoke-specific-request but not quite understand how to jump to a specific intent from LaunchRequest.
Where marketing platform is the skill invocation and result of last campaign is the utterance for skill intent named CampaignIntent.
There are more intents like this, which I want to call based on user's question, e.g.
Alexa, ask marketing platform to give me messaging details
I am using Lambda for the skill. At the moment it looks like the following:
exports.handler = (event, context, callback) => {
try {
if (event.request.type === 'LaunchRequest') {
var welcomeMessage = '<speak>';
welcomeMessage = welcomeMessage + 'Welcome to XYZ agency.';
welcomeMessage = welcomeMessage + '</speak>';
callback(null, buildResponse(welcomeMessage, false));
//How can I tell Alexa to jump to CampaignIntent?
}
else if (event.request.type === 'IntentRequest') {
const intentName = event.request.intent.name;
if (intentName === 'CampaignIntent') {
var ssmlConfirm = "<speak>";
ssmlConfirm = ssmlConfirm + 'Hello Auto.';
ssmlConfirm = ssmlConfirm + "</speak>";
callback(null, buildResponse(ssmlConfirm, true));
}
}
}
catch (e) {
context.fail(`Exception: ${e}`);
}
};
function buildResponse(response, shouldEndSession) {
return {
version: '1.0',
response: {
outputSpeech: {
type: 'SSML',
ssml: response,
},
shouldEndSession: shouldEndSession,
},
sessionAttributes: {},
};
}
CampaignIntent does not have any slot. It simply fetches records from a third party platform API.
I also referred https://stackoverflow.com/a/48032367/1496518 but did not understand how to achieve ...has a WHEN slot to elicit part.
The documentation you linked say, "Users can combine your invocation name with an action, command or question. This sends the service for your skill an IntentRequest with the specific intent that corresponds to the user's request."
If a user invokes your skill in this way, the intent you find in the first request of that user's session will be CampaignIntent (the IntentRequest you've defined) instead of LaunchRequest. There isn't any "jumping" you need to do on your end. The behavior will be the same with or without slot values.

Regarding retrieving prompts

[We have a Dialogflow bot consisting of two intents. Each intent contains some set of questions.
The user answers the questions(prompts) and this process continues. We are getting the fulfillment text only after the intent is completed but we need to get the fulfillment text(Each and every prompt) after completing every question in that particular intent.
Help us in finding the solution.
You can use webhook for slot filling. (under the "Enable webhook call for this intent", enable Enable webhook call for slot filling button). By doing this, you can still stay in intent handler function and prompt what you need until you can finish your steps.
For example:
function flight(agent) {
const city = agent.parameters['geo-city'];
const time = agent.parameters['time'];
const gotCity = city.length > 0;
const gotTime = time.length > 0;
if(gotCity && gotTime) {
agent.add(`Nice, you want to fly to ${city} at ${time}.`);
} else if (gotCity && !gotTime) {
agent.add('Let me know which time you want to fly');
} else if (gotTime && !gotCity) {
agent.add('Let me know which city you want to fly to');
} else {
agent.add('Let me know which city and time you want to fly');
}
}
Also you can use this functionality on actions-on-google library.
Check for more information:
Webhook for slot filling
Enable Webhook for Slot Filling. Dialogflow will call your server to see if you can provide the pending information that your user didn’t.

Dialogflow assistant app exiting after successful fulfillment

I have a dialogflow assistant app with 3 intents. The first intent asks the user for location and name details from google. I am using a webhook for the fulfillment of this intent. I am able to extract the user information name and location, but after it is showing output from webhook, it is exiting from flow. But it is supposed to pass the location parameters to next intent and stay on the flow. Can anybody help me how to stop assistant from exiting?
Here is the webhook code
'use strict';
const functions = require('firebase-functions');
const DialogflowApp = require('actions-on-google').DialogflowApp;
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const requestPermission = (app) => {
app.askForPermissions('To report ', [app.SupportedPermissions.NAME, app.SupportedPermissions.DEVICE_PRECISE_LOCATION]);
};
const userInfo = (app) => {
if (app.isPermissionGranted()) {
const address = app.getDeviceLocation().coordinates;
const name = app.getUserName().givenName;
if (name) {
app.tell(`You are name ${name}`);
}
else {
// Note: Currently, precise locaton only returns lat/lng coordinates on phones and lat/lng coordinates
// and a geocoded address on voice-activated speakers.
// Coarse location only works on voice-activated speakers.
app.tell('Sorry, I could not figure out where you are.Plaese try again');
}
} else {
app.tell('Sorry, I could not figure out where you are.Please try again');
}
};
const app = new DialogflowApp({request, response});
const actions = new Map();
actions.set('request_permission', requestPermission);
actions.set('user_info', userInfo);
app.handleRequest(actions);
});
The problem is that you are calling app.tell() in your code which is a signal to the Assistant to send the message and then end the conversation.
If you want to send the message and then leave the microphone open for the user to reply, you should use app.ask() instead. It takes the same parameters - the only difference is that it expects the user to reply.
So that portion of your code might look something like
if (name) {
app.ask(`You are name ${name}. What would you like to do now?`);
}
(You should make sure that the prompt for the user is one that they will expect to reply. The review process will reject your Action if you reply and it isn't obvious that the user is supposed to reply to you.)

Im keep on getting an error trying to make a session variable

I am working on a Alexa skill. Currently, I am trying to get the users name and have it as a session variable. But, whenever I go to test it, it gives me this error:
"errorMessage": "RequestId: 98b4fce1-9699-11e7-a585-43e1799b56fe Process
exited before completing request"
Here is the TypeError in the log:
TypeError: Cannot read property 'slots' of undefined
Here is my code:
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.APP_ID = APP_ID;
alexa.registerHandlers(handlers);
alexa.dynamoDBTableName = 'usersName';
alexa.execute();
};
var handlers = {
'LaunchRequest': function () {
this.emit('LaunchIntent');
},
'LaunchIntent': function () {
this.atttributes['myName'] = this.event.request.intent.slots.myName.value
this.emit(':ask', 'Hi! Welcome to Welcoming Alarm! What is your name?');
},
'RemebmberNameIntent': function () {
this.emit(':tell,', 'Hi there!' + this.atttributes['myName']);
},
This is because you are trying to access slots from within a LaunchRequest.
There is no intent mapping for a LaunchRequest, and slots are a part of intents. That means there will be no intent object inside a LaunchRequest JSON payload.
A LaunchRequest is an object that represents that a user made a
request to an Alexa skill, but did not provide a specific intent.
More on Alexa requests types here.
In order to make this work, create another intent where in the users can actually say their name. (I hope you have one) Then store the name to session attributes from there.
'TellMyNameIntent': function () {
this.atttributes['myName'] = this.event.request.intent.slots.myName.value
this.emit(':ask', 'Okay, Got it, I will remember your name.');
},

Resources