0
votes

I keep getting an error when I try to test my basic skill (I'm trying to learn how to create them). Here is the error from the log:

2018-11-21T16:10:55.759Z 06a36441-eda8-11e8-a421-f996bf66c592 Unexpected exception 'TypeError: Cannot read property 'value' of undefined':

TypeError: Cannot read property 'value' of undefined at Object.getSuggestion (/var/task/index.js:31:54) at emitNone (events.js:86:13) at AlexaRequestEmitter.emit (events.js:185:7) at AlexaRequestEmitter.EmitEvent (/var/task/node_modules/alexa-sdk/lib/alexa.js:216:10) at AlexaRequestEmitter.ValidateRequest (/var/task/node_modules/alexa-sdk/lib/alexa.js:181:23) at AlexaRequestEmitter.HandleLambdaEvent (/var/task/node_modules/alexa-sdk/lib/alexa.js:126:25) at AlexaRequestEmitter.value (/var/task/node_modules/alexa-sdk/lib/alexa.js:100:31)

at exports.handler (/var/task/index.js:52:9)

How can I figure this out?

Here is my code:

var Alexa = require('alexa-sdk');


const APP_ID = 'amzn1.ask.skill.ab07421a-0a92-4c2b-b3bd-998e14286xxx';


const skillData = [
    {
        city: "Austin",
        suggestion: "Austin has some of the most outstanding people."
    },
    {
        city: "San Antonio",
        suggestion: "San Antonio has some of the most outstanding people."    
    },
    {
        city: "Dallas",
        suggestion: "The Dallas metroplex is one of the hottest places."
    }
];


var number = 0;
while(number<3){
var handlers = {
  'LaunchRequest': function () {


      this.emit(':ask', 'Tell me the name of the major city you are closest to'
   },
  'Unhandled': function () {
      this.emit(':ask', 'Try saying a city name like Austin, San Antonio, or Dallas'); 
  },
  'getSuggestion': function() {
      var city = this.event.request.intent.slots.City.value;


      this.emit(':ask', getSuggestion(skillData,'city', city.toUpperCase()).suggestion + '. Give me another city and I\'ll hook you up with the best peeps.');
  },
  'AMAZON.HelpIntent': function () {
      this.emit(':ask', "What can I help you with?", "How can I help?");
  },
  'AMAZON.CancelIntent': function () {
      this.emit(':tell', "Okay!");
  },
  'AMAZON.StopIntent': function () {
      this.emit(':tell', "Goodbye!");
  },
};
number = number+1;
}


exports.handler = function(event, context, callback){
  var alexa = Alexa.handler(event, context);
  alexa.appId = APP_ID;
  alexa.registerHandlers(handlers);
  alexa.execute();
};


function getSuggestion(arr, propName, cityName) {
  for (var i=0; i < arr.length; i++) {
    if (arr[i][propName] == cityName) {
      return arr[i];
    }
  }
}

Update

I've made some changes that were suggested below, however, I am still getting an error after the initial response.

"errorMessage": "Cannot read property 'city' of undefined"

Please look at my new code and help me figure this out:

var Alexa = require('alexa-sdk');

const APP_ID = 'amzn1.ask.skill.ab07421a-0a92-4c2b-b3bd-998e14286xxx';

const skillData = [
    {
        city: 'Austin',
        suggestion: "Austin is blahblahblahblahlshflashdfasldfha blah."
    },
    {
        city: 'San Antonio',
        suggestion: "San Antonio has blahblahblahblahlshflashdfasldfha blah."    
    },
    {
        city: 'Dallas',
        suggestion: "The Dallas metroplex is one of the hottest blahblahblahbla blahblahblahblahblahblah."
    }
];

var number = 0;
while(number<3){
var handlers = {
  'LaunchRequest': function () {
      this.emit(':ask', 'Tell me the name of the major city you are closest to!', 'Which major city are you closest to?');
   },
  'Unhandled': function () {
      this.emit(':ask', "Try saying a city name like Austin, San Antonio, or Dallas"); 
  },
  'getSuggestion': function() {
      var city = this.event.request.intent.slots.city.value;

      this.emit(':ask', getSuggestion(skillData,'city', city.toUpperCase()).suggestion + '. Give me another city and I\'ll hook you up with the best peeps.');
  },
  'AMAZON.HelpIntent': function () {
      this.emit(':ask', "What can I help you with?", "How can I help?");
  },
  'AMAZON.CancelIntent': function () {
      this.emit(':tell', "Okay!");
  },
  'AMAZON.StopIntent': function () {
      this.emit(':tell', "Goodbye!");
  },
};

number = number+1;
}
exports.handler = function(event, context, callback){
  var alexa = Alexa.handler(event, context);
  alexa.appId = APP_ID;
  alexa.registerHandlers(handlers);
  alexa.execute();
};

function getSuggestion(arr, propName, cityName) {
  for (var i=0; i < arr.length; i++) {

    var prop = arr[i][propName];
    prop = prop.toUpperCase();

    if (prop == cityName) {
      return arr[i];
    }
  }
}

UPDATE #2

After a lot of trying different things, I've gotten the skill to run with the help of bal simpson!

However, the skill still errors out when the user utters a city name. There must be an error in my Interaction Model, which is below:

   {
        "interactionModel": {
            "languageModel": {
                "invocationName": "city picker",
                "intents": [
                    {
                        "name": "AMAZON.FallbackIntent",
                        "samples": []
                    },
                    {
                        "name": "AMAZON.CancelIntent",
                        "samples": []
                    },
                    {
                        "name": "AMAZON.HelpIntent",
                        "samples": []
                    },
                    {
                        "name": "AMAZON.StopIntent",
                        "samples": [
                            "stop"
                        ]
                    },
                    {
                        "name": "AMAZON.NavigateHomeIntent",
                        "samples": []
                    },
                    {
                        "name": "getSuggestion",
                        "slots": [],
                        "samples": [
                            "san antonio",
                            "dallas",
                            "austin"
                        ]
                    }
                ],
                "types": []
            }
        }
    }

Getting close!!

As a last-ditch effort:

Here is my index.js housed in Lambda. Would anyone mind looking at this?

const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === "LaunchRequest";
  },
  handle(handlerInput) {

    console.log("LaunchRequestHandler");
    let speechText = 'Lets get you into your new home. Tell me the name of the major city you are closest to!';
    let prompt = 'Which major city are you closest to?';

    return handlerInput.responseBuilder
      .speak(speechText)
      .reprompt(prompt)
      .getResponse();
  }
};

