Slide 1

Slide 1 text

@kahwee Coding chatbots in node.js

Slide 2

Slide 2 text

@kahwee Hi, I’m KahWee

Slide 3

Slide 3 text

• @kahwee • JavaScript for the past 5 years • Work for Tremor Video in San Francisco • Responsible for We Build SG chatbot • Likes sushi

Slide 4

Slide 4 text

@kahwee What is a chatbot? A chatbot is designed to perform a task via a chat user interface which is typically text enabled

Slide 5

Slide 5 text

@kahwee Why make a chatbot? • Reduce proximity between customers and businesses • Think personal assistants such as Cortana and Amazon Echo • Think chat messaging interfaces such as Facebook Messenger and Kik

Slide 6

Slide 6 text

@kahwee Why make a chatbot? • Businesses are competing on customer’s attention span over other businesses • ComScore found that average Americans devote half their app time to a single app.

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

@kahwee @TODO List ! Receiving messages from chat service " Comprehending the user’s input # Responding to the user

Slide 9

Slide 9 text

@kahwee ! Receiving messages from
 chat service How to integrate with chat services

Slide 10

Slide 10 text

@kahwee Using requestb.in https://requestb.in/

Slide 11

Slide 11 text

@kahwee ’s outgoing webhook

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

@kahwee Facebook Messenger’s webhook

Slide 16

Slide 16 text

@kahwee Facebook has an additional subscription step

Slide 17

Slide 17 text

@kahwee s

Slide 18

Slide 18 text

@kahwee s

Slide 19

Slide 19 text

@kahwee s c

Slide 20

Slide 20 text

@kahwee { "object": "page", "entry": [ { "id": "309202066131176", "time": 1479910134831, "messaging": [ { "sender": { "id": “1328417810563062" }, "recipient": { "id": “309202066131176" }, "timestamp": 1479910134741, "message": { "mid": "mid.1479910134741:99abab3941", "seq": 4, "text": "Hello How are you doing today?" } } ] } ] }

Slide 21

Slide 21 text

@kahwee Local development using localtunnel and nodemon

Slide 22

Slide 22 text

@kahwee Using localtunnel and nodemon • localtunnel • https://localtunnel.github.io/www/ • Lets you test and develop locally • nodemon • Automatically restarts on change

Slide 23

Slide 23 text

@kahwee Live demo https://github.com/kahwee/ranka-jsconfasia

Slide 24

Slide 24 text

@kahwee " Comprehending the user’s input

Slide 25

Slide 25 text

@kahwee “Book an appointment tomorrow at 4 PM” Using the above as an example

Slide 26

Slide 26 text

@kahwee “Book an appointment tomorrow at 4 PM” • The easiest way to determine the intent is to use rule-based filters on the current application • Example use case — Doctor’s appointment service • Only 2 main functions 1. getAppointments() 2. bookAppointment(datetime)

Slide 27

Slide 27 text

@kahwee Regex!

Slide 28

Slide 28 text

@kahwee /book an appointment/i "Book an appointment tomorrow at 4 PM".match(/book an appointment/i)

Slide 29

Slide 29 text

@kahwee /(book).*(appointment)/i "Book appointment tomorrow at 4 PM".match(/ (book).*(appointment)/i)

Slide 30

Slide 30 text

@kahwee /(book).*(appointment)/i "Book me an appointment tomorrow at 4 PM".match(/ (book).*(appointment)/i)

Slide 31

Slide 31 text

@kahwee /(book|reserve).*(appointment)/i "Reserve my appointment tomorrow at 4 PM".match(/(book| reserve).*(appointment)/i)

Slide 32

Slide 32 text

@kahwee /(arrange|book|reserve).*(appointment)/i "Arrange me an appointment tomorrow at 4 PM".match(/(arrange| book|reserve).*(appointment)/i)

Slide 33

Slide 33 text

@kahwee “Book an appointment tomorrow at 4 PM” We determined we need to use bookAppointment(datetime)

Slide 34

Slide 34 text

@kahwee “Book an appointment tomorrow at 4 PM” • How do we get the parameter “tomorrow at 4 PM”? • Regex isn’t as straightforward any more • There’s A Package For That ™

Slide 35

Slide 35 text

@kahwee Using simple NLP tools

Slide 36

Slide 36 text

