5
votes

I am building a custom Alexa skill and want to make REST API calls. Currently, I am able to make GET request to fetch data from my web service which is then used by Alexa. However, I have the following requirements and I am not sure how to go about developing this.

  1. Invoke the Skill (Complete)
  2. User will invoke "Get List of Topics" intent, Alexa makes the GET REST API call and provides the "list of topics"(Complete)
  3. Make Alexa prompt the user to select a topic from the list (Pending)
  4. Receive the response made by the user in the lambda function and use the response to make a POST/PUT call. (Pending)
  5. Reprompt the user if the selected topic is invalid (Pending).

How do I implement 3, 4, and 5? I am currently using Python 3.6 to write the lambda function at AWS developer console. Are there any Amazon Alexa APIs guide for Python 3.6.

How do I do this in Java which is my preferred way?

I followed the instructions here to develop what I currently have: https://github.com/simonprickett/alexabart

Is there any detailed documentation available on how to write Alexa specific lambda function and its associated API guide for Python3 or Java.

Thanks

2
you wish to know the code for Python or Java?Nikhil Wagh
@NikhilWagh I would like to know the functions/API's to use...or how to structure the code for Alexa....which I believe will make the code. Currently Python, however, I am also looking into developing the Alexa Skill in Java too, but not sure how to go about it. Like what classes, functions and APIs to implement,samdset
I had my code in Python, and I did something very similar. Will it be okay if I give you my code and tell you what you should do?Nikhil Wagh
@NikhilWagh Sure, I can make do with the code for now and learn from it. Thanks!samdset

2 Answers

1
votes

If you have a lot of questions and you want each of them answered, you can use sessionAttributes variable. The session variable can retain it's value through out the course of the session. You can make a dictionary to be saved in your sessionAttributes(It has to be a dictionary).

You can save something like this in your session variable.

sessionAttributes: {
    "AllQuestions" : ["string", "string"],
    "LastQuestionIndex" : integer
}

I'm assuming you're able to get the list of questions (using a GET request).

Step 1 : Make a slot

Answer would be a slot which is going to store your answer.

Step 2 : Get your questions ready

When your intent has just started and you don't have anything in your sessionAttributes (use a simple if-else) you'll have to make the GET request and gather all of your questions (maybe in a list or something). You make your GET request and store all the questions in your sessionAttributes['AllQuestions']. And set LastQuestionIndex = -1.

Now the tricky part comes in. (I'm also assuming you're able to use Dialog.ElicitSlot Directive).

Step 3 : Ask questions one-by-one.

Now you have a list of all the questions and you also have the index of last question that was asked. And now you just have to increment the index, get the Next Question, and use Dialog.ElicitSlot Directive to ask this new question. And update the LastQuestionIndex in your sessionAttributes.

Step 4 : Getting the answer

Before proceeding to next question, you'll also have to check if the slot Answer has any value or not? If it does have a value (it is not "None"), then you can use the LastQuestionIndex variable and store the answer for that particular question.

If you're looking for code, here you go:

# Line 1 - 22 should be in your intent function
sessionAttributes =  dict()
if 'sessionAttributes' in event['session']: 
    sessionAttributes = event['session']['sessionAttributes']

if not sessionAttributes.has_key('AllQuestions') : 
    # Make the GET REQUEST
    Questions = ["all", "of", "your", "Questions", "stored", "in", "a", "list"]
    sessionAttributes['AllQuestions'] = Questions
    sessionAttributes['LastQuestionIndex'] = -1


Answer = getSlotValue('Answer')
if Answer != None:
    # AllAnswers is a dictionary which has key as the question number and value is the answer
    # AllAnswers = {
    #   0 : "Answer to your first question",
    #   1 : "Answer to your second question"
    # }
    AllAnswers[sessionAttributes['LastQuestionIndex']] = Answer

return ansNextQuestion(sessionAttributes)


def askNextQuestion(sessionAttributes) :
    Last = sessionAttributes['LastQuestionIndex']
    sessionAttributes['LastQuestionIndex'] = Last + 1

    if Last < len(sessionAttributes['AllQuestions']): 
        outputSpeech = "Your next question is " + sessionAttributes['AllQuestions'][Last + 1]
        return {
            "version": "1.0",
            "sessionAttributes": sessionAttributes,
            "response": {
                "outputSpeech": {
                    "type": "PlainText",
                    "text": outputSpeech
                },
                "shouldEndSession": False,
                "directives": [
                    {
                        "type": "Dialog.ElicitSlot",
                        "slotToElicit": "Question",
                        "updatedIntent": {
                            "name": "GetMovieDetails",
                            "confirmationStatus": "NONE",
                            "slots": {
                                "Answer": {
                                    "name": "Answer",
                                    "value": "NONE" # You can change the value of Answer to get new answer, this is allowed.
                                }
                            }
                        }
                    }
                ]
            }
        }
    else : 
        # You are out of questions, now proceed to what you should do after getting all the answers.
1
votes

You can use slots and Dialog.ElicitSlot directives, to get the information from the user. More specifically, you'll need a slot for which you will return Dialog.ElicitSlot response, and in the speechOutput of the response you'll provide the list of options, and when user provides the information, it'll be collected in the slot. see this : https://developer.amazon.com/docs/custom-skills/dialog-interface-reference.html#elicitslot

If you're looking for code, this is what I did in Python 2.7

def dialog_elicit_slot(output, slotToElicit, city_name, movie_name, attributes, multiplex = None, confirmationStatus = "CONFIRMED"):
    return {
        "version": "1.0",
        "sessionAttributes": attributes,
        "response": {
            "outputSpeech": {
                "type": "PlainText",
                "text": output
            },
            "shouldEndSession": False,
            "directives": [
                {
                    "type": "Dialog.ElicitSlot",
                    "slotToElicit": slotToElicit,
                    "updatedIntent": {
                        "name": "GetMovieDetails",
                        "confirmationStatus": confirmationStatus,
                        "slots": {
                            "CITY": {
                                "name": "CITY",
                                "confirmationStatus": "CONFIRMED" if city_name != None else "NONE",
                                "value": city_name
                            },
                            "NAME": {
                                "name": "NAME",
                                "confirmationStatus": "CONFIRMED" if movie_name != None else "NONE",
                                "value": movie_name
                            },
                            "MULTIPLEX": {
                                "name": "MULTIPLEX",
                                "confirmationStatus": "CONFIRMED" if multiplex != None else "NONE",
                                "value" : multiplex
                            }
                        }
                    }
                }
            ]
        }
    }

Here, you can see I had 3 slots, out of which 2 (CITY and NAME) were made required in the skill builder.

This is what my skill does. It asks for the city and name of the movie in the beginning (invokation of the skill), then my skill would make a GET request to remote site to get the list of mulitplexes. And when I had the list of multiplexes which show that movie(which the user told and is collected in NAME slot) in his particular city, I give them the list of Multiplexes (which is just a string, output variable in the above code). And Dialog.ElicitSlot directive collects the slot information for the slotToElicit slot(which in this case is MULTIPLEX).

If this looks overwhelming, you can just contact me directly.