const GetSuggestionIntentHandler = {
  canHandle(handlerInput) {
    return (
      handlerInput.requestEnvelope.request.type === "IntentRequest" &&
      handlerInput.requestEnvelope.request.intent.name === "getSuggestion"
    );
  },
  handle(handlerInput) {
    let intent = handlerInput.requestEnvelope.request.intent;
    let city = intent.slot.city.value;

    let suggestion = getSuggestion(skillData,'city', city.toUpperCase()).suggestion;

    return handlerInput.responseBuilder
      .speak(suggestion)
      .reprompt('prompt')
      .getResponse();
  }
};

const HelpIntentHandler = {
  canHandle(handlerInput) {
    return (
      handlerInput.requestEnvelope.request.type === "IntentRequest" &&
      handlerInput.requestEnvelope.request.intent.name === "AMAZON.HelpIntent"
    );
  },
  handle(handlerInput) {
    const speechText = "Try saying a city name like Austin, San Antonio, or Dallas";
    const promptText = "How can I help?";

    return handlerInput.responseBuilder
      .speak(speechText)
      .reprompt(promptText)
      // .withSimpleCard("City Details", speechText)
      .getResponse();
  }
};

const CancelAndStopIntentHandler = {
  canHandle(handlerInput) {
    return (
      handlerInput.requestEnvelope.request.type === "IntentRequest" &&
      (handlerInput.requestEnvelope.request.intent.name ===
        "AMAZON.CancelIntent" ||
        handlerInput.requestEnvelope.request.intent.name ===
        "AMAZON.StopIntent" ||
        handlerInput.requestEnvelope.request.intent.name ===
        "AMAZON.PauseIntent")
    );
  },
  handle(handlerInput) {

    const speechText = `Seeya later!`;

    return (
      handlerInput.responseBuilder
        .speak(speechText)
        .withShouldEndSession(true)
        .getResponse()
    );
  }
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);

    return handlerInput.responseBuilder.getResponse();
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
    console.log(`Error handled: ${error.message}`);

    return handlerInput.responseBuilder
      .speak('Sorry, I can\'t understand the command. Try saying a city name like Austin, San Antonio, or Dallas')
      .reprompt('Try saying a city name like Austin, San Antonio, or Dallas')
      .getResponse();
  },
};

const SystemExceptionHandler = {
  canHandle(handlerInput) {
    return (
      handlerInput.requestEnvelope.request.type ===
      "System.ExceptionEncountered"
    );
  },
  handle(handlerInput) {
    console.log(
      `System exception encountered: ${
      handlerInput.requestEnvelope.request.reason
      }`
    );
  }
};

