Start building your own chatbot now >
Note: This article is deprecated. It uses Recast.AI API version 1. You can find an updated tutorial here: NodeJS chatbot tutorial: A Github bot with Recast.AI.

STEP 5: PokeApi

PokeBot answers to the greetings intent just fine, but we can’t do the exact same thing for ‘infopokemon’: it’s a dynamic intent where answers will differ based on the request. In that case, we use an external API: PokeApi.

 

1. Make a request

To make a request to PokeApi, and get your pokemon informations, you have to make a GET request to this url: ‘https://pokeapi.co/api/v2/pokemon/:your_pokemon’

  • I like to use superagent node module to make http requests. Install it.
npm install --save superagent
  • Import superagent module in infopokemon.js, make your request in your getInfoPokemon function and log the result
const request = require('superagent')
const getInfoPokemon = (entity) {
  if (!entity) { return Promise.reject('You didn\'t gave me any pokemon')}
  return new Promise((resolve, reject)) {
    request.get('https://pokeapi.co/api/v2/pokemon/' + entity.raw)
    .end((err, res) => {
      if err { return reject('ERROR') }
      resolve('OK')
      console.log(res.body)
    })
  })
}
modules.exports = getInfoPokemon

 

2. Handle the Asynchronous requests

As a request is Asynchronous, we cannot just return a String and send the result in pokebot.js: we have to wait. That’s why we change the code a little bit: modules function will return a Promise instead of a String.
Resolve something and it will be caught in .then
Reject something and it will be caught in .catch

  • Use .then and .catch to handle the result of infopokemon which is a Promise.
pokebot.js:

...
const intent = res.intent()
const entity = res.get('pokemon')
if (intent) {
  INTENTS[intent.slug](entity)
  .then(res => session.send(res)) // If intent is infopokemon & no error: ‘OK’
  .catch(err => session.send(err)) // If intent is infopokemon & error: ‘ERROR’
}
  • return a resolving only Promise in greetings.js to adapt those changes
greetings.js:
const getGreetings = () => {
  const answers = [
    `Hello!`,
    `Yo ;)`,
    `Hey, nice to see you.`,
    `Welcome back!`,
    `Hi, how can I help you?`,
    `Hey, what do you need?`,
  ]
  return Promise.resolve(random(answers))
}
  • Asking information about a pokemon should now print the json of this pokemon in the console!

 

3. Build a Layout

Now you have the datas, you have to use the doc and build a nice answer for the user with all this data.

  • Take some time to read the Documentation of the API (https://pokeapi.co/docsv2). Here are the informations you can get with a request on a pokemon.

recast-ai-pokeapi-doc

  • Create a new function infoPokemonLayout. It takes the Json as argument and will return the answer of the bot. This answer will contain the name, the types, and a picture.
infopokemon.js:
const infoPokemonLayout = json => {
  const answer = [`:mag_right: ${json.name} infos`]
  const toAdd = json.types.map(elem => elem.type.name).join(' / ')
  answer.push(`Type(s): ${toAdd}`)
  if (json.sprites.front_default) { answer.push(json.sprites.front_default) }
  return answer
}
  • Call the layout function at the ‘resolve’ in getInfoPokemon.
infopokemon.js:
const getInfoPokemon = (entity) {
  if (!entity) { return Promise.reject('You didn\'t gave me any pokemon')}
  return new Promise((resolve, reject)) {
    request.get('https://pokeapi.co/api/v2/pokemon/' + entity.raw)
    .end((err, res) => {
      if err { return reject('ERROR') }
      resolve(infoPokemonLayout(res.body))
      console.log(res)
    })
  })
}
  • Change answer form a string to an Array to send multiple messages.
pokebot.js:
if (intent) {
  INTENTS[intent.slug](entity)
  .then(res => { res.forEach((message) => session.send(message)) })
  .catch(err => { err.forEach((message) => session.send(message))) })
}
greetings.js:
return Promise.resolve([random(answers)])

 

4. Handle images

For now the only thing we send is the url of the image. That’s why we’ll create a message object with a type and a content: the type will be either image or text.

  • Make a function ‘toText’ to change a text into an message Object.
const toText = message => { return { type: 'text', content: message } }
  • Make a function ‘toImage’ to change an image into an message Object.
const toImage = image => { return { type: 'image', content: image } }
  • Use them before you push information in an answer.
infopokemon.js:

const infoPokemonLayout = (json) => {
  const answer = [toText(`:mag_right: ${json.name} infos`)]
  const toAdd = json.types.map(elem => elem.type.name).join(' / ')
  answer.push(toText(`Type(s): ${toAdd}`))
  if (json.sprites.front_default) {
    answer.push(toImage(json.sprites.front_default))
  }
}

greetings.js

return Promise.resolve([toText(random(answers))])
  • Update pokebot.js according to those changes: Replace session.send(message) by sendMessageByType(session, message)
