Pokémon is one of the first game I remember playing. It had everything to shine: an engaging story, a deep but easy to learn gameplay and an amazing character design.
However, with the growing numbers of Pokemon present in each new iteration, it’s very hard to keep track with the growing number of Pokémon you can encounter.
In the latest games, Sun and Moon, there are more than 807 Pokémon to catch!
That’s why I wanted to build a bot to help me keep track: I wanted a companion to help me remember what type is Gyarados or how to make my Stufful evolve.
Besides this copious program, the goal of this tutorial is to show you how to use Gazettes to improve your bot entity detection and how to interact with a Node.JS API that retrieves informations from a knowledge base to create a rich and interactive experience for your users.
This tutorial assumes that you already have a basic knowledge of the Recast.AI’s platform.
If you’re a total beginner on Recast.AI, I advise you to start by reading this tutorial instead.
To follow this tutorial you’ll need:
- An account on Recast.AI. It’s free!
- An up-to-date version (6.0 or higher) of Node.JS installed on your computer.
- A Unix-like command line prompt. If you’re using Windows and can’t install Bash for Windows you’ll need to adapt some steps to your toolchain. We would be happy to help you if you need any.
Note: If you would like to skip the bot creation on Recast.AI and go straight to the server-side, you can fork it from here.
Create a new bot on the platform, and choose Greetings and Small Talk as predefined skills:
TRAINING THE BOT NLP
We’ll focus on training the bot on 2 intents:
- Getting general information about a Pokémon
- Learning about its evolutions.
Create a new intent called
pokemon-informations, and add the following sentences to begin with:
You can add many more sentences, the more examples you add the stronger your bot will be.
You need to tag the Pokémon name with the entity
It would get very, very tedious if we had to teach the algorithm every single Pokémon name this way.
Instead we will use a tool called Gazettes.
CREATING YOUR FIRST GAZETTE
Gazettes are meant to improve entity detection when you can provide a list of synonyms for an entity.
A Gazette holds a list of terms that are called, well, Synonyms, and they are used by the algorithm to make your bot smarter.
You can create a Gazette for an entity at the bottom of the
There are two settings for a Gazette; it can be either open or closed:
- If it is open (the default setting), it will simply improve the entity detection. To do so, it works hand in hand with the entities examples you tagged in your intent expressions. Just think of it as bonus training.
- If it is closed, the synonyms in the Gazette represent every single value the entity can hold. Forget about context and all those fancy features NLP engines use to extract entities, if a word is held in a closed Gazette, it will be tagged, if it is not, it won’t.
The only exception is that closed Gazettes used fuzzy matching to allow for small mistakes and typo, but you can adjust its strictness (100 means a perfect match is required, 1 means everything will be tagged with the entity).
The good news is that you can upload csv files containing synonyms for your gazette.
I created one containg every single Pokémon names that exist: You can download it here.
UPLOAD A .CSV FILE in your gazette page. It might take a while before everything gets loaded.
Now that the bot is taught every Pokémon name, it’s a perfect fit for a closed Gazette. Go to its options and toggle the button to close it.
But why would I need to train my bot once the Gazette is created?
Well, entity and intents, even if linked, are distinct concepts. You still need to train your bot to correctly detect intents even when entities are well trained.
ADDING THE FINAL INTENT
Finish your bot training by adding the last intent,
Add the following sentences :
You should notice that the
POKEMON entity is tagged at the creation of your expression, with no further action!
CREATING THE SKILLS
A big part of the logic of this bot will happen in the NodeJS API, so its skills are very straightforward.
- are triggered if one of the intents you created are present.
- require an instance from the
POKEMONentity to be present.
- send a request to the NodeJS API with the information collected.
Next to the 2 skills you already have in your
Build tab, create a new skill, called
It is triggered when the intent
pokemon-informations is present:
It checks that the entity
POKEMON is set :
Set a message if #pokemon is missing, something like “Which Pokémon do you want to know more about?”
Sends a request to the API once the Pokémon is known, and clean up the memory afterwards:
Create another skill called
pokemon-evolutions structured the same way, but that is triggered if the intent
Pokemon-evolutions is present, and has a webhook URL of
BUILDING THE API
The core of the API simply is an Express.js application. It will have two main routes: one for general information and another for questions about a Pokémon evolutions.
It will also handle POST requests on
/errors, that will be used by the Bot Builder to notice you when something goes wrong.
SETTING UP THE PROJECT
Start by creating a workspace and install the dependencies:
Instead of using a remote database, I created a JSON file containing all the Pokemon knowledge your bot needs.
You can either download it using this link and move it to the folder you just created or you can also use this curl command:
This file is an array of objects structured as such :
Not all the data included will be used in this tutorial so feel free to add features to your bot, or even improve this JSON if needed. You pull requests will be much welcomed!
CREATING THE ROUTES
Now open the index.js file with you favorite editor.
We’ll start by loading the dependencies and start the express application.
Both routes will need to retrieve information about a Pokémon from the JSON file by its name. Let’s write a function to do that:
The controller for the route
/pokemon-informations extracts the Pokémon name for the memory, as configured in the corresponding skill, and fetches its information from JSON.
It then returns a list of messages to display the data in a friendly format.
There is a fallback in case the Pokémon entity extracted by Recast.AI can not be found in the database.
The controller for the route
/pokemon-evolutions is similar, it just returns different data.
Since the formatting of the message displaying the evolution requirements is quite dense, it is better to move it to its own function,
In addition to the fallback if the Pokémon can’t be found, this controller also needs a fallback if the Pokémon doesn’t have any evolution.
You can now launch the API:
The program should output this message on startup:
App is listening on port 5000
If that is not the case for you, try to read along the code again to check for any errors, you’re also welcome to come by our Slack if you get stuck!
MAKING YOUR API PUBLIC
Since Recast.AI needs to be able to publicly access your API, you either need to host it on a public server or to use Ngrok.
Ngrok allows you to expose a port of your computer to the outside world.
Download Ngrok and launch it using this command:
You can now paste the https redirection URL into your Bot base url, in your settings on Recast.AI platform:
Your bot is now live! You can connect to various messaging channels by following the steps in the Connect tab.
GOING FURTHER WITH POKÉBOT
You’ve got a Pokébot up and running. That’s nice already, but with what you’ve learned in this tutorial you can do much more. Here are some queries your bot could process if you want to go further:
- Questions about the moves and when each Pokémon learn them
- Where to find each Pokémon in the games
- Types-matching: what is the modifier of a given type versus another? Mega-bonus if you can handle dual types!
- Adapt the replies depending on the Pokemon version (Good luck on this one!)
Building an exhaustive, all-in-one, all-knowing Pokébot seems like a life’s mission. Only a true Pokéfan could pull it off. Would you be the one?