@kahwee Using simple NLP tools • We are going to use nlp_compromise which has a parts of speech (POS) tagger • https://github.com/nlp-compromise/nlp_compromise • A POS Tagger is a piece of software that reads text and assigns parts of speech to each word or other token based on both its definition and its context — i.e., its relationship with adjacent and related words in a phrase, sentence, or paragraph. (Wikipedia) There’s A Package For That ™

Slide 37

Slide 37 text

@kahwee I have a pen Parse “I have a pen” with
 nlp_compromise const nlp = require('nlp')
 nlp.sentence('I have a pen').terms.forEach((t) => {
 console.log(t)
 })

Slide 38

Slide 38 text

@kahwee I have a pen Person { whitespace: { preceding: '', trailing: ' ' }, text: 'i', normal: 'i', expansion: null, reasoning: [ 'lexicon_pass', 'is_person' ], pos: { Noun: true, Person: true, Pronoun: true }, tag: 'Person', honourific: null, firstName: null, middleName: null, lastName: null },

Slide 39

Slide 39 text

@kahwee I have a pen Verb { whitespace: { preceding: '', trailing: ' ' }, text: 'have', normal: 'have', expansion: null, reasoning: [ 'lexicon_pass' ], pos: { Verb: true, Infinitive: true }, tag: 'Infinitive' }

Slide 40

Slide 40 text

@kahwee I have a pen Term { whitespace: { preceding: '', trailing: ' ' }, text: 'a', normal: 'a', expansion: null, reasoning: [ 'lexicon_pass' ], pos: { Determiner: true }, tag: 'Determiner' },

Slide 41

Slide 41 text

@kahwee I have a pen Noun { whitespace: { preceding: '', trailing: '' }, text: 'pen', normal: 'pen', expansion: null, reasoning: [ 'fallback' ], pos: { Noun: true }, tag: 'Noun' }

Slide 42

Slide 42 text

@kahwee I have an Person { whitespace: { preceding: '', trailing: ' ' }, text: 'i', normal: 'i', expansion: null, reasoning: [ 'lexicon_pass', 'is_person' ], pos: { Noun: true, Person: true, Pronoun: true }, tag: 'Person', honourific: null, firstName: null, middleName: null, lastName: null },

Slide 43

Slide 43 text

@kahwee I have an Verb { whitespace: { preceding: '', trailing: ' ' }, text: 'have', normal: 'have', expansion: null, reasoning: [ 'lexicon_pass' ], pos: { Verb: true, Infinitive: true }, tag: 'Infinitive' }

Slide 44

Slide 44 text

@kahwee I have an Term { whitespace: { preceding: '', trailing: ' ' }, text: 'a', normal: 'a', expansion: null, reasoning: [ 'lexicon_pass' ], pos: { Determiner: true }, tag: 'Determiner' },

Slide 45

Slide 45 text

@kahwee I have an Term { whitespace: { preceding: '', trailing: '' }, text: '', normal: '', expansion: null, reasoning: [], pos: {}, tag: '?' }

Slide 46

Slide 46 text

