GithubHelp home page GithubHelp logo

prg-chatbot's Introduction

Prg-chatbot - Facebook Messenger platform framework

CircleCI

Framework for building reusable chatbot components. Routing, Keyword recognition is built-in.

Requirements and installation

  • requires mongoose > 4.0
  • requires nodejs > 6.0
  • requires express > 4.0
  • requires body-parser > 1.10
$ npm i -S prg-chatbot

Basic setup with Express

It's easy. This basic example can handle everything. Note, that the handler is STRICTLY SYNCHRONOUS.

const express = require('express');
const bodyParser = require('body-parser');
const { createRouter, createProcessor } = require('prg-chatbot/express');

const handler = (req, res, postBack) => {
    res.typingOn()
        .wait();

    switch (req.action()) {
        case 'hello':
            res.text('Hello world');
            return;
        default:
            // send one quick reply
            res.text('What you want?', {
                hello: 'Say hello world'
            })
    }
};

const processor = createProcessor(handler, {
    pageToken: 'stringhere',
    appSecret: 'botappsecret'
});

// app = express();

app.use('/bot', createRouter(processor));

Processing asynchronous actions

How to deal with asynchronous action, when handlers are synchronous? Use postBack(action[, data])).

const handler = (req, res, postBack) => {
    switch (req.action()) {
        case 'downloaded':
            const { data, err } = req.action(true);

            if (err && err.code === 400) {
                res.text('Image size exceeded');
            } else if (err) {
                res.text('Upload failed');
            } else {
                res.text('Hello world');
            }
            return;
        default:
            if (req.isImage()) {
                const resolve = postBack.wait(); // usefull for tests
                bufferloader(req.attachmentUrl(), 1000000)
                    .then(buffer => resolve('downloaded', { data: buffer }))
                    .catch(err => resolve('donwloaded', { err }))
            }
    }
};

Experimental: Router

Router is the way to handle strucured complex bots

const { Router } = require('prg-chatbot');

const app = new Router();

// middleware
app.use('*', (req, res, postBack, next) => {
    res.typingOn()
        .wait();
    next();
});

app.use('actionName', (req, res) => {
    if (req.state.secondAttempt) {
        res.text('hello again');
    } else {
        res.text('hello')
            .setState({ secondAttempt: true });
    }
});

app.use('textAction', /keyword|two-words?/, (req, res) => {
    res.text('Welcome', {
        actionName: 'Say hello' // quick reply
    })
});

API

Classes

Request
Responder
ButtonTemplateBaseTemplate
ReceiptTemplateBaseTemplate
GenericTemplateButtonTemplate
RouterReducerWrapper
ReducerWrapperEventEmitter
Tester
ResponseAssert
AnyResponseAssert
Settings

Functions

bufferloader(url, [limit], [limitJustByBody], [redirCount])

Downloads a file from url into a buffer. Supports size limits and redirects.

attachmentType(response, type, [message])boolean

Checks attachment type

isText(response, [message])boolean

Checks, that response is a text

contains(response, search, [message])boolean

Checks, that text contain a message

quickReplyAction(response, action, [message])boolean

Checks quick response action

templateType(response, expectedType, [message])boolean

Checks template type

waiting(response, [message])boolean

Looks for waiting message

Request

Kind: global class

new Request()

Instance of {Request} class is passed as first parameter of handler (req)

request.senderId

Kind: instance property of Request
Properties

Name Type Description
senderId string sender.id from the event

request.recipientId

Kind: instance property of Request
Properties

Name Type Description
recipientId string recipient.id from the event

request.pageId

Kind: instance property of Request
Properties

Name Type Description
pageId string page identifier from the event

request.state

Kind: instance property of Request
Properties

Name Type Description
state object current state of the conversation

request.isAttachment() ⇒ boolean

Checks, when message contains an attachment (file, image or location)

Kind: instance method of Request

request.isImage([attachmentIndex]) ⇒ boolean

Checks, when the attachment is an image

Kind: instance method of Request

Param Type Default Description
[attachmentIndex] number 0 use, when user sends more then one attachment

request.isFile([attachmentIndex]) ⇒ boolean