const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
    LaunchRequestHandler,
    GetSuggestionIntentHandler,
    CancelAndStopIntentHandler,
    HelpIntentHandler,
    SystemExceptionHandler,
    SessionEndedRequestHandler
  )
  .addErrorHandlers(ErrorHandler)
  .lambda();
  
function getSuggestion(arr, propName, cityName) {
  for (var i=0; i < arr.length; i++) {

    var prop = arr[i][propName];
    prop = prop.toUpperCase();

    if (prop == cityName) {
      return arr[i];
    }
  }
}

And here is my Interaction Model from the Developer Portal:

{
    "interactionModel": {
        "languageModel": {
            "invocationName": "city picker",
            "intents": [
                {
                    "name": "AMAZON.FallbackIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.HelpIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.StopIntent",
                    "samples": [
                        "stop"
                    ]
                },
                {
                    "name": "AMAZON.NavigateHomeIntent",
                    "samples": []
                },
                {
                    "name": "getSuggestion",
                    "slots": [
                        {
                            "name": "city",
                            "type": "CITY_NAMES"
                        }
                    ],
                    "samples": [
                        "{city}"
                    ]
                }
            ],
            "types": [
                {
                    "name": "CITY_NAMES",
                    "values": [
                        {
                            "name": {
                                "value": "dallas"
                            }
                        },
                        {
                            "name": {
                                "value": "san antonio"
                            }
                        },
                        {
                            "name": {
                                "value": "austin"
                            }
                        }
                    ]
                }
            ]
        }
    }
}
1
post your response of getSuggestion IntentShreya Prajapati
Please post request to or response of your getSuggestion Intent.Ussama Zubair
When making a change to a question that already has answers, it is worth getting into the habit of asking yourself whether the change would invalidate those answer(s). In this case the change was substantial, so it is better to add an update, so that new readers of the question do not start off with reading an "update" at the very start. (Some changes are so drastic that they are better as a new question, for much the same reasons). The golden rule is ensuring answers are still relevant for the questions above them.halfer
You are correct! It was totally my bad. Thanks for cleaning it up!Michael Coleman

1 Answers

0
votes

ok. alexa-sdk has been deprecated link. To get the new SDK, do this.

1 - Create a new function in Lambda.

2 - Choose AWS Serverless Application Repository. alexa-skills-kit-nodejs-factskill

3 - Choose alexa-skills-kit-nodejs-factskill.

4 - Click on deploy. Once deployed, click on functions and you should see the new function you just created with a name like aws-serverless-repository-alexaskillskitnodejsfact-NR8HPILH8WNI. enter image description here

5 - Delete the code and replace the code with this. enter image description here

const Alexa = require('ask-sdk');    
const skillData = [
            {
                city: 'Austin',
                suggestion: "Austin is blahblahblahblahlshflashdfasldfha blah."
            },
            {
                city: 'San Antonio',
                suggestion: "San Antonio has blahblahblahblahlshflashdfasldfha blah."    
            },
            {
                city: 'Dallas',
                suggestion: "The Dallas metroplex is one of the hottest blahblahblahbla blahblahblahblahblahblah."
            }
        ];

const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === "LaunchRequest";
  },
  handle(handlerInput) {

    console.log("LaunchRequestHandler");
    let speechText = 'Tell me the name of the major city you are closest to!';
    let prompt = 'Which major city are you closest to?';

    return handlerInput.responseBuilder
      .speak(speechText)
      .reprompt(prompt)
      .getResponse();
  }
};

const GetSuggestionIntentHandler = {
  canHandle(handlerInput) {
    return (
      handlerInput.requestEnvelope.request.type === "IntentRequest" &&
      handlerInput.requestEnvelope.request.intent.name === "getSuggestion"
    );
  },
  handle(handlerInput) {
    let intent = handlerInput.requestEnvelope.request.intent;
    let city = intent.slots.city.value;

    let suggestion = getSuggestion(skillData,'city', city.toUpperCase()).suggestion;

    return handlerInput.responseBuilder
      .speak(suggestion)
      .reprompt('prompt')
      .getResponse();
  }
};

const HelpIntentHandler = {
  canHandle(handlerInput) {
    return (
      handlerInput.requestEnvelope.request.type === "IntentRequest" &&
      handlerInput.requestEnvelope.request.intent.name === "AMAZON.HelpIntent"
    );
  },
  handle(handlerInput) {
    const speechText = "Try saying a city name like Austin, San Antonio, or Dallas";
    const promptText = "How can I help?";

    return handlerInput.responseBuilder
      .speak(speechText)
      .reprompt(promptText)
      // .withSimpleCard("City Details", speechText)
      .getResponse();
  }
};

