jazzedge
7/28/2017 - 6:13 AM

Bot - Load Anonymous Dialogs, Recognizers, Events, Intents

Bot - Load Anonymous Dialogs, Recognizers, Events, Intents

//See: https://github.com/DanielEgan/botstarter

SAMPLE CODE FROM: botstarter/server.js
...
let fs = require('fs');
let path = require('path');
let readdir = require('readdir-enhanced');
...
let bot = new builder.UniversalBot(connector, function (session) {
    session.beginDialog('/default');
});

//events
getFileNames('./app/events')
    .map(file => Object.assign(file, { fx: require(file.path) }))
    //for each one, execute the function (what ever the module returns becomes function (fx))
    .forEach(event => event.fx(event.name, bot));

// // recognizers
getFileNames('./app/recognizers')
    .map(file => Object.assign(file, { recognizer: require(file.path) }))
    .forEach(r => bot.recognizer(r.recognizer));

getFileNames('./app/dialogs')
    .map(file => Object.assign(file, { fx: require(file.path) }))
    .forEach(dialog => dialog.fx(dialog.name, bot));
...
//Takes a directory and using fs to loop through the files in the directory
//this is how we get the names of our dialogs. By looking at the file names in the dialogs folder
//it is used the same way for recognizers, actions, etc.
//filter by .js files 
function getFileNames(dir) {
    return readdir.sync(dir, { deep: true })
        .map(item => `.${path.posix.sep}${path.posix.join(dir, path.posix.format(path.parse(item)))}`) //normalize paths
        .filter(item => !fs.statSync(item).isDirectory() && /.js$/.test(item)) //filter out directories
        .map(file => ({ name: path.basename(file, '.js'), path: file }))
}

EXAMPLE: botstarter/APP/DIALOGS/DEFAULT.JS

module.exports = function (name, bot) {
    bot.dialog(`/${name}`, [
        function (session, args, next) {
            session.endDialog("greeting");
        }
    ])
};

EXAMPLE: botstarter/APP/DIALOGS/SAMPLE.JS

//This is an intent dialog. its trigger
//fires when an intent matches name (which corresponds to the file name)
module.exports = function (name, bot) {
    bot.dialog(`/${name}`, [
        function (session, args, next) {
            session.endDialog(`${name} reached`);
        }
    ]).triggerAction({matches:name})//triggered if action matches "name"
};


EXAMPLE: botstarter/APP/DIALOGS/WATERFALL.JS

let builder = require('botbuilder');

module.exports = function (name, bot) {
    bot.dialog(`/${name}`, [
        // should have customer id
        // prompt for future order id
        function (session, args, next) {
            builder.Prompts.choice(session, `Which order?`, "111|222|333", {
                listStyle: builder.ListStyle.button
            });
        },
        function (session, args, next) {
            let futureOrderID = args.response.entity;
            session.endDialog(`edit ${futureOrderID}`);
        }
    ])
        .triggerAction({matches:name})
};

EXAMPLE: botstarter/APPS/EVENTS/conversationUpdate.js

et builder = require('botbuilder');

module.exports = function (name, bot) {
    bot.on(name, function (message) {
        if (message.action === 'add') {
            var name = message.user ? message.user.name : null;
            var reply = new builder.Message()
                .address(message.address)
                .text("Hi. Now we are in conversatin update.");
            bot.send(reply);
        } else {
            // delete their data
        }
    })
};

EXAMPLE: /APPS/EVENTS/contactRelationUpdate.js

let builder = require('botbuilder');

module.exports = function (name, bot) {
    bot.on(name, function (message) {
        if (message.action === 'add') {
            var name = message.user ? message.user.name : null;
            var reply = new builder.Message()
                .address(message.address)
                .text("Hi. Thanks for adding me. Say 'hello' to see what I can do.");
            bot.send(reply);
        } else {
            // delete their data
        }
    })
};


EXAMPLE: botstarter/app/recognizers/greeting.js

const greetings = [
    'hi',
    'hi there',
    'hey',
    'hey there',
    'hello',
    'hello hello',
    'hello there',
    'what up',
    'what\'s up',
    'whatup',
    'salute',
    'morning',
    'good morning',
    'how are you',
    'how r u'
];

module.exports = {
    recognize: function(context, callback) {
        const text = context.message.text.replace(/[!?,.\/\\\[\]\{\}\(\)]/g, '').toLowerCase();
        
        let isGreeting = greetings.some(g => text === g);

        let recognized = {
            entities: [],
            intent: (isGreeting ? 'greeting' : null),
            matched: undefined,
            expression: undefined,
            intents: [],
            score: (isGreeting ? 1 : 0)
        }

        callback.call(null, null, recognized);
    }
};

EXAMPLE:botstarter/app/recognizers/luisSample.js

//you can have multiple luis models you just need to point to seperate enDpoints
//in a different recognizer files
let builder = require("botbuilder");
const envx = require("envx");

module.exports = new builder.LuisRecognizer(envx("LUIS_ENDPOINT"));

EXAMPLE:botstarter/app/recognizers/qna.js

//this recognizer requires a modified version of the botbuilder-cognitiveservices module
//currently living at http://github.com/codefoster/botbuilder-cognitiveservices
//clone repo  - git clone http://github.com/codefoster/botbuilder-cognitiveservices
//In a command window navigate to that repo run :    npm link
//In a command window navigate to this project (botstarter) run npm link botbuilder-cognitiveservices

//You will also need to add your keys from QnAMaker

//you can have multiple QnA makers you just need to have seperate files 
//and different intent names (intentName:"qna2")
const envx = require("envx");
let builder = require("botbuilder");
var bbcs = require('botbuilder-cognitiveservices');

module.exports = new bbcs.QnAMakerRecognizer({
    knowledgeBaseId: envx("QNA_ID"), 
    subscriptionKey: envx("QNA_KEY"),
    intentName: "qna"
});


EXAMPLE:botstarter/app/services/sampleService.js

let customers = [
    { customerId: 1, type: 'tech', name: 'Loretta Rayes', phone: '(345) 501-2527', onCall: true, pendingAppt: false },
    { customerId: 2, type: 'tech', name: 'Gary Foster', phone: '(662) 588-7043', onCall: false },
    { customerId: 3, type: 'customer', name: 'Kenneth Coleman', phone: '(510) 266-3583', pendingAppt: false },
    {
        customerId: 4, type: 'customer', name: 'Tim Hiatt', phone: '(497) 889-1015', pendingAppt: true,
        orders: [
            { orderId: 1, date: '1/31/2016' },
            { orderId: 2, date: '2/14/2017' },
            { orderId: 3, date: '2/23/2017' }
        ]
    }
];

module.exports.customers = customers;

module.exports.findCustomer = function (customerId) {
    return customers.filter(x => x.customerId == customerId);
}