pokebot.js:

const sendMessageByType = {
  image: (session, elem) => session.send(new builder.Message().addAttachment({
    contentType: 'image/png',
    contentUrl: elem.content,
  })),
  text: (session, elem) => session.send(elem.content),
}

...
if (intent) {
  INTENTS[intent.slug](entity)
  .then(res => { res.forEach((message) => sendMessageByType[message.type](session, message)) })
  .catch(err => { err.forEach((message) => sendMessageByType[message.type](session, message))) })
}

 

STEP 6: Add other intents

Now you have 2 intents working: a basic one, Greetings, and a dynamic one, Infopokemon, but we have 2 more intents to do!

 

1. The last three basic intents: Goodbyes/Help/Feelings

  • Create them on Recast.AI (by yourself or by forking them).
  • Create 3 files, one for each, and add them in the INTENTS tab in pokebot.js.
pokebot
  ├ config.js
  ├ pokebot.js
  ├ intents/
    ├ greetings.js
    ├ infopokemon.js
    ├ feelings.js
    ├ goodbyes.js
    ├ help.js
  └ node_modules/
  • The code will be same as your “Greetings” intent, just change the function name, export and replies.
  • Try you bot on these intents. It can now answer to ‘How are you?’, ‘Help me!’ or ‘Bye!’.

 

2. The movepokemon Intent:

  • Create or fork a movepokemon intent on Recast.AI and add some expressions:

-What moves does bulbasaur learn?
-What can pikachu learn?
-What are venusaur moves?
-Show me charizard moves.

movepokemon.js:

 const movePokemonLayout = (json) => {
      console.log(json.moves)
   const answer = []
   // Fill answer
   return(answer)
 }

 const getmovePokemon = (entity) {
 if (!entity) { return Promise.reject('You didn\'t gave me any pokemon')}
   return new Promise((resolve, reject)) {
     request.get('https://pokeapi.co/api/v2/pokemon/' + entity.raw)
     .end((err, json) => {
       if err { return reject('ERROR') }
       resolve(movePokemonLayout(res.body))
     })
   })
 }
  • To write the movePokemonLayout function, you have to filter and only keep the moves you want (depending on the version, and the way they are learned).
JSON.MOVES:

 "moves": [{
   "move": {
     "name": "flash",
   },
   "version_group_details": [{
     "level_learned_at": 0, // lvl to learn this move
     "version_group": {
       "name": "x-y", // version for those information
     },
     "move_learn_method": {
       "name": "machine", // is the move learn naturally or with TCs?
     }
   }]
 }]
  • I recommend to use the Lodash library. It offers lots of useful functions like filter, find, sortBy and many more!
npm install --save lodash

 

3. The statpokemon Intent:

  • Create or fork a statpokemon intent on Recast.AI and add some expressions:

– What are bulbasaur stats?
– What are venusaur statistics?
– Show me charizard stats.
– Show me stats of pikachu.

statpokemon.js:

 const statPokemonLayout = (json) => {
   console.log(json.stats)
   const answer = []
   // Fill answer
   return(answer)
 }

 const getStatPokemon = (entity) {
   if (!entity) { return Promise.reject('You didn\'t gave me any pokemon')}
   return new Promise((resolve, reject)) {
     request.get('https://pokeapi.co/api/v2/pokemon/' + entity.raw)
     .end((err, json) => {
       if err { return reject('ERROR') }
       resolve(statPokemonLayout(res.body))
     })
   })
 }
  • To write the statPokemonLayout function, loop on the stats and fill the answer with ‘stat.name’ and ‘base_stat’.
JSON.STATS:

 "stats": [{
   "base_stat": 70, // value
   "effort": 0,
   "stat": {
     "name": "speed", // name
   }
 }]

 

Congrats, your bot can now have dynamic replies! Try some Pokemons to see the results. In the 3rd and last part of this tutorial, we’re going to add some sweet features to our bot ;).

Access to step 3 here.

Want to build your own conversational bot? Get started with Recast.AI !

Subscribe to our newsletter


  • Mat

    code of 1. Make a request was not working. With theses changes it works :
    const request = require(‘superagent’)
    const getInfoPokemon = (entity) => {
    if (!entity) { return Promise.reject(‘You didn’t gave me any pokemon’)}
    return new Promise(
    function(resolve, reject) {
    request.get(‘https://pokeapi.co/api/v2/pokemon/’ + entity.raw)
    .end((err, res) => {
    if (err) { return reject(‘ERROR’) }
    resolve(‘OK’)
    console.log(res.body)
    })
    })
    }

    module.exports = getInfoPokemon

  • Mat

    error on Menu 3. Build a Layout, Change answer form a string to an Array to send multiple message:

    .catch(err => { err.forEach((message) => session.send(message))) })
    >>
    .catch(err => { err.forEach((message) => session.send(message)) })