Designing an Alexa skill using my Pokémon Passport Service Data

Not long after I created my Pokémon passport service data, I was eager to build an application using it. I was already familiar with Alexa skills, so I jumped into building an Alexa skill with this data.

Making the data source easy to consume

Because my data source would rarely change, I chose to store it in a JSON file stored on the skill. When I started my data was in a CSV, so I needed to convert it to JSON. I wanted this JSON file to use each Pokémon’s name as a key for their data. Before writing this code myself I did a quick Google search and discovered this article. I altered this code slightly and ended up with the python code below.

import csv
import json
file = '/home/william/Desktop/PokeProject/UpdatedpokemonSheet.csv'
jsonfile='data.json'
data={}
with open(file) as csvFile:
    rd = csv.DictReader(csvFile)
    for rows in rd:
        id = rows["pokemon_name"]
        data[id] = rows
with open(jsonfile, 'w') as jsonFile:
    jsonFile.write(json.dumps(data,indent=4))

After converting my CSV file into JSON, I had a file with 890 entries. Each entry looked roughly like the code below.

"venusaur": {
        "pokedex_number": "3",
        "pokemon_name": "venusaur",
        "last_playable_in": "Pokemon Sword and Shield",
        "last_catchable_in": "Pokemon Sword and Shield Isle of Armor",
        "display_name": "Venusaur"
    }

Writing Python Code that could reference the data

I knew I needed code that could take in user input and return relevant information to the user. Because the information was laid out in an organized manner, I could convert the JSON into a dictionary and retrieve data using the Pokémon’s name as my key.

import json
f = open('pokemon.json',)
data = json.load(f) 
data['bulbasaur']['last_playable_in']

The code above returned ‘Pokemon Sword and Shield’. From here I created a Python function that asked the user which Pokémon they wanted and returned a statement on the last game the Pokémon was playable in and obtainable in.

def pokemon_reference():
  pokemon = input("Tell me a pokemon, and I'll tell you the last game you could \n catch it and the last game you could play with it \n")
  last_playable = data[pokemon]['last_playable_in']
  last_catchable = data[pokemon]['last_catchable_in']
  print("{} was last playable in {} and was last catchable in {}".format(pokemon,last_playable,last_catchable))

Now that I had my Python code ready I started building my first application, an Alexa skill.

Configuring the Alexa Front End

For this Alexa skill, I chose to use the Alexa-hosted option in the Alexa Developer Console. This option hosts all the code in the console, so you don’t have to connect to Lambda. This option is ideal for skills that execute a small bit of code that doesn’t need to connect to other AWS services. I wanted a quick call and response application, so Alexa-hosted was the ideal option for me. I started by visiting the Alexa Developer Console and clicked “Create Skill”. I chose the Custom skill option, chose Alexa-hosted(Python) as the backend resources host, and named my skill “Pokémon Passport Service”. I proceeded with the Hello World Skill template, knowing I’d remove the HelloWorldIntent. I clicked “Next Step” and then started building my Interaction Model.

To begin building my Interaction Model I deleted the HelloWorldIntent and created a FindPokémonIntent. In this new intent, I entered a few Sample Utterances to help the intent route requests.

The sample utterances for my skill

I gave the Intent a single slot named “Pokémon”, but I needed a custom slot type for this project. So, I visited the Slot Type section of the console. I clicked “Add Slot Type”, taking me to the menu below.

Custom slot type menu

I entered the value “Pokémon” in the menu and clicked “Next”. Within the menu, you submit values, and if necessary give them IDs and Synonyms. To save time, I pulled a CSV list of all Pokémon and copied it into the “Bulk Edit” option. This created 890 slot values for my “Pokémon” slot. I jumped back to the FindPokémonIntent and gave my “Pokémon” intent slot the slot type of “Pokémon”.

I finished designing my Interaction Model by giving my skill the invocation name, Pokémon Passport Service.

Coding the Pokémon Passport Service Skill

The first step to programming the skill was uploading my JSON file. I named this JSON file, “Pokémon.json”. The next step was working on my “lambda_function.py” file. I started by importing the packages necessary for the service. I imported the requests and JSON libraries. Next, I deleted the HelloWorldIntentHandler class and the line “sb.add_request_handler(HelloWorldIntentHandler())” from the bottom of the program. Then, I created the PokémonIntentHandler. This handler looks for the “FindPokemonIntent”. When called the handler pulls the slot value from the request. The handler then opens the JSON file as a dictionary and queries it. The last game the Pokémon was available and playable in is returned to the user. This code worked well for most Pokémon, but some issues needed troubleshooting.

Troubleshooting the Pokémon Passport Service Code

The first issue I ran into was handling the Nidoran family of Pokémon. There are two Pokémon named Nidoran, one female and one male. When designing my skill I strongly considered how users might ask for Nidoran. I wasn’t confident that users would always specify gender. I brainstormed several solutions to this problem, including prompting the user. Ultimately, I settled on a simple solution. Each slot value was checked with an if statement in the code. If the slot value was Nidoran, female Nidoran, or male, then “last_catchable_in” and “last_playable_in” would be set to “Let’s Go Pikachu and Eevee” and the display_name was set to “Nidoran”. If the input wasn’t Nidoran, then the program would search the JSON file and return the relevant values for the Pokémon.

Finishing the Code for the Pokémon Passport service

Having built the baseline functionality of the program, I then focused on making the final output palatable for the user. The variables “last_catchable_in”, “last_playable_in”, “output”, and “display_name” during the initial build. Now I needed to use them to create an understandable response. For Nidoran, I hardcoded output to say “Both male and female Nidoran were last obtainable and catchable in Let’s Go Pikachu and Eevee”. For all other cases, I made the output say “(display_name) was last obtainable in (last_obtainable_in) and last playable in(last_playable_in)”. The variables display_name, last_playable_in, and last_obtainable_in represented the name of the Pokémon, the last game the Pokémon was playable in, and the last game the Pokémon was obtainable in respectively. My speak_output was set equal to this output. The handler would take input from the user and respond with the polished output.

Since I had no other intent handlers to create I checked my code for errors and proceeded to test my skill.

My skill worked well, but I wanted a few more features and I needed to troubleshoot my skill. Check out my next article for insight into my troubleshooting process, adding cards, and publishing the finished skill.