Skip to content

Instantly share code, notes, and snippets.

@slvnperron
Created May 24, 2017 23:33
Show Gist options
  • Save slvnperron/796a684da763792208d78d71d772ba00 to your computer and use it in GitHub Desktop.
Save slvnperron/796a684da763792208d78d71d772ba00 to your computer and use it in GitHub Desktop.
This is an example of how to build a form in Botpress using three different ways
misunderstand:
- I don't understand this.
done:
- 🎈
- We're all done then :)
ask_gender:
- text: What is your gender?
quick_replies:
- <QR_MALE> Male
- <QR_FEMALE> Female
ask_first_name:
- What is your first name?
ask_last_name:
- What is your last name?
ask_profile_ok:
- |
Here's the info I have on you:
> First Name: {{fname}}
> Last Name: {{lname}}
> Gender: {{gender}}
- text: Is this correct ?
quick_replies:
- <PROFILE_RIGHT> Yes, perfect!
- <PROFILE_WRONG> No, fix it
welcome:
- Hello {{user.first_name}} !
- This is a demo of asking questions on messenger.
profile_wrong:
- I am sorry to hear that we got your profile wrong. We will fix that now.
/*
ORIGINAL FLOW MANAGER, CURRENT BOTPRESS VERSION
Description: This is the original bot with the current built-in Flow Manager
Dependencies: This code works as-is. No external dependencies (files).
*/
const dedent = require('dedent')
module.exports = function(bp) {
bp.middlewares.load()
// Listen for the GET_STARTED postback on Facebook Messenger
bp.hear({ text: 'GET_STARTED' }, (event, next) => {
// Send a Welcome message (function is defined below)
sayWelcome(bp, event)
// If there is no conversation that exists for this user yet
if (!bp.convo.find(event)) {
// Start a new conversation (see function below)
askConfirmProfile(bp, event)
}
})
}
function sayWelcome(bp, event) {
// sendText returns a NodeJS Promise (https://www.promisejs.org/)
return bp.messenger.sendText(event.user.id, `Hello ${event.user.first_name} !`)
.then(() => bp.messenger.sendText(event.user.id, 'This is a demo of asking questions on messenger.'))
}
function askConfirmProfile(bp, event) {
const txt = message => bp.messenger.createText(event.user.id, message, { typing: true })
bp.convo.start(event, convo => {
const getProfile = () => ({
fname: convo.get('fname') || event.user.first_name,
lname: convo.get('lname') || event.user.last_name,
gender: convo.get('gender') || event.user.gender
})
const profileTxt = profile =>
txt(dedent`Here's the info I have on you:
> First Name: ${profile.fname}
> Last Name: ${profile.lname}
> Gender: ${profile.gender}`)
const isProfileCorrect = bp.messenger.createText(event.user.id, 'Is this correct ?', {
quick_replies: [
{ title: 'No, fix it', payload: 'PROFILE_WRONG' },
{ title: 'Yes, perfect', payload: 'PROFILE_RIGHT' }
]
})
convo.messageTypes = [ 'text', 'message', 'postback', 'quick_reply' ]
convo.threads['default'].addMessage(() => profileTxt(getProfile()))
convo.threads['default'].addQuestion(isProfileCorrect, [
{
pattern: 'PROFILE_WRONG',
callback: () => {
convo.say(txt('I am sorry to hear that we got your profile wrong. We will fix that now.'))
convo.switchTo('ask')
}
},
{
pattern: 'PROFILE_RIGHT',
callback: () => {
convo.stop('done')
}
},
{
default: true,
callback: () => {
convo.say(txt('Sorry I don\'t understand what you just said.'))
convo.repeat()
}
}
])
convo.createThread('ask')
convo.threads['ask'].addQuestion(txt('What is your first name ?'), [{
default: true,
callback: res => {
convo.set('fname', res.text)
convo.next()
}
}])
convo.threads['ask'].addQuestion(txt('What is your last name ?'), [{
default: true,
callback: res => {
convo.set('lname', res.text)
convo.next()
}
}])
const askGender = bp.messenger.createText(event.user.id, 'What is your gender ?', { quick_replies: [
{ title: 'Guy', payload: 'QR_MALE' },
{ title: 'Girl', payload: 'QR_FEMALE' },
]})
const genderUtterances = {
male: /man|guy|QR_MALE/i,
female: /girl|woman|QR_FEMALE/i
}
convo.threads['ask'].addQuestion(askGender, [
{
pattern: genderUtterances.female,
callback: res => {
convo.set('gender', 'female')
convo.switchTo('default')
}
},
{
pattern: genderUtterances.male,
callback: res => {
convo.set('gender', 'male')
convo.switchTo('default')
}
},
{
default: true,
callback: res => {
convo.say(txt('I don\'t understand this.'))
convo.repeat()
}
}])
convo.on('done', function() {
convo.say('🎈')
convo.say(txt("We're all done then :)"))
})
})
}
/*
SPLIT CONTENT FROM THE FLOW, UPCOMING BOTPRESS v1
Description: This is an attempt at separating the content from the flow logic.
This bot is the same as index.js and does the exact same thing.
The content is logic-less, the flow is content-less.
The goal is that non-developers can edit the content easily,
remove the need to redeploy the app after changing the content,
and also have a much more clean code-base.
Dependencies: Botpress UMM (next branch) || Unstable
DEPENDS on the `content.yml` file, which is the actual content
*/
module.exports = function(bp) {
bp.middlewares.load()
// Listen for the GET_STARTED postback on Facebook Messenger
bp.hear({ text: 'GET_STARTED' }, (event, next) => {
// Send a Welcome message (function is defined below)
event.reply('#welcome')
// If there is no conversation that exists for this user yet
if (!bp.convo.find(event)) {
// Start a new conversation (see function below)
askConfirmProfile(bp, event)
}
})
}
function askConfirmProfile(bp, event) {
bp.convo.start(event, convo => {
const getProfile = () => ({
fname: convo.get('fname') || event.user.first_name,
lname: convo.get('lname') || event.user.last_name,
gender: convo.get('gender') || event.user.gender
})
convo.messageTypes = [ 'text', 'message', 'postback', 'quick_reply' ]
setupDefaultThread(convo, event)
setupAskThread(convo, event)
convo.on('done', function() {
convo.say('#done')
})
})
}
function setupDefaultThread(convo, event) {
convo.threads['default'].addQuestion('#ask_profile_ok', getProfile, [
{
pattern: 'PROFILE_WRONG',
callback: () => {
convo.say('#profile_wrong')
convo.switchTo('ask')
}
},
{
pattern: 'PROFILE_RIGHT',
callback: () => {
convo.stop('done')
}
},
{
default: true,
callback: () => {
convo.say('#misunderstand')
convo.repeat()
}
}
])
}
function setupAskThread(convo, event) {
const genderUtterances = {
male: /man|guy|QR_MALE/i,
female: /girl|woman|QR_FEMALE/i
}
convo.createThread('ask')
convo.threads['ask'].addQuestion('#ask_first_name', [{
default: true,
callback: res => {
convo.set('fname', res.text)
convo.next()
}
}])
convo.threads['ask'].addQuestion('#ask_last_name', [{
default: true,
callback: res => {
convo.set('lname', res.text)
convo.next()
}
}])
convo.threads['ask'].addQuestion('#ask_gender', [
{
pattern: genderUtterances.female,
callback: res => {
convo.set('gender', 'female')
convo.switchTo('default')
}
},
{
pattern: genderUtterances.male,
callback: res => {
convo.set('gender', 'male')
convo.switchTo('default')
}
},
{
default: true,
callback: res => {
convo.say('#misunderstand')
convo.repeat()
}
}
])
}
@slvnperron
Copy link
Author

slvnperron commented May 24, 2017

@jcampbell05 @DanyFS

Here's what I'd like to know:

  1. How do you like the separation of Flow and Content (index.js vs index_umm.js) ?
  2. How could the Flow code be much concise, simpler to write and understand for new comers ?
  3. Is there any limitation in this approach, if we would like to build a much more complex Flow and/or Content ?

Thanks guys

@jcampbell05
Copy link

jcampbell05 commented May 25, 2017

@DanyFS @slvnperron I'm going to port this to Botpress Topics to see what it looks like :)

Not sure about the umm, let me come up with something of how I would believe it should work.

@slvnperron
Copy link
Author

@jcampbell05 umm is already implemented btw

@jcampbell05
Copy link

@slvnperron yeah I like it, just not sure about how we trigger it :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment