Bots: Basics
WHOAMI
Front End Lead @ Rails Reactor
github.com/viattik
twitter.com/vi_attik
What is Chatbot?
Motivation
• Alternative UX
• ~90% of our time on mobile is spent on email
and messaging platforms
• Cheap and fast to develop
https://chatbotsmagazine.com/the-complete-beginner-s-guide-to-chatbots-8280b7b906ca
Examples
https://t.me/chatwarsbot
Platforms
• Telegram
• Slack
• Messenger
• Viber
• …
+ =
https://github.com/viattik/pokedex-bot
Libraries used
• Telegram:
• https://core.telegram.org/bots
• https://github.com/yagop/node-telegram-bot-
api
• PokeAPI:
• https://pokeapi.co
• https://github.com/PokeAPI/pokedex-promise-
v2
Creating bot
• Register bot via BotFather
• Initialise Telegram and PokeAPI
• Handle message
• Define replies
Creating bot
• Register bot via BotFather
• Initialise Telegram and PokeAPI
• Handle message
• Define replies
const TelegramBot = require(‘node-telegram-bot-api');

const telegram = new TelegramBot(
“YOUR_BOT_TOKEN",
{ polling: true }
);

const PokedexPromise = require('pokedex-promise-v2');
const pokedex = new PokedexPromise();
Creating bot
• Register bot via BotFather
• Initialise Telegram and PokeAPI
• Handle message
• Define replies
function onMessage(message) {

const text = message.text;

getReply(message.chat.id, text).then((reply) => {

if (!reply) { reply = getDefaultReply(); }

telegram.sendMessage(message.chat.id, reply.text, reply.form);
// or telegram.sendPhoto, telegram.sendAudio etc.

});

}
telegram.on('text', onMessage);
Creating bot
• Register bot via BotFather
• Initialise Telegram and PokeAPI
• Handle message
• Define replies
module.exports.intents = {

'/pokemons': (pageNumber = 0) => {

return pokedex.getPokemonsList(getInterval(pageNumber))

.then(({ results }) => {

return {

reply: TEXTS.POKEMON_LIST(pageNumber, results),

form: {

reply_markup: {

keyboard: [

pageNumber === 0

? [ BUTTONS.MAIN_MENU, BUTTONS.NEXT_PAGE ]

: [ BUTTONS.MAIN_MENU, BUTTONS.PREV_PAGE, BUTTONS.NEXT_PAGE ],

],

resize_keyboard: true,

one_time_keyboard: true,

},

}

};

});

},

'/pokemon': (name) => {

return pokedex.getPokemonByName(name)

.then((response) => {

return [

{ replyMethod: 'sendPhoto', reply: response.sprites.front_default },

{ reply: TEXTS.POKEMON(response) }

];

});

},
...
};
https://t.me/JSTonightPokedexBot
+ +
=
https://github.com/viattik/pokedex-bot
https://your_domain.slack.com/apps/manage/custom-
integrations
Libraries used
• Slack:
• https://api.slack.com/bot-users
• https://scotch.io/tutorials/building-a-slack-bot-with-node-js-and-
chuck-norris-super-powers
• https://www.npmjs.com/package/slackbots
• Wit:
• https://wit.ai
• https://github.com/wit-ai/node-wit
• PokeAPI:
• https://pokeapi.co
• https://github.com/PokeAPI/pokedex-promise-v2
wit.ai
• Natural Language Interface
• Is a part of Facebook
• Easy to start
• Alternative - api.ai
Replies
type + type_name + know_about
=
Information about type
contact (pokemon) + know_about
=
Information about
pokemon
contact + weight + know_about
=
Pokemon weight
greetings
=
hi
(and information about
bot if the first call)
thanks
=
you’re welcome
bye
=
bye
answer (yes or no)
=
…
answer (yes or no)
=
depends on previous
message
const slackSettings = {

token: ‘BOT_TOKEN',

name: 'pokedex'

};

const witAccessToken = ‘WIT_TOKEN';



const slack = new Bot(slackSettings);

const wit = new Wit({ accessToken: witAccessToken });

const pokedex = new Pokedex();
slack.on('message', (message) => {

if (isChatMessage(message) && !isMessageFromPokedex(message)

&& (

!isChannelConversation(message)

|| isChannelConversation(message) && isMentioningPokedex(message)

)

) {

const text = removeMentions(message.text);

wit.message(text).then((data) => {

const processed = processIntent(message, data);

if (!processed) {

postReply(message, TEXTS.DIDNT_UNDERSTAND);

}

pushConversation(message, data);

})

}

});
function processIntent(message, data) {

const intents = data.entities;

logIntents(message, data);

if (intents.greetings) {

const user = getUser(message);

const greetingMessages = getMessagesWithIntents(message,
'greetings');

const text = !greetingMessages.length

? TEXTS.FIRST_GREETING(user)

: TEXTS.RANDOM_GREETING(user);

postReply(message, text);

return true;

}

...

}
function processIntent(message, data) {
...



if (intents.know_about && intents.pokemons) {

postReply(message, TEXTS.POKEMONS_INFO);

return true;

}



if (intents.type && intents.type_name && (intents.know_about
|| intents.question)) {

const typeName = intents.type_name[0].value.toLowerCase();

pokedex.getTypeByName(typeName)

.then((response) => {

postReply(message, TEXTS.TYPE(response));

}).catch((error) => {

if (error.statusCode === 404) {

postReply(message, TEXTS.TYPE_NOT_FOUND);

}

});

return true;

}
...

}
function processIntent(message, data) {
...

if (intents.answer) {

const lastMessage = getLastMessage(message);

if (lastMessage && lastMessage.wit.entities.thanks) {

const answer = intents.answer[0].value;

const text = answer.toLowerCase() === 'yes' ?
TEXTS.OK_HIT_ME : TEXTS.ALRIGHT;

postReply(message, text);

return true;

}

}

}
Issues
• Wit.ai works, but needs some learning
• Wit.ai works, but pay attention to ‘BETA’ marks
• Save history - needed for yes-no answers
Where to start?
https://chatbotsmagazine.com/
… and more
• Tools
• https://botmock.com
• https://chatfuel.com
• http://botanalytics.co
• Bots:
• https://www.messenger.com/t/mereminder
• https://www.chatbots.org
• https://tiv.ai/me
https://frameworksdays.com/event/frontend-fwdays-17
Contest
+ =
https://t.me/JSTContestBot

Bots: Basics @ Javascript Tonight, 2017.09.22

  • 1.
  • 2.
    WHOAMI Front End Lead@ Rails Reactor github.com/viattik twitter.com/vi_attik
  • 4.
  • 5.
    Motivation • Alternative UX •~90% of our time on mobile is spent on email and messaging platforms • Cheap and fast to develop https://chatbotsmagazine.com/the-complete-beginner-s-guide-to-chatbots-8280b7b906ca
  • 6.
  • 9.
  • 14.
    Platforms • Telegram • Slack •Messenger • Viber • …
  • 15.
  • 16.
    Libraries used • Telegram: •https://core.telegram.org/bots • https://github.com/yagop/node-telegram-bot- api • PokeAPI: • https://pokeapi.co • https://github.com/PokeAPI/pokedex-promise- v2
  • 17.
    Creating bot • Registerbot via BotFather • Initialise Telegram and PokeAPI • Handle message • Define replies
  • 19.
    Creating bot • Registerbot via BotFather • Initialise Telegram and PokeAPI • Handle message • Define replies
  • 20.
    const TelegramBot =require(‘node-telegram-bot-api');
 const telegram = new TelegramBot( “YOUR_BOT_TOKEN", { polling: true } );
 const PokedexPromise = require('pokedex-promise-v2'); const pokedex = new PokedexPromise();
  • 21.
    Creating bot • Registerbot via BotFather • Initialise Telegram and PokeAPI • Handle message • Define replies
  • 22.
    function onMessage(message) {
 consttext = message.text;
 getReply(message.chat.id, text).then((reply) => {
 if (!reply) { reply = getDefaultReply(); }
 telegram.sendMessage(message.chat.id, reply.text, reply.form); // or telegram.sendPhoto, telegram.sendAudio etc.
 });
 } telegram.on('text', onMessage);
  • 23.
    Creating bot • Registerbot via BotFather • Initialise Telegram and PokeAPI • Handle message • Define replies
  • 24.
    module.exports.intents = {
 '/pokemons':(pageNumber = 0) => {
 return pokedex.getPokemonsList(getInterval(pageNumber))
 .then(({ results }) => {
 return {
 reply: TEXTS.POKEMON_LIST(pageNumber, results),
 form: {
 reply_markup: {
 keyboard: [
 pageNumber === 0
 ? [ BUTTONS.MAIN_MENU, BUTTONS.NEXT_PAGE ]
 : [ BUTTONS.MAIN_MENU, BUTTONS.PREV_PAGE, BUTTONS.NEXT_PAGE ],
 ],
 resize_keyboard: true,
 one_time_keyboard: true,
 },
 }
 };
 });
 },
 '/pokemon': (name) => {
 return pokedex.getPokemonByName(name)
 .then((response) => {
 return [
 { replyMethod: 'sendPhoto', reply: response.sprites.front_default },
 { reply: TEXTS.POKEMON(response) }
 ];
 });
 }, ... };
  • 25.
  • 26.
  • 27.
  • 28.
    Libraries used • Slack: •https://api.slack.com/bot-users • https://scotch.io/tutorials/building-a-slack-bot-with-node-js-and- chuck-norris-super-powers • https://www.npmjs.com/package/slackbots • Wit: • https://wit.ai • https://github.com/wit-ai/node-wit • PokeAPI: • https://pokeapi.co • https://github.com/PokeAPI/pokedex-promise-v2
  • 29.
    wit.ai • Natural LanguageInterface • Is a part of Facebook • Easy to start • Alternative - api.ai
  • 33.
  • 34.
    type + type_name+ know_about = Information about type
  • 35.
    contact (pokemon) +know_about = Information about pokemon
  • 36.
    contact + weight+ know_about = Pokemon weight
  • 37.
  • 38.
  • 39.
  • 40.
    answer (yes orno) = …
  • 41.
    answer (yes orno) = depends on previous message
  • 42.
    const slackSettings ={
 token: ‘BOT_TOKEN',
 name: 'pokedex'
 };
 const witAccessToken = ‘WIT_TOKEN';
 
 const slack = new Bot(slackSettings);
 const wit = new Wit({ accessToken: witAccessToken });
 const pokedex = new Pokedex();
  • 43.
    slack.on('message', (message) =>{
 if (isChatMessage(message) && !isMessageFromPokedex(message)
 && (
 !isChannelConversation(message)
 || isChannelConversation(message) && isMentioningPokedex(message)
 )
 ) {
 const text = removeMentions(message.text);
 wit.message(text).then((data) => {
 const processed = processIntent(message, data);
 if (!processed) {
 postReply(message, TEXTS.DIDNT_UNDERSTAND);
 }
 pushConversation(message, data);
 })
 }
 });
  • 44.
    function processIntent(message, data){
 const intents = data.entities;
 logIntents(message, data);
 if (intents.greetings) {
 const user = getUser(message);
 const greetingMessages = getMessagesWithIntents(message, 'greetings');
 const text = !greetingMessages.length
 ? TEXTS.FIRST_GREETING(user)
 : TEXTS.RANDOM_GREETING(user);
 postReply(message, text);
 return true;
 }
 ...
 }
  • 45.
    function processIntent(message, data){ ...
 
 if (intents.know_about && intents.pokemons) {
 postReply(message, TEXTS.POKEMONS_INFO);
 return true;
 }
 
 if (intents.type && intents.type_name && (intents.know_about || intents.question)) {
 const typeName = intents.type_name[0].value.toLowerCase();
 pokedex.getTypeByName(typeName)
 .then((response) => {
 postReply(message, TEXTS.TYPE(response));
 }).catch((error) => {
 if (error.statusCode === 404) {
 postReply(message, TEXTS.TYPE_NOT_FOUND);
 }
 });
 return true;
 } ...
 }
  • 46.
    function processIntent(message, data){ ...
 if (intents.answer) {
 const lastMessage = getLastMessage(message);
 if (lastMessage && lastMessage.wit.entities.thanks) {
 const answer = intents.answer[0].value;
 const text = answer.toLowerCase() === 'yes' ? TEXTS.OK_HIT_ME : TEXTS.ALRIGHT;
 postReply(message, text);
 return true;
 }
 }
 }
  • 52.
    Issues • Wit.ai works,but needs some learning • Wit.ai works, but pay attention to ‘BETA’ marks • Save history - needed for yes-no answers
  • 53.
  • 54.
  • 55.
    … and more •Tools • https://botmock.com • https://chatfuel.com • http://botanalytics.co • Bots: • https://www.messenger.com/t/mereminder • https://www.chatbots.org • https://tiv.ai/me
  • 56.
  • 57.