Amazon Alexa custom skill issue in ios app - aws-lambda

I'm trying to implement custom skills using Amazon Alexa Skill Kit (ASK). I have configured Amazon Alexa Voice Service (AVS) and ASK project, Then created lambda function also.
I have 2 custom intents.
{
"intents": [
{
"intent": "fIntent"
},
{
"intent": "bIntent"
},
{
"intent": "AMAZON.HelpIntent"
},
{
"intent": "AMAZON.StopIntent"
}
]
}
I have a Utterances like below
fIntent get info
fIntent get status
fIntent find info
fIntent info
Here is my index.js code
'use strict';
var Alexa = require('alexa-sdk');
var SKILL_NAME = 'ScottSkill';
var APP_ID = '';
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.registerHandlers(handlers);
alexa.execute();
};
var handlers = {
'LaunchRequest': function () {
this.emit(':tellWithCard','Hi, Im your personal car assistant. How can i help you');
},
'fIntent':function (){
this.emit(':tell','Fuel level is 100');
},
'AMAZON.HelpIntent': function () {
var readFuel = 'Iam Personal car assistant, I can assist you with car info';
var speeachOutput = readFuel;
var reprompt = 'How can I help you';
this.emit(':ask', speeachOutput, reprompt);
},
'AMAZON.StopIntent': function () {
this.emit(':tell', 'OKay, Goodbye');
},
'AMAZON.CancelIntent': function () {
this.emit(':tell', 'OKay, Goodbye');
}
};
Now the problem is when I'm saying skill name I'm getting LaunchRequest message.
But when I'm trying to get custom intent value by saying fIntent info
I'm not getting the message what I configured in the index.js file.
if I say info its should tell Fuel level is 100.
But I'm Not getting that info. Can someone help me?

Don't develop the two components at one.
First develop you skill and test it from an Echo device
Once you are done, develop your Amazon Voice Service app

Related

I want to implement auto complete search for bot from Mongo Database

I want to implement auto complete search for bot..for example bot should get responses as auto complete options from Mongo Database. Can any one suggest how to do this without Azure Search?
I have tried implementing like this but in my case i want to get the tags from Database.
May i know what are the available options to do this?
When you send a message from the bot, you can add the autocomplete options to the activity's channel data. Then in Web Chat, you can use a custom store middleware to retrieve the options and update the JQuery Auto complete widget.
Bot Framework SDK v4 (C#)
var reply = turnContext.Activity.CreateReply();
reply.Text = "Hello, World!";
reply.ChannelData = JObject.FromObject( new {
autocompleteOptions = new List<string>() { "Option 1", "Option 2", "Option 3" }
});
await turnContext.SendActivityAsync(reply);
Web Chat v4
const store = createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
const { payload: { activity: { channelData: { autcompleteOptions } = {}}}} = action;
if (autcompleteOptions) {
// Update JQuery Autcomplete Widget with `autocompleteOptions`
}
}
return next(action);
}
);
For more details take a look at the Incoming Event Web Chat Sample and this Stack Overflow answer.
Hope this helps!

No response from any other intent request except Launch request