Checks, when the attachment is a file

Kind: instance method of Request

Param Type Default Description
[attachmentIndex] number 0 use, when user sends more then one attachment

request.attachment([attachmentIndex]) ⇒ object | null

Returns whole attachment or null

Kind: instance method of Request

Param Type Default Description
[attachmentIndex] number 0 use, when user sends more then one attachment

request.attachmentUrl([attachmentIndex]) ⇒ string | null

Returns attachment URL

Kind: instance method of Request

Param Type Default Description
[attachmentIndex] number 0 use, when user sends more then one attachment

request.isMessage() ⇒ boolean

Returns true, when the request is text message, quick reply or attachment

Kind: instance method of Request

request.text([tokenized]) ⇒ string

Returns text of the message

Kind: instance method of Request

Param Type Default Description
[tokenized] boolean false when true, message is normalized to lowercase with -

Example

console.log(req.text(true)) // "can-you-help-me"

request.quickReply([getData]) ⇒ null | string | object

Returns action or data of quick reply When getData is true, object will be returned. Otherwise string or null.

Kind: instance method of Request

Param Type Default
[getData] boolean false

Example

typeof res.quickReply() === 'string' || res.quickReply() === null;
typeof res.quickReply(true) === 'object';

request.isPostBack() ⇒ boolean

Returns true, if request is the postback

Kind: instance method of Request

request.isReferral() ⇒ boolean

Returns true, if request is the referral

Kind: instance method of Request

request.isOptin() ⇒ boolean

Returns true, if request is the optin

Kind: instance method of Request

request.action([getData]) ⇒ null | string | object

Returns action of the postback or quickreply When getData is true, object will be returned. Otherwise string or null.

  1. the postback is checked
  2. the referral is checked
  3. the quick reply is checked
  4. expected keywords are checked
  5. expected state is checked

Kind: instance method of Request

Param Type Default
[getData] boolean false

Example

typeof res.action() === 'string' || res.action() === null;
typeof res.action(true) === 'object';

request.postBack([getData]) ⇒ null | string | object

Returns action or data of postback When getData is true, object will be returned. Otherwise string or null.

Kind: instance method of Request

Param Type Default
[getData] boolean false

Example

typeof res.postBack() === 'string' || res.postBack() === null;
typeof res.postBack(true) === 'object';

Responder

Kind: global class

new Responder()

Instance of responder is passed as second parameter of handler (res)

responder.text(text, [quickReplys]) ⇒ this

Send text as a response

Kind: instance method of Responder

Param Type Description
text string text to send to user, can contain placeholders (%s)
[quickReplys] object.<string, string>

Example

res.text('Hello %s', name, {
    action: 'Quick reply',
    complexAction: {
        title: 'Another quick reply', // required
        match: 'string' || /regexp/, // optional
        someData: 'Will be included in payload data' // optional
    }
})

responder.setState(object) ⇒ this

Sets new attributes to state (with Object.assign())

Kind: instance method of Responder

Param Type
object object

Example

res.setState({ visited: true });

responder.expected(action) ⇒ this

When user writes some text as reply, it will be processed as action

Kind: instance method of Responder

Param Type Description
action string desired action

responder.image(imageUrl) ⇒ this

Sends image as response. Requires appUrl option to send images from server

Kind: instance method of Responder

Param Type Description
imageUrl string relative or absolute url

Example

// image on same server (appUrl option)
res.image('/img/foo.png');

// image at url
res.image('https://google.com/img/foo.png');

responder.wait([ms]) ⇒ this

Sets delay between two responses

Kind: instance method of Responder

Param Type Default
[ms] number 600

responder.typingOn() ⇒ this

Sends "typing..." information

Kind: instance method of Responder

responder.typingOff() ⇒ this

Stops "typing..." information

Kind: instance method of Responder

responder.seen() ⇒ this

Reports last message from user as seen

Kind: instance method of Responder

responder.receipt(recipientName, [paymentMethod], [currency], [uniqueCode]) ⇒ ReceiptTemplate

Sends Receipt template

Kind: instance method of Responder