const CancelAndStopIntentHandler = {
  canHandle(handlerInput) {
    return (
      handlerInput.requestEnvelope.request.type === "IntentRequest" &&
      (handlerInput.requestEnvelope.request.intent.name ===
        "AMAZON.CancelIntent" ||
        handlerInput.requestEnvelope.request.intent.name ===
        "AMAZON.StopIntent" ||
        handlerInput.requestEnvelope.request.intent.name ===
        "AMAZON.PauseIntent")
    );
  },
  handle(handlerInput) {

    const speechText = `Goodbye`;

    return (
      handlerInput.responseBuilder
        .speak(speechText)
        .withShouldEndSession(true)
        .getResponse()
    );
  }
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);

    return handlerInput.responseBuilder.getResponse();
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
    console.log(`Error handled: ${error.message}`);

    return handlerInput.responseBuilder
      .speak('Sorry, I can\'t understand the command. Try saying a city name like Austin, San Antonio, or Dallas')
      .reprompt('Try saying a city name like Austin, San Antonio, or Dallas')
      .getResponse();
  },
};

const SystemExceptionHandler = {
  canHandle(handlerInput) {
    return (
      handlerInput.requestEnvelope.request.type ===
      "System.ExceptionEncountered"
    );
  },
  handle(handlerInput) {
    console.log(
      `System exception encountered: ${
      handlerInput.requestEnvelope.request.reason
      }`
    );
  }
};

const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
    LaunchRequestHandler,
    GetSuggestionIntentHandler,
    CancelAndStopIntentHandler,
    HelpIntentHandler,
    SystemExceptionHandler,
    SessionEndedRequestHandler
  )
  .addErrorHandlers(ErrorHandler)
  .lambda();

function getSuggestion(arr, propName, cityName) {
  for (var i=0; i < arr.length; i++) {

    var prop = arr[i][propName];
    prop = prop.toUpperCase();

    if (prop == cityName) {
      return arr[i];
    }
  }
}

6 - Go to developer.amazon.com and change your Alexa Skill endpoint to the new lambda ARN. enter image description here

To add a slot type:

enter image description here

Specify slot in your sample phrases like this:

enter image description here

Change your slot name to city:

enter image description here

So instead of musicStations it will be city. Make sure you have entered the three values in your slot values like this:

Add your custom slot values to CITY_NAMES: Add slot values

If you have done it right, your interaction model should be something like this:

                "name": "getSuggestion",
                "slots": [
                    {
                        "name": "city",
                        "type": "CITY_NAMES"
                    }
                ],
                "samples": [
                    "city name is {city}",
                    "{city}"
                ]

Testing Lambda code

In the drop down menu, choose 'configure test events'. enter image description here

Create new test event with JSON from your developer test portal which should look like this.

{
"version": "1.0",
"session": {
    "new": true,
    "sessionId": "amzn1.echo-api.session.XXXXXX",
    "application": {
        "applicationId": "amzn1.ask.skill.XXXXXX"
    },
    "user": {
        "userId": "amzn1.ask.account.XXXXXX"
    }
},
"context": {
    "AudioPlayer": {
        "playerActivity": "IDLE"
    },
    "System": {
        "application": {
            "applicationId": "amzn1.ask.skill.XXXXXX"
        },
        "user": {
            "userId": "amzn1.ask.account.XXXXXX"
        },
        "device": {
            "deviceId": "amzn1.ask.device.XXXXXX",
            "supportedInterfaces": {
                "AudioPlayer": {}
            }
        },
        "apiEndpoint": "https://api.eu.amazonalexa.com",
        "apiAccessToken": "ACCESS_TOKEN"
    },
},
"request": {
    "type": "IntentRequest",
    "requestId": "amzn1.echo-api.request.XXXX",
    "timestamp": "2018-12-03T20:28:29Z",
    "locale": "en-IN",
    "intent": {
        "name": "PlayRadioIntent",
        "confirmationStatus": "NONE",
        "slots": {
            "musicStation": {
                "name": "musicStation",
                "value": "classic rock",
                "resolutions": {
                    "resolutionsPerAuthority": [
                        {
                            "authority": "amzn1.er-authority.XXXX.RadioStations",
                            "status": {
                                "code": "ER_SUCCESS_MATCH"
                            },
                            "values": [
                                {
                                    "value": {
                                        "name": "Classic Rock",
                                        "id": "b8a5bd97a8a02691f9f81dcfb12184dd"
                                    }
                                }
                            ]
                        }
                    ]
                },
                "confirmationStatus": "NONE",
                "source": "USER"
            }
        }
    }
}

Click on test button

Check Logs

Does the test result look like this? To see the logs, click on logs. It might have additional error details.

enter image description here