I'm new to Alexa skill creation. I tried to create a skill for my term project in college and am trying to finish it. I've finally got the Lambda and interaction model communicating and am now testing the skill in the tool. I'm finding 2 issues.
1) The invocation name is sending me the unhandled response back, and
2) None of the intents outside of the launch intent are sending any response back. The Lambda code is as below:
"use strict";
var Alexa = require("alexa-sdk");
var handlers = {
"Invocation": function LaunchIntent() {
this.response.speak("Hello, Welcome to Family Table. where would you like to make a reservation today?");
this.emit(':ask', ':responseReady');
context.succeed(handlers());
},
"LaunchIntent": function LaunchIntent() {
this.response.speak("Hello, Welcome to Family Table. where would you like to make a reservation today?");
this.emit(':responseReady');
context.succeed(handlers());
},
"FoodIntent": function FoodIntent() {
this.response.speak("What kind of food would you like today?");
this.emit(':responseReady');
context.succeed(handlers());
},
"cityintent": function cityintent() {
this.response.speak("Where would you like to eat?");
this.emit(':responseReady');
context.succeed(handlers());
},
"restaurantintent": function restaurantintent() {
this.response.speak("Would you like to eat at {RestaurantName}?");
this.emit(':responseReady');
context.succeed(handlers());
},
"cofirmintent": function cofirmintent() {
this.response.speak("You want to eat at {RestaurantName} correct?");
this.emit(':responseReady');
context.succeed(handlers());
},
"Amazon.FallbackIntent": function AmazonFallbackIntent() {
this.response.speak("Sorry I can't do that right now.");
this.emit(':responseReady');
context.succeed(handlers());
},
"Amazon.CancelIntent": function AmazonCancelIntent() {
this.response.speak("Cancelling");
this.emit(':responseReady');
context.succeed(handlers());
},
"Amazon.HelpIntent": function AmazonHelpIntent() {
this.response.speak("I don't know how to help you with that.");
this.emit(':responseReady');
context.succeed(handlers());
},
"Amazon.StopIntent": function AmazonStopIntent() {
this.response.speak("Alright, please come back soon.");
this.emit(':responseReady');
context.succeed(handlers());
},
"Amazon.YesIntent": function AmazonYesIntent() {
this.response.speak("Thank you for using Family Table. Your reservation has been made. Enjoy your meal.");
this.emit(':responseReady');
context.succeed(handlers());
},
'Unhandled': function () {
this.emit(':ask', 'I don\'t get it!', 'I don\'t get it!');
context.succeed(handlers());
},
};
exports.handler = function (event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.registerHandlers(handlers);
alexa.execute();
};
What am I missing? Thanks for your help.
You have a couple of things to be corrected.
LaunchRequest:
It is LaunchRequest and not LaunchIntent. When you invoke a skill, this is the handler which will be called.
context.succeed:
You don't need context.succeed(handlers());, you can remove it from all the intent handlers.
shouldEndSession:
If this parameter is not set or if it is set to true, Alexa will end the current session and your skill will be closed. No subsequent user speech will reach your backend code unless you invoke it again.
The good thing is that, you don't have to set this parameter manually and the SDK will take care of it as follows:
:ask: will 'ask' the user and wait for a response by keeping the session alive. If you set a re-prompt, it will be triggered after 8 seconds if there is no interaction from user.
ask: will automatically include "shouldEndSession":"false" in response.
Ex:
'AbcIntent': function () {
var speech="Your speech here";
var reprompt="Your re-prompt here";
this.emit(':ask', speech,reprompt);
}
:tell will just say the response and end the session. Use this when you don't expect any response from user. Ex: use it for AMAZON.StopIntent.
speak() and listen(): if there is no listen(), speak() will be treated as :tell, it just tell the response and set "shouldEndSession":"true" in response which will end the session. But if there is a listen(), the SDK will set "shouldEndSession":"false" in response and will keep the session alive.
Make your changes like this:
"LaunchRequest": function () {
this.response
.speak("Hello, Welcome to Family Table. where would you like to make a reservation today?")
.listen("where would you like to make a reservation today?");
this.emit(':responseReady');
}
Or use :ask
"FoodIntent": function () {
const speech = "What kind of food would you like today?";
const reprompt = "What kind of food would you like today?";
this.emit(':ask',speech,reprompt);
}

AWS lambda function failing in Amazon Connect

