A FAQ Chatbot have the purpose of answering the most common questions asked by users. We will build one using and some of its funtionalities, that will help us to build a smarter chatbot. Bard is a chatbot builder framework written in NodeJS/Typescript, but you can use it on your NodeJS/Javascript project too. Bard Conversation Flow We want to develop an intuitive chatbot, that does not depends on its default dialog flow. The conversation must be intuitive. The user must have the option to ask any question at any conversation point, and the chatbot must respond to it. We can achieve that writing a dialog that expects questions and send the respective answers, using the . incoming layer The main part of the conversation will be written using the , where we can manipulate and redirect the interaction between the dialogs. trailing layer Above we have a basic flow. The chatbot asks and waits for the user's question. On user interaction, he will try to get the answer based on his input, then shows the answer if got it, otherwise retry it (maximum of 3 retries). Then the chatbot say bye and ends the conversation. Building it Declaring our Chatbot First of all, we need to setup our project: npm init npm i --save bard-builder express Now we must import and declare our chatbot. Bard Let's create a file named : main.js {Bot} = ( ); main = { bot = Bot({ : }); } main(); const require "bard-builder" const ( ) function /* declare the chatbot instance */ const new name "my-faq-bot" /* here we declare the dialogs */ /* here we start the chatbot */ /* here we setup and start the message gateway */ Organizing our dialogs To start writing our dialogs, we need to put every dialog into a separated file inside a folder named . That will help us to build and visualize the conversation. dialogs └── dialogs ├── root-trailing ├── faq-trailing ├── bye-trailing └── faq-incoming.js .js .js .js Now we have to link all these dialogs in our declared instance. To do that we will need to create another file named . The folder structure will look like this: Bot flow.js └── main └── flow └── dialogs ├── root-trailing ├── faq-trailing ├── bye-trailing └── intent-incoming.js .js // where we declare and setup our chatbot .js // link and setup the dialogs .js .js .js root_trailing = ( ); faq_trailing = ( ); bye_trailing = ( ); intent_incoming = ( ); .exports = { deps = {}; bot.trailing( , root_trailing(deps)); bot.trailing( , faq_trailing(deps)); bot.trailing( , bye_trailing(deps)); bot.incoming( , intent_incoming(deps)); } const require "./dialogs/root-trailing" const require "./dialogs/faq-trailing" const require "./dialogs/bye-trailing" const require "./dialogs/intent-incoming" /* export a function that receives the chatbot as a parameter, then link the dialogs to it */ module ( ) function bot /* this can be used to pass dependencies to dialogs */ const /* link dialogs into our chatbot */ "root" "faq" "bye" "intent" And we need to modify our inside the file to setup the flow: main function main.js {Bot} = ( ); main = { bot = Bot({ : }); setup_flow(bot); } main(); const require "bard-builder" const ( ) function /* declare and setup the chatbot instance */ const new name "my-faq-bot" /* here we start the chatbot */ /* here we setup and start the message gateway */ Writing the dialogs - Root dialog ( ): /dialogs/root-trailing.js Now we can start writing those dialogs. The will be responsible for greeting the user and redirecting to the : empty root trailing dialog faq trailing dialog .exports = { [ { is_known = session.storage.get( ); greeting_message = ; (is_known) greeting_message = ; session.send(greeting_message); session.storage.set( , ); course.replace( ); } ]; } /* export a function that returns the dialog (array of functions) */ module ( ) function deps return ( ) => session, course /* get known data */ const "known_greeting" /* if user already interacted, then send a different message to him */ let "Hello! I am FAQ Chatbot!" if "Hello again!" /* set known to true */ "known_greeting" true /* redirect interation to the faq trailing dialog */ return "faq" - Intent dialog ("/dialogs/intent-incoming.js"): Now we must write our , that will be responsible for understanding the user input and checking if it is a valid question. intent incoming dialog We will need to create a answer-question table to make the user input validation. You can use a configuration file, but we just write it inside the .dialogs/intent-incoming.js file. JSON If the user input is a valid question, then it will save the answer in the session using . session.storage.set(key, value) And since this is an dialog, the interaction won't stop after reach the end. It will continues through until reach the , unless you stop it (manually, omitting at the last step). incoming layer trailing layer course.next() You should substitute that question validation for some cognitive engine. There are many out there, include some free ones. questions_list = { : , : , : }; .exports = { [ { user_input = session.getMessage().data; (!(user_input && user_input.length)) { course.next(); } answer = questions_list[user_input.toLowerCase()]; (answer) { session.storage.set( , answer); course.replace( ); } course.next(); } ]; } const "who are you?" "I am a just a chatbot, that's sad because I even have a name :/" "what is a chatbot?" "Chatbot is a applicati0n th47 coNDuc7 4 c0nv3rS47i0 i7h um4n" "what is your purpose?" "Not to pass butter, sadly." /* export a function that returns the dialog (array of functions) */ module ( ) function deps return ( ) => session, course /* get the user input */ const if return /* check if user input is a valid question, if so save it in session and redirect it to the faq dialog */ const if "answer" return "faq" /* ensure interation to keep going through and reach the trailing layer */ return - FAQ dialog ( ): /dialogs/faq-trailing.js Here we can check for the previous set value on session . If it exists, send the answer. Otherwise send to back to the begin of , if retries reaches more than 2 times, say bye and end the session. answer faq trailing dialog .exports = { [ { have_answer = session.storage.get( ); (have_answer) course.next(); session.send( ); course.wait(); }, (session, course) => { have_answer = session.storage.get( ); (!have_answer) { max_tries = session.storage.get( ) || ; (max_tries >= ) { session.send( ); session.storage.set( , ); course.replace( ); } session.send( ); session.storage.set( , ++max_tries); course.replace( ); } session.storage.set( , ); session.send(have_answer); session.storage.set( , ); course.next(); }, (session, course) => { session.send( ); course.wait(); }, (session, course) => { response = session.getMessage().data; (response != && response != ) { session.send( ); course.replace( ); } course.replace( ); } ]; } /* export a function that returns the dialog (array of functions) */ module ( ) function deps return ( ) => session, course /* if have an answer, jump to the next step */ const "answer" if return "Can I help you?" return const "answer" if /* if retries reaches more than 2 times, say bye and end the session */ let "answer_max_tries" 0 if 2 "I can't help you if I can't understand you." /* reset tries counter */ "answer_max_tries" 0 return "bye" "Sorry, I don't have an answer to that." "answer_max_tries" return "faq" /* reset tries counter */ "answer_max_tries" 0 /* send answer and set its session value to null */ "answer" null return /* ask if want to ask another question */ "Want to ask it again?" return /* if response is yes, redirect to the faq dialog again, if not say bye */ const if "yes" "y" "Alright!" return "bye" return "faq" - Bye dialog ( ): /dialogs/bye-trailing.js Here we say bye to our user. .exports = { [ { session.send( ); session.end() } ]; } /* export a function that returns the dialog (array of functions) */ module ( ) function deps return ( ) => session, course "Goodbye! I hope I've been helpful!" return Message Gateway Now that we have all of dialogs written, we can start writing our message gateway. You can use to insert a or to retrieve a . bot.push(message) outgoing message bot.pull() incoming message To do that, create a file named inside our project folder: gateway.js └── main └── flow └── gateway └── dialogs ├── root-trailing ├── faq-trailing ├── bye-trailing └── intent-incoming.js .js // where we declare and setup our chatbot .js // link and setup the dialogs .js // create the message gateway (receiving and sending messages) .js .js .js Receiving messages You probably are receiving from by a , so we will need to create one (you can use other frameworks, but to simplify we will just use , that is a excellent a reliable framework). message broker webhook "express" Sending messages To send a reply for the messages sent by the , in response to the ones received, we can use function. It will pull a from the . We can do it by creating a pulling system and sending all to our . conversation flow bot.pull() outgoing message conversation flow outgoing messages message broker Gateway: So, we are creating a for receiving the messages and a pulling system to send the messages out to the message broker (your broker) - you can substitute that. We need put the code above inside the previous created file: webhook gateway.js {Message, MessageTypes} = ( ); express = ( ); .exports = { (port, bot) { .port = port; .bot = bot; .message_broker = { : .log( , message.data) }; .server = express(); .server.use(express.json()); .server.post( , (request, response) => { body = request.body; message = Message( body.contact, body.session, body.origin, body.data, MessageTypes.TEXT ); .bot.push(message); response.status( ).send( ); }); .server.listen( .port); } pullProcess() { message = .bot.pull(); (message ) { setTimeout( .pullProcess(), ); } .message_broker.sendMessage(message); setImmediate( .pullProcess()); } } const require "bard-builder" const require "express" module class Gateway constructor this this /* declare message broker (mock) */ this sendMessage ( ) => message console "Simulating sending message:" /* declare webhook server */ this /* to parse JSON body */ this /* declare endpoit for receiving messages */ this "/receive/message" const const new /* use bot.push(message_object) to send a message to the conversation flow */ this return 200 "OK - Message received!" this this /* get message from chatbot */ const this /* if it is an Error instance, re-run this with delay (probably empty) */ if instanceof Error return => () this 500 /* send message to message broker */ this /* re-run this */ return => () this Above we are receiving a from a and creating/inserting the instance into the using . incoming message webhook Message conversation flow bot.push(message) Every time it happens a new interaction is executed in the . conversation flow You can create a switch to handle all incoming message types and set the respective one into the instance. Message We are declaring our and creating a function that calls itself repeatedly to pull messages from the . The pulling function try to get a message, and if fail will wait some time to run again (probably the queue is empty). If succeed, will send the message to our and re-call the function immediately again. Using this mechanism we can ensure that we not lock the thread only by pulling messages. We are re-scheduling these calls to fit wherever it can (using and let the other parts of the code breath and run smoothly. message broker conversation flow message broker setImmediate() And to add this to the chatbot system we must modify our file again: main.js {Bot} = ( ); setup_flow = ( ); Gateway = ( ); main = { bot = Bot({ : }); setup_flow(bot); bot.start(); gateway = Gateway( , bot); gateway.pullProcess(); } main(); const require "bard-builder" const require "./flow.js" const require "./gateway.js" const ( ) function /* declare and setup the chatbot instance */ const new name "my-faq-bot" /* here we start the chatbot */ /* declare gateway (webhook and pulling system) and start pulling messages from bot and sending it to the message broker */ const new 8888 There you have a simple, but smart, FAQ chatbot. Testing it You can make a HTTP request to our created with the message body: webhook POST > http://localhost: /receive/message { : , : , : , : , : } 8888 "contact" "11445917045" "session" "dkioas32902" "origin" "insomnia" "data" "hello!" "type" "text" Then you can send messages to your chatbot and the chatbot output will probably be at your console. These are the questions to ask with a answer: "who are you?" "what is a chatbot?" "what is your purpose?" You can add more chaging the variable in the . questions-list intent incoming dialog Conclusion Now we finished our FAQ chatbot. I recommend you to change the in the for any preferred cognition engine you have. And for the message broker too. There are some good cognition engines and message brokers out there, some of them are free. question-table intent incoming dialog You can evolve this chatbot to something bigger too. No bounds to what you can do here. You can find and example of this tutorial here: FAQ chatbot Also published at https://dev.to/arnaldobadin/how-to-create-a-nodejs-faq-chatbot-d47