Alexa Skill Revamp - The Intents

This post is 3 of X, part of the "Battle Cry Revamp" series

Posts in the series I'll udpate the list as I write more:

Alexa Skill Revamp - Battle Cry

Alexa Skill Revamp - The Code (the humanity!)

Alexa Skill Revamp - The Intents

Alexa Skill Revamp - Person Profile

I remember when you had to do all this by hand...

So my code is now much more isolated, but there's still a lot of code in the handlers that has nothing to do with the game itself.

The reason for this is that when I wrote the skill we had dialog delegation in a very basic form, but I had to ensure that the values I got back from the intent matched what I expected, and if not I had some interesting scenarios such as what happened if only the second value didn't match properly (do I ask for the second move again, or was it misheard and the third move was actually the second?)

Slot management has come a long way since then and I want Battle Cry to take full advantage, so I need to update the intents.

I'm still sticking with improving the existing skill - I can't look at improving utterances until I'm sure of how I want to collect the information I need. When it comes to intents and slots there are two primary use cases:

  • Quoting a share code: When you start a new battle I need to make sure you you have the code for a valid opponent, which means getting their share code so I can perform a lookup.

  • Picking your moves: Whether it's setting up a battle to send to someone, or deciding how to fight back this is the crux of the battle mechanism. Three attack moves, three defence moves, then go.

The other intents are slot free, so although I might review their sample utterances, cleaning up these two scenarios should enable me to get the code into a state where the vast majority is based on game functionality.

Quoting a share code

First I'll tackle the more straight forward of the two. So I've mentioned it before but a share code is a color, an animal and a four digit code. So my intents use three slots

Three share code slots within the Alexa Skill Designer

Now the four digit number I'm not concerned by, but the color and the animal are selected from a predefined list that I use in the skill to generate them. Now if you have a large number of items for a particular slot then you can look into Catalog Management, but this is just a small list so I just want them to definitely match one of the entries I've picked. For this we use slot validation.

What this means is that if the utterance fits, but the value for the slot doesn't match the rules we set for it, then Alexa will ask for a new value until there's one that matches. This allows the skill to worry about using the value and not have to validate the match itself.

So to do that we use the "Edit Dialog" button against the slot in our intent, and select from the validations available. You have to also enter the possible responses Alexa uses when asking for a new value, which saves your skill from having to worry about it in terms of logic and testing.

The options when you're validating a slot

Straight forward to implement, but very useful when you can't have any variation on the response you're receiving. This was a journey in itself for me and one that I am now able to delete.

Picking your moves

Okay so this is the first time in the revamp that I've actually had to fundamentally change the way something works, but the end result - I hope - is going to be less code and cleaner code.

So I have custom slot type which is "moves" - top, middle, bottom (there are synonyms but this is what I'm looking for). And for a player to complete their turn I need six moves - three defence, three offence.

So that's exactly what I'd asked for, six slots in total.

Three original slot structure

I couldn't mark them as required because that can be a lot to say in one go, plus users will maybe choose to say one at a time or three at a time (at best).

What this meant was that I had a lot of code keeping track of my moves, looping through six slots to figure out how far they'd gotten so I can elicit the next slot. This meant what I had was quite a brittle dialog. (I'm not showing the loop code in this case, not hiding - but I wrote it alongside some state management and I'd have to explain a lot more than is worthwhile for it to make sense! Want to focus on the intents )

For example, if I put too many words between the slot values (I get into my battles, I'm playing it out!) then what can happen is the dialog thinks maybe I said less than I did - and my loop would decide to ask for defence move two when I'd already said it and that immediately makes it less fun and more chore. Not good! I can fix this...by creating more and more utterances that correctly handle every situation for one slot, then two, then three, then....ARGH! NO! I can't do it any more.....it's horrible. Every time I find a new way I want to handle, it's six more utterances at least - now I'm spending all my time trying to maintain or automate that for what feels like a really simple intent.

So I've got brittle dialog and nasty loop code in my skill doing all this stuff, I want rid of it.

And now I can! By using a new beta feature for slots - multi value slots. What this allows me to do is create a single slot called "moves" and give it a good set of utterances (just for that one slot).

One slot to rule them all

Then in the dialog options for that slot, I say that I might get more than one value.

Multi value slot toggle

Now when I speak, Alexa will pick up when the user speaks more than one utterance together, and give them back as a list of slot values in the skill! Here's an example from the utterance profiler in the skill console

Example output from the utterance profiler

That is so nice! I'm maintaining less within the intent and when this hits my Alexa.NET code I can simply run though the values I know I've received, rather than having to check the state and value of each slot and have complicated state management.

  var moves = intentRequest.Intent.Slots["moves"];
  if (moves.SlotValue.SlotType == SlotValueType.List)
  {
      //Got multiple values
      foreach (var value in moves.SlotValue.Values)
      {
          //...do my stuff...
      }
  }

Now my logic is kinda simplistic:

  • If I get less than the three I need for the defensive moves I can elicit the slot for more.
  • If I get more than I can ask for confirmation of the first three - and if they're confirmed then I can use what's left and ask for the remainder
  • Keep doing that until I have six values.

You know what this needs? MORE REQUEST HANDLERS! And this is part of why I find them so important. I don't just have to isolate my code into "everything to do with this intent". Some intents have subtle use case changes and each should be their own handler. So this is what I will probably write instead:

  • Handles the moves intent AND six values
  • Handles moves where there's more than three values and I haven't got confirmation
  • Handles moves where there's more than three values and they've just confirmed
  • Handles moves in all other scenarios

Anything that reduces the number of slots I need to care about is going to help me maintain the codebase for this skill, but the way multi value slots uses the utterances to fill in the detail means that I also have a much more fluid and natural flow to the dialog I'm building - with less effort! Total result.

Is that really it?

I hadn't looked at multi value slots in great detail before now. I mean I wrote the code for Alexa.NET but that's implementing a spec for a library, I wasn't really paying attention to the real world implementation until now and I definitely hadn't looked into the skill console side of things.

Overall it's MUCH easier than I expected, I thought I'd be wrapping my head around it more - especially as I want two lots of three not just a list (the example implementation is pizza toppings and I was a little concerned I'd have more trouble because my example is a little bit more specific). It's not required for everyone, but once again the team have come up with a really tidy solution for when it is.

So now what?

Now what? Well I'm going to do some internal tidying up - I want to refactor the logic so they fit the request handler structure I mentioned and do a little testing to ensure I've not broken anything.

Once that's complete the next step on the list is implementing voice profiles, not a huge change for the codebase but actually a really big difference in how playable my game is.

See you soon!