Param Type Default Description
recipientName string
[paymentMethod] string "'Cash'" should not contain more then 4 numbers
[currency] string "'USD'" sets right currency
[uniqueCode] string null when omitted, will be generated randomly

Example

res.receipt('Name', 'Cash', 'CZK', '1')
    .addElement('Element name', 1, 2, '/inside.png', 'text')
    .send();

responder.button(text) ⇒ ButtonTemplate

Sends nice button template. It can redirect user to server with token in url

Kind: instance method of Responder

Param Type
text string

Example

res.button('Hello')
    .postBackButton('Text', 'action')
    .urlButton('Url button', '/internal', true) // opens webview with token
    .urlButton('Other button', 'https://goo.gl') // opens in internal browser
    .send();

responder.genericTemplate() ⇒ GenericTemplate

Creates a generic template

Kind: instance method of Responder
Example

res.genericTemplate()
    .addElement('title', 'subtitle')
        .setElementImage('/local.png')
        .setElementUrl('https://www.seznam.cz')
        .postBackButton('Button title', 'action', { actionData: 1 })
    .addElement('another', 'subtitle')
        .setElementImage('https://goo.gl/image.png')
        .setElementAction('action', { actionData: 1 })
        .urlButton('Local link with extension', '/local/path', true, 'compact')
    .send();

ButtonTemplate ⇐ BaseTemplate

Kind: global class
Extends: BaseTemplate

new ButtonTemplate()

Helps with creating of button template Instance of button template is returned by {Responder}

buttonTemplate.urlButton(title, url, hasExtension, [webviewHeight]) ⇒ this

Adds button. When hasExtension is set to true, url will contain hash like: #token=foo&senderId=23344

Kind: instance method of ButtonTemplate

Param Type Default Description
title string button text
url string button url
hasExtension boolean includes token in url
[webviewHeight] string null compact

buttonTemplate.postBackButton(title, action, [data]) ⇒ this

Adds button, which makes another action

Kind: instance method of ButtonTemplate

Param Type Default Description
title string Button title
action string Button action (can be absolute or relative)
[data] object {} Action data

ReceiptTemplate ⇐ BaseTemplate

Kind: global class
Extends: BaseTemplate

new ReceiptTemplate()

Provides fluent interface to make nice Receipts Instance of button template is returned by {Responder}

receiptTemplate.addElement(title, [price], [quantity], [image], [subtitle]) ⇒ this

Adds item to receipt

Kind: instance method of ReceiptTemplate

Param Type Default Description
title string
[price] number 0 a item price
[quantity] number amount of items
[image] string null image of item
[subtitle] string null optional subtitle

GenericTemplate ⇐ ButtonTemplate

Kind: global class
Extends: ButtonTemplate

new GenericTemplate()

Generic template utility

genericTemplate.addElement(title, [subtitle], [dontTranslate]) ⇒ this

Adds element to generic template

Kind: instance method of GenericTemplate

Param Type Default
title string
[subtitle] string null
[dontTranslate] boolean false

genericTemplate.setElementUrl(url, [hasExtension]) ⇒ this

Sets url of recently added element

Kind: instance method of GenericTemplate

Param Type Default
url any
[hasExtension] boolean false

genericTemplate.setElementImage(image) ⇒ this

Sets image of recently added element

Kind: instance method of GenericTemplate

Param Type
image string

genericTemplate.setElementAction(url, hasExtension, [webviewHeight])

Sets default action of recently added element

Kind: instance method of GenericTemplate

Param Type Default Description
url string button url
hasExtension boolean false includes token in url
[webviewHeight] string null compact

genericTemplate.urlButton(title, url, hasExtension, [webviewHeight]) ⇒ this

Adds button. When hasExtension is set to true, url will contain hash like: #token=foo&senderId=23344

Kind: instance method of GenericTemplate

Param Type Default Description
title string button text
url string button url
hasExtension boolean includes token in url
[webviewHeight] string null compact

genericTemplate.postBackButton(title, action, [data]) ⇒ this

Adds button, which makes another action

Kind: instance method of GenericTemplate

Param Type Default Description
title string Button title
action string Button action (can be absolute or relative)
[data] object {} Action data

