Create a Botonic Plugin

Sometimes you may need a specific feature according to your needs and you want to build your particular plugin that doesn't exist yet. In order to achieve this, we have to review some important aspects.

Fundamental Concepts

  • You can create your own plugins to be used locally in your project or as a npm package.
  • package.json is mandatory.
  • Each plugin have to implement the methods we describe in this guideline.

Plugin Conventions

Every plugin you create for botonic has to be under a directory named:
botonic-plugin-{YOUR_PLUGIN_NAME}.

  • Example: botonic-plugin-dialogflow

In addition, the plugin directory has to be structured in the following way:

botonic-plugin-{my-plugin-name}
└── package.json
└── src
└── index.js <-- This is the entry point of your code
└── MY_USEFUL_CODE

The required fields in your package.json must be the following:

  • name: we suggest you to put the same name as the directory, for simplicity and maintainability.
  • version: the corresponding plugin's version, starting by 0.0.1.
  • main: the entry point of your plugin. We suggest you to mantain the structure as it is.
  • dependencies: your dependencies, if any.
  • devDependencies: your devDependencies, if any.

Example :

{
"name": "@botonic/plugin-luis",
"version": "0.1.0",
"main": "src/index.js",
"dependencies": {
"axios": "latest"
},
"devDependencies": {
"@babel/runtime": "^7.5.5"
}
}

How to Create a Plugin?

For a better understanding, we will start with the most essential parts our plugin must have.
In order to develop a plugin for Botonic, you will have to create a new directory structured as explained before. Once created, you will have to copy this boilerplate code in your index.js:

botonic-plugin-{my-plugin-name}/src/index.js

// By default, we suggest you to name your class with UpperCamelCase
export default class BotonicPluginMyPluginName {
constructor(options) {
this.options = options
}
async pre({ input, session, lastRoutePath }) {
return { input, session, lastRoutePath }
}
async post({ input, session, lastRoutePath, response }) {
return { input, session, lastRoutePath, response }
}
}

As can be seen, in our plugin we will have three basic methods:

  • constructor: which will be used in order to pass to our plugin the necessary options (JS Objects) needed to run our code, such as tokens, authentication keys, etc.
  • pre: stands for all these kind of operations that we want to preprocess of our input, such as applying NLU to extract intents or entities.
  • post: stands for all these kind of operations that we want to process ex-post, such as adding a tracking id to our session.

Botonic will look for pre and post methods and will execute them before or after the input is processed, correspondingly.

Note: It's crucial that pre and post methods are declared with the async keyword for an expected behaviour.

Let's take a closer look at Botonic LUIS Plugin:

import axios from 'axios'
export default class BotonicPluginLUIS {
constructor(options) {
this.options = options
}
async pre({ input, session, lastRoutePath }) {
let intent = null
let confidence = 0
let intents = []
let entities = []
try {
let luis_resp = await axios({
url: `https://${this.options.region}.api.cognitive.microsoft.com/luis/v2.0/apps/${this.options.appID}`,
params: {
'subscription-key': this.options.endpointKey,
q: input.data,
verbose: true,
},
})
if (luis_resp && luis_resp.data) {
intent = luis_resp.data.topScoringIntent.intent
confidence = luis_resp.data.topScoringIntent.score
intents = this.convertIntents(luis_resp.data.intents)
entities = luis_resp.data.entities
}
} catch (e) {}
Object.assign(input, { intent, confidence, intents, entities })
return { input, session, lastRoutePath }
}
convertIntents(luisIntents) {
return luisIntents.map(li => ({ intent: li.intent, confidence: li.score }))
}
async post({ input, session, lastRoutePath, response }) {}
}

That's all! Once you have implemented your plugin, you are ready to use it.

The fallback content to display on prerendering