AWS GoT Hack: Target Intent(s)

To recap, I'm working on a 48-hour hack to help learn about AWS.  My goal is to:

Create a "Game of Thrones" Alexa Skill that allows the user to ask if a character is alive or dead, and responds with an accurate answer.

In the previous post, we got the very basic Alexa skill working. All it could do is tell me where it got its data. Now, let's add the intent that is the target of this first version of the skill: Is a character alive or dead?

Here is the target intent expressed as a question and some answers:

Q: Is {{name}} [[alive|dead]]?
A: [[Yes|No]], {{name}} is alive.
A: [[Yes|No]], {{name}} died on {{DeathDate}} during episode {{DeathEp}}
A: I don't know who {{name}} is.  Can you please ask again?

Alexa Skill

The first thing to do is create sample utterances for the question.  But I would prefer not to keep updating text boxes in the UI directly, as I have no revision history.  Therefore, I'm going to move the existing utterances to a file in the repository. I'll do the same with the existing Intent Schema and commit the original versions.  I'll still have to copy the text from the file into the text boxes, but at least I have revision history.

Sample Utterances

The sample utterances are pretty straightforward for this one:

AliveDeadIntent Is {CharacterName} alive
AliveDeadIntent Is {CharacterName} dead

We do have to add an argument, or slot, called "CharacterName", as that needs to be passed to the Lambda function. Now that I think about it, we need to know which question was asked, also. So we actually have two target intents:

AliveIntent Is {CharacterName} alive
DeadIntent Is {CharacterName} dead

Intent Schema

Updating the Intent Schema is a bit trickier, as we have to allow for the slot. For a first pass, let's see if Amazon's pre-defined "AMAZON.US_FIRST_NAME" slot-type will work for us. I'm thinking it might have trouble with "Tyrion"...

    {
      "intent": "AliveIntent",
      "slots": [
        {
          "name": "CharacterName",
          "type": "AMAZON.US_FIRST_NAME"
        },
      ]
    },

There is another identical block for "DeadIntent".

So now I do the manual copy of the files into the form in the Alexa Developer Console. And, shoot, the Intent Schema parser doesn't like trailing commas. I like them because they allow extra array elements to be added to the end of the array, and only the lines of the new element show up in the diff.

Testing

I haven't written any code yet, but I can see how the intent will map to the Lambda request:

Utterance: Is Tyrion Alive

Lambda Request:

{
  "session": {
    "sessionId": "SessionId.5e9a9713-fcb7-4f81-895d-eb305978f423",
    "application": {
      "applicationId": "amzn1.ask.skill.74990661-2d20-4fd3-abba-f2274f835629"
    },
    "attributes": {},
    "user": {
      "userId": "amzn1.ask.account.AHDS6B5HSMEUYNLJPHSR4MQZJ3BTFJM5OZEXOOTC2LI42RBSPH4Y6HPY4FTSGGJL5HY45KWCCHOXVMVQVXCDHF2RYVRCLJV75PVOVY2YWJCAUOSMOLYLQ76Z3LJBK4XOR5K6LUWWCVBRU6TT4NSGW3IXANXNFJX2UVGUZ7MXFQ5P7SYJIMADUXGA3TGLEGR4XYYV44TZQA72JUI"
    },
    "new": true
  },
  "request": {
    "type": "IntentRequest",
    "requestId": "EdwRequestId.f49fea49-3671-45f7-93e7-66f10b3825a6",
    "locale": "en-US",
    "timestamp": "2016-09-21T23:34:46Z",
    "intent": {
      "name": "AliveIntent",
      "slots": {
        "CharacterName": {
          "name": "CharacterName",
          "value": "Tyrion"
        }
      }
    }
  },
  "version": "1.0"
}

There's lots of stuff in there, but the "intent" block tells me that we correctly mapped to "AliveIntent", and the CharacterName is actually "Tyrion"!

Woohoo!

Let's add the code!

Lambda Code

My changes should be again limited to index.js:

  • Add the new intents to intentHandlers().  Because they are really similar, I'm going to have both of them call a common function "handleAliveDeadIntent()".
  • Create that common function and lift some helper functions from another Amazon sample.
    • buildSpeechletResponse()
    • isCharacterNameSlotValid()

Time to zip, upload and test.

Testing

Let's ask about Tyrion again. And we seem to have failed. CloudWatch? Ah, I didn't port all the code I needed from that sample skill.

Let's try again... And one more time...

OK, now we're actually executing.  But instead of "Tyrion", I got "[object Object]" in the response.  Hmm. Undoubtedly my JavaScript rustiness... Actually, it was a misunderstanding of the slot object.

And that does it!  Alexa even pronounces "Tyrion" correctly.

echosim.io

There's also a very cool simulator available for testing.  You can actually use it just like an Echo. And it works!

Super, duper. Now (well, after soccer practice), it is time to get some data from the Wikia. And it will be time for a new blog post.