Router ⇐ ReducerWrapper

Kind: global class
Extends: ReducerWrapper

new Router()

Cascading router

router.use([action], [pattern], ...reducers) ⇒ Object

Appends middleware, action handler or another router

Kind: instance method of Router

Param Type Description
[action] string name of the action
[pattern] RegExp | string | function
...reducers function | Router

Example

// middleware
router.use((req, res, postBack, next) => {
    next(); // strictly synchronous
});

// route with matching regexp
router.use('action', /help/, (req, res) => {
    res.text('Hello!');
});

// route with matching function (the function is considered as matcher
// in case of the function accepts zero or one arguments)
router.use('action', req => req.text() === 'a', (req, res) => {
    res.text('Hello!');
});

// use multiple reducers
router.use('/path', reducer1, reducer2)
   .next('exitAction', (data, req, res, postBack, next) => {
       postBack('anotherAction', { someData: true })
   });

// append router with exit action
router.use('/path', subRouter)
   .next('exitAction', (data, req, res, postBack, next) => {
       postBack('anotherAction', { someData: true })
   });

router.reduce(req, res, postBack)

Reducer function

Kind: instance method of Router
Overrides: reduce

Param Type
req Request
res Responder
postBack function

ReducerWrapper ⇐ EventEmitter

Kind: global class
Extends: EventEmitter
Emits: ReducerWrapper#event:action

new ReducerWrapper()

Solution for catching events. This is useful for analytics.

Example

const reducer = new ReducerWrapper((req, res) => {
    res.text('Hello');
});

reducer.on('action', (senderId, processedAction, text, req) => {
    // log action
});

reducerWrapper.reduce(req, res, postBack)

Reducer function

Kind: instance method of ReducerWrapper

Param Type
req Request
res Responder
postBack function

ReducerWrapper.ReducerWrapper

Kind: static class of ReducerWrapper

new ReducerWrapper([reduce])

Creates an instance of ReducerWrapper.

Param Type Default Description
[reduce] function o => o the handler function

Tester

Kind: global class

new Tester()

Utility for testing requests

tester.res([index]) ⇒ ResponseAssert

Returns single response asserter

Kind: instance method of Tester

Param Type Default Description
[index] number 0 response index

tester.any() ⇒ AnyResponseAssert

Returns any response asserter

Kind: instance method of Tester

tester.lastRes() ⇒ ResponseAssert

Returns last response asserter

Kind: instance method of Tester

tester.passedAction(path) ⇒ this

Checks, that app past the action

Kind: instance method of Tester

Param Type
path string

tester.getState() ⇒ object

Returns state

Kind: instance method of Tester

tester.setState([state])

Sets state with Object.assign()

Kind: instance method of Tester

Param Type Default
[state] object {}

tester.text(text) ⇒ Promise

Makes text request

Kind: instance method of Tester

Param Type
text string

tester.optin(action, [data]) ⇒ Promise

Make optin call

Kind: instance method of Tester

Param Type Default
action string
[data] object {}

tester.quickReply(action, [data]) ⇒ Promise

Send quick reply

Kind: instance method of Tester

Param Type Default
action string
[data] object {}

tester.postBack(action, [data]) ⇒ Promise

Sends postback

Kind: instance method of Tester

Param Type Default
action string
[data] object {}

Tester.Tester

Kind: static class of Tester

new Tester(reducer, [senderId], [processorOptions], [storage])

Creates an instance of Tester.

Param Type Default Description
reducer Router | ReducerWrapper | function
[senderId] string null
[processorOptions] object {} options for Processor
[storage] MemoryStateStorage place to override the storage

ResponseAssert

Kind: global class

new ResponseAssert()

Utility for asserting single response

responseAssert.contains(search) ⇒ this

Checks, that response contains text

Kind: instance method of ResponseAssert

Param Type
search string

responseAssert.quickReplyAction(action) ⇒ this

Checks quick response action

Kind: instance method of ResponseAssert

Param Type
action string

responseAssert.templateType(type) ⇒ this

Checks template type

Kind: instance method of ResponseAssert

