What you can achieve with the help of the bot
How to make use of the bot
How to submit your question
Why content moderation is useful
How Quick Replies feature is helping in improving both user and developer experience
How OTN is crucial for the app
How custom Wit.ai model helps in making the interactions with the bot more human like
How NotifyBot persona is useful for sending notifications without confusing the users
How edge cases are handled
Credibility Calculation function
I always wanted to build an app that could help people make good decisions because so many times we see(around us and in our lives) that it is a common problem to get stuck in dilemma about with option to choose in a given situation. A possible solution is to create a polling app that helps people create polls for others to participate in. This way people can get the idea of which option to go for from the poll results. But here's the catch! Do polls really reflect honest, unbiased and un-opinionated results? Clearly polls are good for questions where we want others' individual opinions, for e.g., when we want to how many people prefer a certain product and how many prefer the other one. But when we want help in deciding for ourselves and need a single best choice, we can't rely on these polls because they can be biased, and can reflect individual opinions and beliefs. Some people might just act mischievously and select the option that clearly appears as bad. These create noise in the outcome of the poll. Hence to bring, maybe not perfect, but a good surety that the polls actually represent the wisdom of the crowd as a whole and noise elements are curbed, I mixed the concept of polling app with the concept of credibility scores to incentivize the users to think more rationally while answering in the poll instead of voting based on personal biases or mischievous behavior.
I believe this will help building a community that will in turn help each other solve several common problems in life. That's my goal.
What it does
The bot introduces a new way to interact with each other anonymously on Messenger by creating and answering polls. It lets a person create polls where the user posts a question(using text and optionally images) along with some choices(max 5) for others to vote from. Others can participate in the poll and vote for the option they feel, more feasible and better for the situation. Finally, after the poll is ended, the person who created the poll gets the analysis in the form of a chart. The participants who opted in for getting notified about the results also receive the answer(not complete analysis). All participants will have their credibility scores(explained in next segment) updated and can ask the bot about it(once who opted in to be notified will be notified about the change explicitly, others will have ask the bot themselves to see if any change has come). A user can have only 1 ongoing poll. The bot uses a smart credibility score calculation algorithm to bring good surety that the extreme cases in a poll don't leave much impact on the final outcome. This means that those who vote in favor of more extreme option(by extreme I mean, one that really appears as bad solution) have lesser impact on the poll result.
It needs atleast 2 users to test the above functionalities.
How I built it
- Techstack for this project includes Typescript(Node.js) with Express.js framework, Ejs template engine and PostgresSql Database. I am using a custom trained model from Wit.ai for NLP and Cloud Vision API for image content moderation. For chart, I am making use of Chart.js library.
- I divided the entire app into 2 major flows - asking question/creating poll and answering question/participating in poll. Apart from these 2 flows, there are other minor interactions as well such as Getting Started interaction, Fetching Credibility Scores interaction, Ending an ongoing poll interaction and Greeting interaction. For each interaction, I have implemented a separate function. The 2 major flows are further divided into states. The user while interacting in the flow transitions from one state to another. This states are handled in separate functions as well.
- When user wants to start a new poll, his/her PSID gets stored in a Set data structure(instead of Array of better search time performance) and his/her question gets stored in a Map data structure(instead of simple objects for better search performance). Similarly the options also get stored in separate Map list. Finally, after all the inputs are made, the poll object(containing question and options as well as some extra variables for storing data like PSIDs of users who have voted in this poll) is created and stored on a queue. Now if a user asks for a poll, then a poll which this user has not participated in yet, is fetched.
- The following pic describes the Credibility Scores calculation function - The range of (0, 100) is only for showing credibility scores to users in a decimal point free manner. The actual credibility scores that the database stores for the users is in range (0.5, 1.5) and calculation of points for options use this range only. For e.g., the maximum increase in points for an option due to a single user can be 1.5(slightly less than it) and minimum can be 0.5(slightly more than it).
- I also maintain a DB containing data of which state user is in and to store things like if current user has asked question previously, has answered polls previously,etc so that for users who are completely new, I can present long descriptive messages in every flow to explain things, and for those who have carried out the respective actions before, present short messages. This was to improve user experience.
PS: I made some last minute changes to the bot hence there is very slight difference between how analysis chart is labeled in the video and in the real bot. Also now one can post questions using both texts(atleast 80 alphabetic characters) and images(atmost 2). Lastly the video is slightly fast paced to reduce its length.
How custom Wit.ai model helped in making interactions more natural
Since this is a chatbot experience, hence the only way for users to use its features is through messages. Hence it becomes crucial that these interactions through messages feel natural to the user. The user should be able to talk to the bot without having to structure his/her message in a particular format to get things done. This is where, Wit.ai model plays crucial role. I have made use of custom Wit.ai's NLP model to understand what user wants to do. When that is known, a check is made that which state is the user in, when the message came. This helps the bot knows the context of the interaction with user and what role does his/her current message plays. If the user is in a flow and sends the message to exit it, then the bot understands that the user is in a particular state and wants to exit the state and go back to state 0. Hence appropriate functions are called for that. Similarly when user sends some text which does not correspond to any available commands and the user is currently in the asking question flow, the bot understands that the text is a part of the question user wants to ask, and hence acts accordingly. This way the bot is able to provide natural interaction experience to the users.
How Quick Replies feature helped in improving both developer and user experience
For ensuring that while participating in a poll, the user is able to vote for only one option and is able to do it conveniently without having to write entire option, I am making use of Quick Replies feature of messenger. This greatly improves user experience and eases my job to verify their input, because otherwise I would have to make several checks, since user might not type the entire answer word to word with proper punctuation marks.
How One Time Notification feature is crucial for the app
A user might participate in several polls one after the anther but may not want to get notified of every poll's outcome, hence I have added the interaction to the flow of answering question where the persona bot(I have mentioned in the Challenges section why I used persona) asks if the user wants to get notified. It is very likely that the creator of the poll might leave the poll open for a day or few, hence to ensure that the participants who opted in to get notified actually get notified, I am making use of One Time Notification feature of messenger. This way OTN feature plays a crucial role in the app.
How content moderation is carried out
Since the content that a user posts has the potential to reach a wide audience, it is very important to keep checks on the type of content user is posting.
- For checking questions and the options submitted for any swear words, I am using a Node.js library: bad-words.
- For keeping check on the images that user posts for any nsfw or adult content, I am using Google Cloud Vision API.
- Lastly, for checking that the image user has posted doesn't contain any offensive text, I am using Vision API for text detection and then bad-words library for detecting swear words in the text.
Challenges I ran into
- The biggest challenge was to create the flows and state transitions within them. Since there can multiple users interacting simultaneously, it was a huge challenge to maintain states properly so that all the requests could be handled properly. Organizing the code properly so that it could be extended later was very important. The state transitions of the users was tough to handle since there can be more than one state that user can land to from his/her current state. So this was the part where I spent most of the time thinking how to write the flows and state transitions.
- A major challenge was training custom model in Wit.ai for my bot so that it can distinguish between user commands and user input(questions and choices) flawlessly. Even while in being in the flow of entering question, there is a possibility that user might want to end flow, so I had to ensure that the model was trained enough distinguish between a question and command to end the flow or command to do something else so that the bot can act accordingly. For example if the user enters command to participate in new poll while he/she is in middle of creating a poll then the model should be able to recognize it so that the bot can tell the user to that he/she needs to finish the current flow before starting another.
- There are still some issues with Greetings interaction. Sometimes the bot confuses simple greetings with commands. Eg - 'Hello Bot' is greetings message but 'Hello Bot I would like to start a poll' is not. Hence to avoid confusion, I have trained the bot to recognize the latter statement as command but this has lead to bot not able to recognize greetings sometimes with good confidence. So that's a trade-off I made, to focus more on functionality. But I am working to fix it.
- Design of the Credibility calculation algorithm had to be such so that the new credibility scores of the users are not significantly different from their previous values. Also the change for every user should be different based on how far their option was in terms of total points from the winning option. The further it was, greater should be the decrease and vice-versa. This design was challenging to come up with.
- I also faced an issue related to user experience of the participants who opt in for getting notified about the poll results since its not predetermined when the poll creator will end the poll. So it might happen that some of these participants are in the middle of another flow, maybe creating their own polls, when creator decides to end his/her poll. This is problematic because the participants might get confused, if they are interrupted suddenly with the notification, about whether they should continue writing their question or restart the flow since its interrupted. One solution is to mention something like 'continue with whatever you are doing' at the end of the notification message. This will cover up both the cases when user is in the middle of the flow and when he/she isn't. But if DilemmaBot mentions this type of line in the message, then it makes conversation unnatural because it should appear as if the bot knows what's happening currently. Hence I created a separate persona NotifyBot whose sole job is to send notifications and tell the user to carry on with whatever he/she was doing.
Accomplishments that I'm proud of
- I am very proud that I was able to create a chatbot experience that serves the functionalities of a traditional app using just the messages.
- The concept of Credibility scores might not seem very novel since various apps make use of similar concept in the forms of upvotes/downvotes, likes/dislikes, etc. However I was able to come up with something that could be used with respect to polls, and I am proud of this.
- Being absolute beginner in Machine Learning concepts, this was the first time I worked with NLP. This was challenging because I had to ensure the model was trained enough to distinguish between user questions and commands and not confuse the two as that would lead to bugs.
- I am very happy to be able to build a complete product and not just a prototype. I was able to build the chatbot keeping in mind different ways user can interact with it. I have added mark_seen and typing signals to improve user experience. Although there might be some cases that I am missing but overall it was a great experience building the logical flow of the Messenger experience.
What I learned
- I learnt how to create complex flows for a chatbot experience. The messages that comes from the user do not have the information about the previous conversations hence it was crucial to ensure that the bot keeps track of the conversations and design the state transitions and flows properly so that the interactions with the bot appear smooth instead of artificial. Although the bot replies using pre-programmed texts but how and where the bot uses these texts really makes the conversation very natural. For me building this type of experience was new.
- I learnt to organize code(although I am still not very good at it). I had to write the appropriate functions for handling different states and commands, and it had to be in such a way that I could debug the code and extend it further without much trouble. This was challenging but somehow things worked out.
What's next for DilemmaBot
- I tried to integrate sentiment analysis feature of Wit.ai to classify questions into 2 categories - Light Hearted(positive and neutral) and Serious(negative). However due to lack of expertise and data, I could not train it the way I wanted. The issue was that if a certain text had words like stress in it, then it would get classified as negative even though the issue might not be serious at all. We can't ask the user to tag the question himself/herself as he/she might not give correct tags. Hence I would like to collaborate with an expert in this field and add this feature. This feature would help separate serious issues from others so that they could be given better attention.
- Right now the bot does not work with videos, however its likely that the users may want to use videos while creating polls, so I will work on adding support for this media element to the bot.
- The concept of Credibility Scores does look promising but there are possibilities to improve it. So based on users' feedback I will work on further improving the concept so that I can offer better decision making bot.
- As mentioned in the Challenges section, I still face some issues with the Greetings interaction. So I am working to fix that.
- I have tried to cover many edge cases but still bugs can come up and also there can be more edge cases left to be covered, so I will work on solving those bugs and edge cases.