I have written an AWS lambda function in node.js to send an email, which is invoked in an Amazon Connect contact flow. In the error branch it plays a prompt saying "lambda function failed." I verified the IAM role has permission to send email with SES, the sender/receiver emails are verified in SES, and also the lambda function has permissions for Amazon Connect.
The email does actually get sent out, but oddly I still hear the prompt "lambda function failed." Here is the code:
"use strict";
const aws = require('aws-sdk');
const sender = "Sender Name <sender#email.com>";
const recipient = "recipient#email.com";
const subject = "ALERT: no agents are logged in";
const body_text = "There are no agents logged in";
const body_html =
`<html>
<head></head>
<body>
<h1>ALERT</h1>
<p>Ther are no agents logged in to take calls in the queue.</p>
</body>
</html>`;
const charset = "UTF-8";
let params = {
Source: sender,
Destination: {
ToAddresses: [
recipient
],
},
Message: {
Subject: {
Data: subject,
Charset: charset
},
Body: {
Text: {
Data: body_text,
Charset: charset
},
Html: {
Data: body_html,
Charset: charset
}
}
},
};
const ses = new aws.SES({apiVersion: '2010-12-01'});
exports.handler = function(event, context, callback) {
ses.sendEmail(params, function(err, data) {
if(err) {
console.log("fail");
callback(err, err.message);
}
else {
console.log("success");
callback(null);
}
});
};
I checked the cloudwatch logs and don't see any error:
00:17:24
START RequestId: 17f1e239-990e-11e8-96bb-a1980f44db91 Version: $LATEST
00:17:24
2018-08-06T00:17:24.723Z 17f1e239-990e-11e8-96bb-a1980f44db91 success
00:17:24
END RequestId: 17f1e239-990e-11e8-96bb-a1980f44db91
00:17:24
REPORT RequestId: 17f1e239-990e-11e8-96bb-a1980f44db91 Duration: 226.51 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 32 MB
How do I troubleshoot this?
EDIT:
I enabled contact flow logs. In CloudWatch I noticed this:
{
"Parameters": { "FunctionArn": "arn:aws:lambda:us-west-2:769182588423:function:noAgentEmail", "TimeLimit": "8000" },
"Timestamp": "2018-08-06T06:36:31.786Z",
"ContactFlowModuleType": "InvokeExternalResource",
"Results": "The Lambda Function Returned An Error.",
"ExternalResults": { "forceClose": "false" },
"ContactId": "458027b0-d895-439e-bc06-114500dce64a",
"ContactFlowId": "arn:aws:connect:us-west-2:769182588423:instance/1e2ddedd-8335-42fe-89de-1e986fc016ef/contact-flow/2329af39-682c-4dc8-b3a2-5e7fe64de5d2"
}
What's confusing is it indicates the lambda function returned something:
"ExternalResults": { "forceClose": "false" }
But this is clearly not the case given the code. What's going on?
There's a couple of things to ensure your working Lambda function can be used for Connect.
As mentioned in the above answer, the return value should be a flat JSON object. As the guide says:
Nested and complex objects are not supported.
So, it should look something like this when you execute the lambda directly:
Response:
{
"statusPop": "success",
"id": "1",
"name": "me",
}
The property names and values need to be
alphanumeric, dash, and underscore characters.
Oh, and here's what tripped me up:
Amazon Connect sends paramters as part of a hierarchical structure, so any parameters you're expecting need to be referenced as
event['Details']['Parameters']['statusPop'];
instead of
event['statusPop'];
And don't forget to add permissions using:
aws lambda add-permission --function-name function:my-lambda-function --statement-id 1 \
--principal connect.amazonaws.com --action lambda:InvokeFunction --source-account 123456789012 \
--source-arn arn:aws:connect:us-east-1:123456789012:instance/def1a4fc-ac9d-11e6-b582-06a0be38cccf
More info and in depth details of what I mentioned here: https://docs.aws.amazon.com/connect/latest/adminguide/connect-lambda-functions.html
Your lambda needs to return a flat filed JSON object. It looks like on success your lambda callbacks with null.
Update your exports to this:
exports.handler = function(event, context, callback) {
ses.sendEmail(params, function(err, data) {
if(err) {
console.log("fail");
//callback(err, err.message);
callback(null, {"status":"error"});
}
else {
console.log("success");
callback(null, {"status":"success"});
}
});
});
More information on lambda/connect requirements here: https://docs.aws.amazon.com/connect/latest/adminguide/connect-lambda-functions.html
Note:
The output returned from the function must be a flat object of key/value pairs, with values that include only alphanumeric, dash, and underscore characters. Nested and complex objects are not supported. The size of the returned data must be less than 32 Kb of UTF-8 data.
you must return a valid JSON object such as below example
export const handler = async(event) => {
console.log("event" + JSON.stringify(event));
let amount = event['Details']['Parameters']['amount'];
console.log("amount:" + amount);
let resultMap = {
"amountValid": "valid"
};
console.log("resultMap" + JSON.stringify(resultMap));
return resultMap;
};

Amazon Connect - Invoke Lambda