Param Type
type string

responseAssert.attachmentType(type) ⇒ this

Checks attachment type

Kind: instance method of ResponseAssert

Param Type
type string

ResponseAssert.AnyResponseAssert#contains(search) ⇒ this

Checks, that response contains text

Kind: static method of ResponseAssert

Param Type
search string

ResponseAssert.AnyResponseAssert#quickReplyAction(action) ⇒ this

Checks quick response action

Kind: static method of ResponseAssert

Param Type
action string

ResponseAssert.AnyResponseAssert#templateType(type) ⇒ this

Checks template type

Kind: static method of ResponseAssert

Param Type
type string

ResponseAssert.AnyResponseAssert#attachmentType(type) ⇒ this

Checks attachment type

Kind: static method of ResponseAssert

Param Type
type string

AnyResponseAssert

Kind: global class

new AnyResponseAssert()

Utility for searching among responses

Settings

Kind: global class

new Settings()

Utility, which helps us to set up chatbot behavior

settings.greeting([text]) ⇒ this

Sets or clears bot's greeting

Kind: instance method of Settings

Param Type Default Description
[text] string false leave empty to clear

settings.getStartedButton([payload]) ⇒ this

Sets up the Get Started Button

Kind: instance method of Settings

Param Type Default Description
[payload] string | object false leave blank to remove button, or provide the action

Example

const settings = new Settings(config.facebook.pageToken);
settings.getStartedButton('/start'); // just an action

settings.whitelistDomain(domains) ⇒ this

Useful for using facebook extension in webviews

Kind: instance method of Settings

Param Type
domains string | Array.<string>

settings.menu([locale], [inputDisabled]) ⇒ MenuComposer

Sets up the persistent menu

Kind: instance method of Settings

Param Type Default
[locale] string "default"
[inputDisabled] boolean false

Example

const { Settings } = require('prg-chatbot');

const settings = new Settings('page-token-string');

settings.menu()
    .addNested('Nested Menu')
        .addUrl('Go to google', 'https://google.com')
        .done()
    .addPostBack('Do something', '/the/action')
    .done();

Settings.Settings

Kind: static class of Settings

new Settings(token, [log])

Creates an instance of Settings.

Param Type
token string
[log] Object

bufferloader(url, [limit], [limitJustByBody], [redirCount]) ⇒

Downloads a file from url into a buffer. Supports size limits and redirects.

Kind: global function
Returns: Promise.

Param Type Default Description
url string
[limit] number 0 limit in bytes
[limitJustByBody] boolean false when true, content size in header is ignored
[redirCount] number 3 maximmum amount of redirects

Example

router.use('*', (req, res, postBack) => {
    if (req.isFile()) {
        bufferloader(req.attachmentUrl())
            .then(buffer => postBack('downloaded', { data: buffer }))
            .catch(err => postBack('donwloaded', { err }))
    }
});

attachmentType(response, type, [message]) ⇒ boolean

Checks attachment type

Kind: global function

Param Type Default Description
response object
type string
[message] string | false "'Attachment type does not match'" use false for no asserts

isText(response, [message]) ⇒ boolean

Checks, that response is a text

Kind: global function

Param Type Default Description
response object
[message] string | false "'Should be a text'" use false for no asserts

contains(response, search, [message]) ⇒ boolean

Checks, that text contain a message

Kind: global function

Param Type Default Description
response object
search string
[message] string | false "'Should contain a text'" use false for no asserts

quickReplyAction(response, action, [message]) ⇒ boolean

Checks quick response action

Kind: global function

Param Type Default Description
response object
action string
[message] string | false "'Should contain the action'" use false for no asserts

templateType(response, expectedType, [message]) ⇒ boolean

Checks template type

Kind: global function

Param Type Default Description
response object
expectedType string
[message] string | false "'Template type does not match'" use false for no asserts

waiting(response, [message]) ⇒ boolean

Looks for waiting message

Kind: global function

Param Type Default Description
response object
[message] string | false "'Should be waiting placeholder'" use false for no asserts

prg-chatbot's People

Contributors

davidmenger avatar vaclavobornik avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.