javascriptaws-lambdaalexa-skills-kitalexa-slot

Alexa ask a question and get response from external API


I have set up a simple intent

{
  "interactionModel": {
    "languageModel": {
      "invocationName": "viva bank",
      "intents": [
        ...builtin intents...{
          "name": "ask",
          "slots": [{
            "name": "question",
            "type": "AMAZON.SearchQuery"
          }],
          "samples": [
            "when {question}",
            "how to {question}",
            "what {question}"
          ]
        }
      ],
      "types": []
    }
  }
}

But when I ask a question it gives me a generic error response like this:

Me: alexa ask viva bank when is the late fee charged

Alexa: Sorry, I don't know that.

Here is my lambda code, but I don't think it is getting that far.

'use strict';

const Alexa = require('ask-sdk-core');
var https = require('https');
var querystring = require('querystring');


const APP_ID = 'amzn1.ask.skill.1234';

const AskIntentHandler = {
  canHandle(handlerInput) {
    return !!handlerInput.requestEnvelope.request.intent.slots['question'].value;
  },
  handle(handlerInput) {
    var question = handlerInput.requestEnvelope.request.intent.slots['question'].value;
    console.log('mydata:', question);
    var responseString = '';
    const subscription_key = 'XXXX';

    var data = {
      simplequery: question,
      channel: 'Alexa'
    };
    var get_options = {
      headers: {
        'Subscription-Key': subscription_key
      }
    };

    https.get('https://fakeapi.com/' + querystring.stringify(data), get_options, (res) => {
      console.log('statusCode:', res.statusCode);
      console.log('headers:', res.headers);

      res.on('data', (d) => {
        responseString += d;
      });

      res.on('end', function(res) {
        var json_hash = JSON.parse(responseString);
        // grab the first answer returned as text and have Alexa read it
        const speechOutput = json_hash['results'][0]['content']['text'];
        console.log('==> Answering: ', speechOutput);
        // speak the output
        return handlerInput.responseBuilder.speak(speechOutput).getResponse();
      });
    }).on('error', (e) => {
      console.error(e);
      return handlerInput.responseBuilder.speak("I'm sorry I ran into an error").getResponse();
    });
  }

};

exports.handler = (event, context) => {
  const alexa = Alexa.handler(event, context);
  alexa.APP_ID = APP_ID;
  alexa.registerHandlers(AskIntentHandler);
  alexa.execute();
};

I'm really just looking to create a very simple pass through, where a question is asked to Alexa, and then I pipe that to an external API and have Alexa read the response.


Solution

  • You can make the question slot value as required if it is mandatory for the intent and you need to include the intent name. You can use async/await to handle the API.

    const Alexa = require('ask-sdk-core');
    const https = require('https');
    const querystring = require('querystring');
    const { getSlotValue } = Alexa;
    
    const APP_ID = 'amzn1.ask.skill.1234';
    
    const AskIntentHandler = {
      canHandle(handlerInput) {
        return (
          handlerInput.requestEnvelope.request.type === "IntentRequest" &&
          handlerInput.requestEnvelope.request.intent.name === "AskIntent"
        );
      },
      async handle(handlerInput) {
        const question = getSlotValue(handlerInput.requestEnvelope, "question");
        console.log("question ", question);
        const data = await getAnswer(question);
        const speechText = data;
        return handlerInput.responseBuilder
          .speak(speechText)
          .reprompt(speechText)
          .getResponse();
      }
    };
    
    const getAnswer = question => {
      const subscription_key = "XXXX";
      let data = {
        simplequery: question,
        channel: "Alexa"
      };
      let get_options = {
        headers: {
          "Subscription-Key": subscription_key
        }
      };
      return new Promise((resolve, reject) => {
        https
          .get(
            "https://fakeapi.com/" + querystring.stringify(data),
            get_options,
            res => {
              console.log("statusCode:", res.statusCode);
              console.log("headers:", res.headers);
              res.on("data", d => {
                responseString += d;
              });
    
              res.on("end", function(res) {
                var json_hash = JSON.parse(responseString);
                // grab the first answer returned as text and have Alexa read it
                const speechOutput = json_hash["results"][0]["content"]["text"];
                console.log("==> Answering: ", speechOutput);
                resolve(speechOutput);
              });
            }
          )
          .on("error", e => {
            console.error(e);
            resolve("I'm sorry I ran into an error");
          });
      });
    };