get_customer_input
ReasonForCalling_Play_prompt
Lambda function returns properly when testing Lex chatbot.
Invoking the function through Amazon Connect results in an Error.
Any ideas on how to save the return from Lambda in Connect with proper formatting? * Updated to add updated lambda code and Lex configuration image.
Lambda Code:
console.log('Loading event');
var AWS = require('aws-sdk');
var db = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
exports.handler = (event, context, callback) => {
var ssn = event.currentIntent.slots.userSSN;
var mySecret = event.currentIntent.slots.secretWord;
var params = {
TableName: 'users',
Key: {
"fourDigSSN": {
"N": ssn
},
"mySecretWord": {
"S": mySecret
}
},
AttributesToGet: ["accountBalance"]
};
db.getItem(params, function(err, data) {
if (err) {
console.log(" It didn't work and here is the error " + err); // an error occurred
}
else
callback(null, {
"sessionAttributes":{
"accountBal": data.Item.accountBalance.N
},
"dialogAction": {
"type": "ConfirmIntent",
"message": {
"contentType": "PlainText",
"content": "Your account has been verified. Your account balance is " + data.Item.accountBalance.N + "."
},
"intentName": "ReasonForCalling",
"slots": {
"userSSN": ssn,
"secretWord": mySecret
}
}
});
// var accountBal = data.Item.accountBalance.N;
// //console.log("GetDBItem succeeded:", JSON.stringify(data, null, 2));
// callback(null, {accountBalance : accountBal});
});
};
[lex_configuration][1]
[connect_contact_flow][2]
[connect_lambda_Details][3]
Your Amazon Connect contact flow appears to be referencing $.External.(something) after matching the "ReasonForCalling" intent. $.External is only used if Amazon Connect is calling upon a Lambda function directly. In your case, Amazon Connect is interacting with Lex. Lex is calling Lambda, so any response you get back to Amazon Connect will be coming from Lex, not Lambda. In order for Amazon Connect to read back something from Lex, you will need to use one of the following in your Play prompt step:
$.Lex.IntentName
$.Lex.Slots.(slotName)
$.Lex.SessionAttributes.(sessionAttributeKey)
Option1: You can configure Lex to insert the Account Balance into a slot called "AccountBal", then "return parameters to client". From there, Amazon Connect can access that value as $.Lex.Slots.AccountBal.
Option2: If you want Amazon Connect to interact directly to Lambda, you can use Lex to collect userSSN and secretWord and then build a separate Lambda function that Amazon Connect calls directly using an "Invoke AWS Lambda Function" step to perform the database lookup. With this method, you would be receiving a response directly from Lambda and can reference it as $.External.accountBalance.
EDITED ----------
Your callback has DialogAction type set as "ConfirmIntent" so Lex is most likely still expecting some user response. I doubt Amazon Connect is even getting anything back from Lex. Try updating the callback to something like the following so Lex will finish fulfillment and return to Amazon Connect:
callback(null, {
"sessionAttributes":{
"accountBal": data.Item.accountBalance.N
},
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled",
"message": {
"contentType": "PlainText",
"content": "Your account has been verified. Your account balance is " + data.Item.accountBalance.N + "."
}
}
});

Integrating Microsoft Bot Framework with api.ai

I am working on integrating Microsoft Bot Framework with api.ai. I followed the tutorials here. On coding, I also deployed the bot to Heroku using Heroku command line.
I have used the code as below:
(I have changed my APP ID and Password):
var builder = require('botbuilder');
var restify = require('restify');
var apiairecognizer = require('api-ai-recognizer');
var request = require('request');
//=========================================================
// Bot Setup
//=========================================================
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log('%s listening to %s', server.name, server.url);
});
// Create chat bot
var connector = new builder.ChatConnector({
appId: '4c8f3u2b-c56n-4117-bc16-ec31eeb5d25c',
appPassword: '4CBNO8vBGtdcGh9PoiVYottY'
});
var connector = new builder.ConsoleConnector().listen();
var bot = new builder.UniversalBot(connector);
var recognizer = new apiairecognizer("84c78b2c15684c7380c6a74c8fbb343f");
var intents = new builder.IntentDialog({
recognizers: [recognizer]
});
bot.dialog('/',intents);
intents.matches('Flow_1',function(session, args){
var fulfillment = builder.EntityRecognizer.findEntity(args.entities, 'fulfillment');
if (fulfillment){
var speech = fulfillment.entity;
session.send(speech);
}else{
session.send('Sorry...not sure how to respond to that');
}
});
intents.onDefault(function(session){
session.send("Sorry...can you please rephrase?");
});`
My Package.json
{
"name": "nodebot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"api-ai-recognizer": "^1.0.1",
"botbuilder": "^3.8.4",
"restify": "^4.3.0"
}
}
My Procfile
web: node app.js
But after successfully deploying to Heroku, I am seeing the following error:
{"code":"ResourceNotFound","message":"/api/messages does not exist"}
Even when I tried testing the bot from Bot Framework Emulator, I am seeing the below error:
Request to 'http://localhost:3978/api/messages' failed: [404] Not Found
I have following questions:
1. How to successfully integrate api.ai with Framework?
2. How to host it Heroku?
It seems that the api/messages route is not defined. You are missing this line server.post('/api/messages', connector.listen());.
Also, you are defining the connector twice, the ChatConnector and the ConsoleConnector. Make sure to delete the code related to the ConsoleConnector.

Resources