Examples
Below you will find different examples showing the implementation in different use cases. These examples have been compiled based on the community, feel free to post an example that you like or that you think would be useful for new people.
How to Update to the Latest Version
To ensure you're using the most up-to-date features and bug fixes, it's important to keep your BuilderBot installation current. Follow the steps below to update to the latest version. To keep your project up to date, make sure to run the command to update the core and the corresponding provider
pnpm install @builderbot/bot@latest
pnpm install @builderbot/provider-baileys@latest
pnpm install @builderbot/provider-wppconnect@latest
pnpm install @builderbot/provider-venom@latest
pnpm install @builderbot/provider-meta@latest
pnpm install @builderbot/provider-twilio@latest
My first bot
The following code represents the quick use of a bot that when you type the word hi
, greets you with a welcome message and asks you for your name and then returns a funny image
app.ts
import { createBot, createProvider, createFlow, addKeyword, MemoryDB } from '@builderbot/bot'
import { BaileysProvider } from '@builderbot/provider-baileys'
const welcomeFlow = addKeyword<BaileysProvider, MemoryDB>(['hi'])
.addAnswer('Ey! welcome')
.addAnswer('Your name is?', { capture: true }, async (ctx, { flowDynamic }) => {
await flowDynamic([`nice! ${ctx.body}`,'I will send you a funny image'])
})
.addAction(async(_ , {flowDynamic}) => {
const dataApi = await fetch(`https://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true`)
const [imageUrl] = await dataApi.json()
await flowDynamic([{body:'😜', media: imageUrl}])
})
const main = async () => {
const adapterDB = new MemoryDB()
const adapterFlow = createFlow([welcomeFlow])
const adapterProvider = createProvider(BaileysProvider)
adapterProvider.initHttpServer(3000)
await createBot({
flow: adapterFlow,
provider: adapterProvider,
database: adapterDB,
})
}
main()
Conversational history
Often, we will need to manage conversations and keep the context in a memory called state
which is volatile and accessible from any function executed in a stream.
const welcomeFlow = addKeyword(['hello'])
.addAnswer(
"¿What's your name?",
{capture: true},
async (ctx, { flowDynamic, state }) => {
await state.update({ name: ctx.body })
await flowDynamic('Thanks for giving me your name!')
}
)
.addAnswer(
'¿How old are you?',
{capture: true},
async (ctx, { flowDynamic, state }) => {
const name = state.get('name')
await state.update({ age: ctx.body })
await flowDynamic(`Thanks for sharing your age! ${name}`)
}
)
.addAnswer('Here is your data:', null, async (_, { flowDynamic, state }) => {
const myState = state.getMyState()
await flowDynamic(`Name: ${myState.name} Age: ${myState.age}`)
})
Dynamic Messages
In other occasions we need to send messages in a dynamic way of data that can be variable, below you can see an example of how you should do it and how you should NOT do it.
❌ Avoid it this, does not work because addAnswer serializes the content at the start of execution.
let name = ''
const flow = addKeyword('hello')
.addAnswer(`What is your name?`, { capture: true }, async (ctx) => {
name = ctx.body
})
.addAnswer(`Your name is: ${name}`)
If you want to send a dynamic message use flowDynamic.
const flow = addKeyword('hello')
.addAnswer(`What is your name?`, { capture: true }, async (ctx, { state }) => {
await state.update({ name: ctx.body })
})
.addAction(async (ctx, { state, flowDynamic }) => {
const name = state.get('name')
await flowDynamic(`Your name is: ${name}`)
})
Send File
When you want to send an image, audio, file or any other file you can do it this way. It is important to note that the URL must be publicly accessible.
const flow = addKeyword('hello')
.addAnswer(`Send image from URL`,
{ media: 'https://i.imgur.com/0HpzsEm.png' }
)
.addAnswer(`Send video from Local`,
{ media: join(process.cwd(), 'assets', 'sample.png') }
)
.addAnswer(`Send video from URL`,
{ media: 'https://media.giphy.com/media/KWZKwdBC2ODWlQ8kgt/giphy.mp4' }
)
.addAnswer(`Send file from URL`,
{ media: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' }
)
Other ways to use when the route is coming from a dynamic data source
const flow = addKeyword('hello')
.addAction(async (_,{flowDynamic}) => {
// ...db get source...
await flowDynamic([
{body:'This is an image', media:'https://i.imgur.com/0HpzsEm.png'}
])
await flowDynamic([
{body:'This is a video', media:'https://media.giphy.com/media/KWZKwdBC2ODWlQ8kgt/giphy.mp4'}
])
})
If you need to send a file that is stored locally you can do that too. The use of join
is recommended to ensure correct directory concatenation.
const flow = addKeyword('hello')
.addAction(async (_,{flowDynamic}) => {
const pathLocal = join('assets','doc.pdf')
// pathLocal = c:/doc.pdf
await flowDynamic([
{body:'This is a video', media: pathLocal }
])
})
Switch to another flow
If you want to divert a conversational flow to another logic flow based on a response input you can do it in this way:
const flowToA = addKeyword(EVENTS.ACTION).addAnswer('Here we have Option A!')
const flowToB = addKeyword(EVENTS.ACTION).addAnswer('Here we have Option B!')
const flowToC = addKeyword(EVENTS.ACTION).addAnswer('Here we have Option C!')
const flowDefault = addKeyword(EVENTS.ACTION).addAnswer("We don't have that Option 🤔")
const flow = addKeyword('order')
.addAnswer(
[
`Which one is the best option for you?`,
`Type **A**`,
`Type **B**`,
`Type **C**`,
],
{ capture: true }
)
.addAnswer(`Thanks for you answer`,async (ctx, {gotoFlow})=> {
const userAnswer = ctx.body
if(userAnswer === 'A'){
return gotoFlow(flowToA)
}
if(userAnswer === 'B'){
return gotoFlow(flowToB)
}
if(userAnswer === 'C'){
return gotoFlow(flowToC)
}
return gotoFlow(flowDefault)
})
.addAnswer(`this message will not be sent`)
❌ This does not work, the invocation of the gotoFlow function must necessarily include a return.
//...Previous code...
....addAnswer(`Thanks for you answer`,async (ctx, {gotoFlow})=> {
gotoFlow(flowToA)
})
.addAnswer(`this message will not be sent`)
This does work
//...Previous code...
....addAnswer(`Thanks for you answer`,async (ctx, {gotoFlow})=> {
return gotoFlow(flowToA)
})
.addAnswer(`this message will not be sent`)
Turn off bot a certain user
Sometimes we will need to turn off the bot for a certain user, so that we can have a conversation with the client without the bot interfering.
const flow = addKeyword<BaileysProvider>('magic keyword')
.addAction(async (_, { state, endFlow }) => {
const botOffForThisUser = state.get<boolean>('botOffForThisUser')
await state.update({botOffForThisUser:!botOffForThisUser})
if(botOffForThisUser) return endFlow()
})
.addAnswer('Hello!')
Turn off for everyone
Sometimes we will need to disable the bot for all people, without the need to shut down the server or stop the script.
const flow = addKeyword<BaileysProvider>('botoff')
.addAction(async (_, { globalState, endFlow }) => {
const botOffForEveryOne = globalState.get<boolean>('botOffForEveryOne')
await globalState.update({botOffForEveryOne:!botOffForEveryOne})
if(botOffForEveryOne) return endFlow()
})
.addAnswer('Hello!')
Bot Self-Interaction
In certain scenarios, it is necessary for the bot's phone number (host) to be able to interact within logical flows. To achieve this, we have several configurable options:
- host: This is used when you want the bot to be able to respond to messages in the same chat with itself. For example, if the bot's number is 0000, it will be able to send and receive messages to/from 0000.
- both: This option allows both the bot and you (the developer/administrator) to intervene in the chat of a person interacting with the bot.
- none: (default option) Only allows interaction between the user and the bot, without intervention from the host number.
app.ts
import { createBot, createProvider, createFlow, addKeyword, MemoryDB } from '@builderbot/bot'
import { BaileysProvider } from '@builderbot/provider-baileys'
const main = async () => {
const adapterDB = new MemoryDB()
const adapterFlow = createFlow([...])
const adapterProvider = createProvider(BaileysProvider, {
writeMyself: 'host' as 'none' | 'host' | 'both'
})
adapterProvider.initHttpServer(3000)
await createBot({
flow: adapterFlow,
provider: adapterProvider,
database: adapterDB,
})
}
main()