@kahwee I have an const gemoji = require('gemoji') console.log(gemoji.unicode[‘']) { description: 'red apple', names: [ 'apple' ], tags: [], name: 'apple', emoji: '' } There’s A Package For That ™

Slide 47

Slide 47 text

@kahwee Initial pass with nlp_compromise • Using nlp_compromise, • Parse “Book an appointment tomorrow at 4 PM” through nlp_compromise

Slide 48

Slide 48 text

@kahwee Book an appointment tomorrow at 4 PM Noun { whitespace: { preceding: '', trailing: ' ' }, text: 'Book', normal: 'book', expansion: null, reasoning: [ 'fallback' ], pos: { Noun: true }, tag: 'Noun' }

Slide 49

Slide 49 text

@kahwee Book an appointment tomorrow at 4 PM Term { whitespace: { preceding: '', trailing: ' ' }, text: 'an', normal: 'an', expansion: null, reasoning: [ 'lexicon_pass' ], pos: { Determiner: true }, tag: 'Determiner' },

Slide 50

Slide 50 text

@kahwee Book an appointment tomorrow at 4 PM Noun { whitespace: { preceding: '', trailing: ' ' }, text: 'appointment', normal: 'appointment', expansion: null, reasoning: [ 'fallback' ], pos: { Noun: true }, tag: 'Noun' },

Slide 51

Slide 51 text

@kahwee Book an appointment tomorrow at 4 PM _Date { whitespace: { preceding: '', trailing: '' }, text: 'tomorrow at 4 PM', normal: 'tomorrow at 4 pm', expansion: null, reasoning: [ 'lexicon_pass', 'lexicon_pass', 'Date-Preposition-Date' ], pos: { Noun: true, Date: true }, tag: 'Date', data: { year: null, month: null, day: null } } ]

Slide 52

Slide 52 text

@kahwee Book an appointment tomorrow at 4 PM Returns “2016-11-21T02:00:00.000Z” Passed through chrono-node There’s A Package For That ™

Slide 53

Slide 53 text

@kahwee Figuring out the date and time Use `chrono-node` const chrono = require(‘chrono-node') const parsed = chrono.parse('feb 23 to mar 2’) console.log(parsed[0].start.date()) // 2017-02-23T20:00:00.000Z console.log(parsed[0].end.date()) // 2017-03-02T20:00:00.000Z

Slide 54

Slide 54 text

@kahwee # Responding to the user

Slide 55

Slide 55 text

@kahwee General rules of thumb • Be succinct • Be friendly • Respect the medium • Handle errors

Slide 56

Slide 56 text

@kahwee Be succinct • Mobile messaging apps are limited by space. The shorter the bot responses are, the better. • Remember emojis are valid responses too! ✅

Slide 57

Slide 57 text

@kahwee Be friendly • Use pronouns like I and You. • Greetings, apologizing and thank you • Remember to greet back • It’s okay to say “Sorry I don’t understand” • Use active instead of passive voice. “Your flight has been booked” is not as good as “I booked your flight.” • Be humble and polite so people won’t be frustrated

Slide 58

Slide 58 text

@kahwee Respect the medium Know what kind of response the messaging API supports. For example, Facebook Messenger supports: • Text • Emoji • Location • Buttons

Slide 59

Slide 59 text

@kahwee Respect the medium • Format using “underscore.string” • toSentence(["jQuery", "Mootools", “Prototype"])
 // => "jQuery, Mootools and Prototype” • prune("Hello, cruel world", 15)
 // => "Hello, cruel..." There’s A Package For That ™

Slide 60

Slide 60 text

@kahwee Respect the medium • Giphy uses buttons in Slack

Slide 61

Slide 61 text

@kahwee Respect the medium • Poncho uses a “Send Location” button that users can tap on instead of typing a city name or postal code in Facebook Messenger

Slide 62

Slide 62 text

@kahwee Respect the medium • We Build SG uses generic templates in Facebook Messenger.

Slide 63

Slide 63 text

@kahwee Respect the medium • Use “ranka” for added expressivity • https://github.com/kahwee/ranka There’s A Package For That ™

Slide 64

Slide 64 text

@kahwee Handle errors “To err is human, to stderr program.”

Slide 65

Slide 65 text

@kahwee Problems faced when building bots 1. Choosing what to build is hard 2. You are encroaching into a personal space such as Facebook Messenger. 3. Every chat messaging system is a medium that can have special characteristics hence different APIs

Slide 66

Slide 66 text

@kahwee Conversational vs Structured text • Conversational text • Less predictable, potentially open-ended • Requires a complex rule-based system or machine learning capabilities

Slide 67

Slide 67 text

Humani: Jessie’s Story • Example of conversational chatbot • By PullString

Slide 68

Slide 68 text

@kahwee Conversational vs Structured text • Structured text • More predictable • Limited functionality

Slide 69

Slide 69 text

We Build SG • Example of structured chatbot • Built by me and We Build SG’s API • Try asking about “upcoming events” to We Build SG

Slide 70

Slide 70 text

@kahwee Sometimes coding it yourself isn’t the right solution

Slide 71

Slide 71 text

@kahwee Bot builders services • Octane AI • api.ai • KeyReply • PullString

Slide 72

Slide 72 text

@kahwee Machine learning and NLP services • luis.ai • wit.ai • api.ai

Slide 73

Slide 73 text

@kahwee Thanks • Spencer Kelly • Spencer Yang • Junshu Okamoto • Sayanee Basu

Slide 74

Slide 74 text

@kahwee Thanks • Source code for the afternoon: • https://github.com/kahwee/ranka-jsconfasia • We Build SG chatbot: • https://github.com/webuildsg/bot • Ranka: • https://github.com/kahwee/ranka