npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

amio-chatbot-builder

v1.2.0-alpha

Published

[![npm version](https://badge.fury.io/js/amio-chatbot-builder.svg)](https://badge.fury.io/js/amio-chatbot-builder)

Downloads

4

Readme

amio-chatbot-builder-js

npm version

Amio Chatbot Builder is a simple bot framework that simulates a state machine chatbot. You can easily add NLP and analytics features though. We, are using it on our own chatbot projects. Just like Amio, the framework aims to be platform agnostic. Check out all the supported platforms.

Let us know how to improve this library. We'll be more than happy if you report any issues or even create pull requests. ;-)

Installation

npm install amio-chatbot-builder --save

You will want to send and receive messages. For this purpose install amio-sdk-js.

npm install amio-sdk-js --save

Usage

Prerequisities

  1. Setup NodeJs - we prefer to use it with Express (use generator)
  2. Setup Amio webhooks

Basic setup

You can copy/paste this setup.

1. Create state

// file echo.state.js
const State = require('amio-chatbot-builder').State
const AmioApi = require('amio-sdk-js').AmioApi

const amioApi = new AmioApi({
    accessToken: 'get access token from https://app.amio.io/administration/settings/api'
})

class EchoState extends State {
  
  constructor(){
    super()
    this.addNextState(this, webhook => true)
  }
  
  async execute(channelId, contactId, webhook) {
    const {data} = webhook
    const payload = data.content ? data.content.payload : data.postback.payload
    await this._sendMessage(channelId, contactId, payload)
  }
  
  async _sendMessage(channelId, contactId, text){
    await amioApi.messages.send({
      contact: {id: contactId},
      channel: {id: channelId},
      content: {
        type: 'structure',
        payload: {
          text,
          buttons: [{
            type: 'postback',
            title: 'Click me',
            payload: 'POSTBACK_CLICKED' 
          }]
        }
      }
    })
  }
}

module.exports = EchoState

2. Setup chatbot

// file my-chatbot.js
const Chatbot = require('amio-chatbot-builder').Chatbot
const EchoState = require('./path/to/echo.state.js')

class MyChatbot extends Chatbot {
  constructor(){
    super()
    const echoState = new EchoState()
    this.addPostback('POSTBACK_CLICKED', echoState)
    this.setInitialState(echoState)
  }
}

module.exports = new MyChatbot() // make it singleton (not obligatory ;)

3. React to webhooks

After setting up Amio webhooks you can pass the webhook events to your chatbot.

// file router.js
const express = require('express')
const router = express.Router()
const chatbot = require('./path/to/my-chatbot.js')
const WebhookRouter = require('amio-sdk-js').WebhookRouter

const amioWebhookRouter = new WebhookRouter({
    secretToken: 'get secret at https://app.amio.io/administration/channels/{{CHANNEL_ID}}/webhook'
})

amioWebhookRouter.onMessageReceived(async webhook => await chatbot.runNextState(webhook))
amioWebhookRouter.onPostbackReceived(async webhook => await chatbot.runPostback(webhook))
// you can react to other webhook events too

router.post('/webhooks/amio', (req, res) => amioWebhookRouter.handleEvent(req, res))

module.exports = router

Chatbot

Chatbot represents a state machine. The most important methods you'll be using are chatbot.runNextState() and chatbot.runPostback().

You can set it up using either inheritance or composition:

//Inheritance
class MyChatbot extends Chatbot {
  constructor(){
    super()
    this.addPostback()
    // ...
  }
}

// Composition
const chatbot = new Chatbot()
chatbot.addPostback()
// ...

Method | Params | Description ------- | ------ | -----------
addInterceptor | interceptor | Registers a new interceptor at the end of the interceptor chain. addPostback | keystate | Registers a state that will be invoked after postback with a specific key is received runNextState | webhook | How it works: 1. Iterate all interceptors` before(). 2. Keep executing states while state.execute() returns a state. 3. Iterate all interceptors` after().Warning - If an interceptor returns false, go directly to step 3.
runPostback | webhook | Picks a correct state that was registered using chatbot.addPostback(). Then it executes chatbot.runNextState()
setErrorPostbackState | state | State that is executed if no postback is matching the key registered in chatbot.addPostback(key, state). setInitialState | state | If no postback starts the chatbot, the initial state will be executed as the very first state.
setInterceptors | array(interceptor) interceptors | Sets the whole interceptor chain. The first interceptor is to be run first. setPostbackKeyExtractor | function | Normalizes postback key so that it can be used to find a correct. It's useful if you're passing some data in postback like 'POSTBACK:ARBITRARY_DATA'. In this case, you would register a state as chatbot.addpostback('POSTBACK', state)It accepts webhook.data.postback.payload as the function argument.

State

State holds all the steps a chatbot shall do upon receiving a webhook. It's a reusable piece of logic. Generally, one state will consist of several 'message sends'.

Method | Params | Description ------- | ------ | ----------- addNextState | nextStatecondition | Adds a static transition to a next state. If condition(webhook) return true. The state will be selected for execution. execute | channelIdcontactIdwebhook | Executes state`s logic. If you return a new state it will run immediately - it is so called dynamic transition.

State transitions - static vs. dynamic

Static transitions between states are known from the app startup (or from the compilation). They are defined as chatbot.addPostback(key, state) or as state.addNextState(state, condition).

function condition(webhook){
  if(now() % 2 === 0) return true // use this state after next webhook event is received
  
  return false
}

Dynamic transitions between states are decided either in state.execute() or anywhere you call chatbotCache.setNextState(). You can run a state immediately without having to wait for another webhook if you return it from state.execute().

class MyState extends State {
  
  execute(channelId, contactId, {data}){
    if(data.content) { 
      console.log('I will execute YourState right now!')
      return new YourState() 
    } 
    
    console.log('just log') 
  }
}

Cache

Chatbot uses a cache that is referenced in code like chatbotCache. It keeps temporary data about a contact. The contact is always identified by contactId. You can use it to store and retrieve your data using chatbot.set() and chatbot.get().

By default, the cache stores:

  • last 100 clients (LRU)
  • next state - chatbot.setNextState()
  • last 20 states chatbot.getPastStates()

Method | Params | Description ------- | ------ | ----------- get | contactIdkeydefaultValue = null | Returns a value for a key of contact with contactId.
getLastState | contactId | Returns last visited state. getNextState | contactId | Returns the next state that will be executed by chatbot. getPastStates | contactId | Returns last 20 states executed for contact contactId. reset | | Clears the cache. set | contactIdkeyvalue | Add value to a key of contact with contactId.

Interceptor

Interceptors are used to influence received webhook events either before or after a state is executed. An interceptor is a class that extends require('amio-chatbot-builder').Interceptor. Register interceptors using chatbot.setInterceptors([interceptor1, ...])

How the interceptors work:

  1. Your server receives a webhook event.
  2. You pass the event over to chatbot via chatbot.runNextState(webhook)
  3. Chatbot first iterate all interceptors` before(). The first interceptor that returns false breaks the interceptor chain and state execution is skipped. Go directly to step 5.
  4. Chatbot keeps executing states while state.execute() returns a new state.
  5. Chatbot iterates all interceptors` after().

SEE EXAMPLE .

Method | Params | Description ------- | ------ | -----------
before | channelIdcontactIdwebhook| before() is executed before the state itself. Return false if you wish to prevent the state execution. No other interceptors will be run either.You can also change state using chatbotCache.setNextState(newState). after | channelIdcontactIdwebhook| after() is executed after the state execution. It good for a clean up. All registered interceptors are always executed.

Logging

If you want to enable logs, add namespace amio-chatbot-builder-js:* to your DEBUG environment variable.

process.env.DEBUG = 'your-project-namespace:*,amio-chatbot-builder-js:*'

For more details check debug lib and the logz.io wrapper.

How to get contactId/channelId

contactId/channelId can be obtained from every webhook. We are trying to resolve them for you and pass to all methods where they may be needed frequently like state.execute(channelId, contactId, webhook).

const contactId = webhook.data.contact.id
const channelId = webhook.data.channel.id