Start building your own chatbot now >

What’s in it for me?

In this guide, you’ll learn how Bot Hosting works, how your code should be structured to run on it and what are the good and bad practices.

I start this tutorial by assuming you already know how to use the platform tools: train your bot, create a conversation flow using Bot Builder, connect it to channels using Bot Connector, so if it’s not the case, I invite you to check out our others tutorials.

We’ll start with a quick overview of what Bot Hosting is, will move on to a description of the requirements and limitations, and conclude by building a custom code hosted on Bot Hosting! Let’s roll. 

What is Bot Hosting?

Bot Hosting is a service that allows you to host your bots without any devops knowledge.

It is based on serverless cloud instances. Your code is triggered by a call to a https endpoint (e.g. POST https://run.recast.ai/your-bot). Once triggered, it executes and goes back to sleep until the next call. You can also easily access your logs deploy your code each time you push!

Of course, it’s fully integrated with other Recast.AI services, so you can host a bot using Bot Connector and made with Bot Builder.

You can find Bot Hosting on Recast.AI, in the Run/Bot Hosting tab.

Requirements

As of today, only NodeJs is supported for Bot Hosting. More languages will come soon.

Since we deploy your code in generic containers, there are 3 requirements.

Build task

Your package.json must contain the build task. It must be present even if empty or just copying files. The default one you will find in the starter kit is “build”: “babel src -d lib” to compile your Javascript. So you can code with your favorite ES6 or ES7 features.

During the build, only the DevDependencies are installed, so be careful to put all dependencies needed by the build on the dev dependencies on your package.json.

Lib directory

A lib directory must be present (by default it’s created with the build task).

Specific entrypoint

The entrypoint of your code in production must be in the lib/bot.js file. This file must contain an export of a bot function named bot. The function takes the first argument the body of the request (Bot Connector, custom curl,…).

Example: your bot.js

export const bot = (body, response, callback) => { 
  if (body.message) {
    // your logic
  } else {
    callback('No text provided')
  }
}

You can change all other file names, directory structures, but be sure that these three points work fine!

Limitations

To be able to provide the best experience, we’ve set some default limits to your instances:

Description Limit Increase possible?
Code size (code + vendors) 200Mo No
Maximum execution duration per request 30seconds Yes
Concurrent requests 150 Yes


If you reach those limits, contact us and we’ll raise them for you if it is possible.

First hosted code from scratch

Now you’ve seen the requirements of Bot Hosting, let’s start with something simple. We’ll create a bot getting Chuck Norris facts using the https://api.chucknorris.io/ API on Facebook Messenger.

Here’s how you’re going to do it:

1- Create the bot on Recast.AI and train it

2- Connect it to Facebook Messenger using Bot Connector

3- Talk to it

4- Create our code and integrate the API

5- Push our code to Github

7- Deploy it on Bot Hosting

8- Enjoy!

Create the bot on Recast.AI and train it

First, we need a bot on Recast.AI, so let’s connect to the platform and create a new bot:

You can see that your new bot contains greetings and goodbyes default intents.

Now, let’s add our main intent: get_joke.

Fill it with expressions you want your bot to understand. Create a “category” entity and tag your sentences containing categories to give results using categories of the API

That’s enough training for the purpose of this tutorial. Let’s now connect it to a channel! Go to the “Run tab”, select your channel (here we’re using Messenger), and follow the instructions. If you’ve configured replies in the “Build” tab, you can start talking to your bot right away. 

But since we want to integrate an API to enrich the conversation, we need to add some code! First, create a new repository on Github.

Now, locally, initialize your repository with a package.json:

{
  "name": "chuckmorris-bot",
  "version": "1.0.0",
  "description": "A bot giving you fun facts about Chuck Norris",
  "main": "server.js",
  "scripts": {
    "start": "nodemon --exec babel-node -- src/server.js",
    "prod": "node lib/server.js",
    "lint": "eslint src/",
    "build": "babel src -d lib"
  },
  "author": "Recast.AI",
  "license": "ISC",
  "repository": {
    "type": "git",
    "url": "git@github.com:RecastAI/chucknorris-bot.git"
  },
  "dependencies": {
    "babel-polyfill": "^6.22.0",
    "body-parser": "^1.15.2",
    "express": "^4.14.0",
    "recastai": "^3.1.1",
    "request": "^2.81.0"
  },
  "devDependencies": {
    "babel-cli": "^6.11.4",
    "babel-eslint": "^6.1.2",
    "babel-preset-es2015": "^6.22.0",
    "babel-preset-stage-0": "^6.22.0",
    "babel-register": "^6.11.5",
    "eslint": "^3.2.0",
    "eslint-config-zavatta": "^4.2.0",
    "eslint-plugin-import": "^1.6.1",
    "nodemon": "^1.11.0"
  },
  "babel": {
    "presets": [
      "es2015",
      "stage-0"
    ]
  },
  "eslintConfig": {
    "extends": "zavatta",
    "rules": {
      "no-console": 0,
      "callback-return": 0
    }
  }
}

 

and a src folder containing 3 files:

– bot.js: the file containing your bot logic

– server.js: the server used locally

– config.js: a non-versioned config file

then, run npm install to install the node modules.

 

Now, let add code to the server.js file:

const express = require('express')
const bodyParser = require('body-parser')

// Load configuration
require('./config')
const bot = require('./bot').bot

// Start Express server
const app = express()
app.set('port', process.env.PORT || 5000)
app.use(bodyParser.json())

// Handle / route
app.use('/', (request, response) => {
  // Call bot main function
  bot(request.body, response, (error, success) => {
    if (error) {
      console.log('Error in your bot:', error)
      if (!response.headersSent) { response.sendStatus(400) }
    } else if (success) {
      console.log(success)
      if (!response.headerSent) { response.status(200).json(success) }
    }
  })
})

if (!process.env.REQUEST_TOKEN.length) {
  console.log('ERROR: process.env.REQUEST_TOKEN variable in src/config.js file is empty ! You must fill this field with the request_token of your bot before launching your bot locally')
  process.exit(0)
} else {
  // Run Express server, on right port
  app.listen(app.get('port'), () => {
    console.log('Our bot is running on port', app.get('port'))
  })
}

This code requires the bot function in the bot file, and setups a simple express server which transfer any new request to the bot function.

We also need to fill the config.js file:

process.env.PORT = '5000'
process.env.REQUEST_TOKEN = ‘YOUR-RECASTAI-REQUEST-TOKEN’
process.env.LANGUAGE = 'en'

Now let’s focus on the bot.js file:

const recastai = require('recastai').default
const client = new recastai(process.env.REQUEST_TOKEN)
const request = require('request')

Then, add the bot export:

export const bot = (body, response, callback) => {
  console.log(body)

  if (body.message) {
    client.connect.handleMessage({ body }, response, replyMessage)
    callback(null, { result: 'Bot answered :)' })
  } else if (body.text) {
    replyMessage(null, body.text, response)
  } else {
    callback('No text provided')
  }
}

This method takes 3 parameters:

body, the body of the request 

response, the response object from the server in case of a local run

callback, the object called in case of a bot hosting run

 

If the body contains a message object, that means the request is coming from bot connector, so we use Bot Connector SDK and pass the replyMessage as callback function.

Else if it contains a text key, we consider this is a simple Curl of API call so we handle it directly through the replyMessage function.

Now let’s go with the function replyMessage:

const replyMessage = (message, text, res) => {
  const recastaiReq = new recastai.request(process.env.REQUEST_TOKEN, process.env.LANGUAGE)
  const content = (message ? message.content : text)

  recastaiReq.analyseText(content)
  .then(recastaiRes => {
    if (recastaiRes.entities.hasOwnProperty('category')) {
      request('https://api.chucknorris.io/jokes/categories', (_err, _res, body) => {
        let response = JSON.parse(body)
        let category = recastaiRes.entities.category[0].value
        if (response.indexOf(category)) {
          request(`https://api.chucknorris.io/jokes/random?category=${category}`, (_err, _res, body) => {
            body = JSON.parse(body)
            const content = body.value
            
            return message ? message.reply([{ type: 'text', content }]).then() : res.json({ reply: content })
          })
        } else {
          request('https://api.chucknorris.io/jokes/categories', (_err, _res, body) => {
            body = JSON.parse(body)
            const content = `Sorry, I only know about these categories: ${body.join(', ')}.`
            
            return message ? message.reply([{ type: 'text', content }]).then() : res.json({ reply: content })
          })
        }
      })
    } else {
      request('https://api.chucknorris.io/jokes/random', (_err, _res, body) => {
        body = JSON.parse(body)
        const content = body.value
  
        return message ? message.reply([{ type: 'text', content }]).then() : res.json({ reply: content })
      })
    }
  })
}

 

First, this function initialises the Recast.AI Request SDK and sets the content.

Then, we use analyseText to analyse the sentence sent by the user.

Once we’ve got the response, if there is an entity category, we request the ChuckNorris API with the category if it’s an existing category and send the returned joke to the user. Otherwise we reply to the user that the category doesn’t exist.

If there is no category, we simply request the ChuckNorris API for a random joke and send it to the user.

Easy! You can try it locally with

npm start

and then

curl -X POST http://localhost:5000 --data='{"text": "I want a sport joke!"}'

Cool, but better if it’s online!

So go back to the Run tab, then go to the Bot Hosting sub-tab.

Connect your account to Github and link your repository:

Click on “Connect your repo” to start deploying your repository! In 1 or 2 minutes, it’ll be deployed and connected to your channels! Try it out on Facebook 🙂

A final word

That’s it, congratulations you’ve made it! Actually, it’s rather simple, but there are some requirements and limitations to understand. Now you should be ready to code Jarvis on your own! 🙂

Of course, you can find the complete code on Github and the train of the bot on Recast.AI.

If you have any feedback, question or suggestion for the next features, drop me an email at julien@recast.ai or chat on our Slack Community (https://slack.recast.ai – Julien).

Julien Blancher – Recast.AI

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

Subscribe to our newsletter


There are currently no comments.