Sacha: Scheduler Slackbot
Meet Sacha, a Slack bot that schedules meetings with your Slack teammates and sets personal reminders. Just say things like:
- Hey Sacha! Can you set a reminder for tomorrow to call Olivia?
- Yo Sacha, can you set a meeting with @dewgong, @radgups, and @wasavi for next Thursday at 4pm to discuss decorating the house?
and Sacha will work with your Google Calendar and say:
- Okay! I will remind you to call Olivia tomorrow. Is that right?
- Alright! Scheduling a meeting with Duong, Radhika, and Savi for 7/24/17 at 4pm to discuss decorating the house.
Teams are busy. No one has time to check everyone's calendars to find the optimal time to meet, and notify each person to a meeting. What happens if you pick a time and someone now has a conflict? What if you want to make a Google Calendar invite and someone doesn't have a Google calendar? To optimize time efficiency, we built a Slack bot to set personal reminders and manage the tedious task of finding the optimal time to meet, booking the time, and reminding all attendees about meetings prior to the event.
This tool was built as an internal tool for teams. We target any small teams, organizations, and student groups.
This bot was built by Andrew, Audrey, Caroline and myself over four days. We bridged the communication between various tools to build Sacha:
- Express: used to build our server and routes necessary for OAuth and messaging endpoints
- API.AI: a natural language processing API to process incoming client messages and return JSON objects with essential information to set reminders & meetings
- Slack & Slack API: deployed our bot as an app, utilized the real time messaging and web api to send and receive messages
- Google Calendar API: to fetch conflicts, availabilities, send invites, and create events on users' calendars
- MongoDB & Mongoose: to store our meetings, users, and reminders
- Heroku: allowed us to run our cron jobs on a schedule as well as our app
- Trello: our product taskboard to keep our priorities in line and on track for completion.
To organize our workflow, we used Trello to breakdown our vision into digestible milestones and subtasks.
- User initiates a message with Sacha via Slack. Using Real Time Messaging (RTM) and Express, we receive the message and gather the user's information. If the user doesn't exist (#1), we create them and ask for Google Calendar access. After authenticating, we store their tokens and Slack information into a MongoDB document.
- Now that we have record of the user (#2), we allow them to either schedule a reminder or meeting with other team members. When the user initiates the request, the request is stored in a pending state in the user document until the request is fully confirmed. The hits an endpoint, where an axios request is made to api.ai where the message is parsed into useful information to schedule the meeting. Through api.ai's training, we were able to train our agent to map the user's queries to the correct parameters. Utilizing the followups and context features, we are able to check if the required parameters to make the meeting (i.e. time, subject, attendees, date) have been provided before we allow the user to set the meeting, and will prompt the user if insufficient information has been provided. The information comes back through our messaging endpoint.
- When the request is ready for scheduling, we ensure that there are no time conflicts on any of the attendee's calendars. First, we look through MongoDB for our attendees. If they exist, we use their Google OAuth information to access their calendars and grab their conflicts (if any) and events for the next seven days (in case we need to recommend free times). If they don't exist, we find their Slack DM Id using the passed through Slack Id and prompt them to authorize Google Calendar. On the other hand, the organizer is notified that the pending request cannot go through and a cron job is run to check back every 5 minutes to see if all Google Calendars have been authorized. Within two hours, if they have been authorized, we check for conflicts by gathering every person's conflicts within the requested time slot, otherwise we cancel the request to allow the organizer to make new requests.
- In order to recommend times that would work for every person, we request a list of events for each person via the Google Calendar API for the coming seven business days and find slots where there are no conflicts between. We then return 10 times that work. When we've found a time slot that works for everyone (there are no conflicts), the user is then allowed to book the meeting where we store the event as a Meeting document and post it to every person's Google Calendars via the Google Calendar API.
- Asynchronous Difficulties: while aiming to retrieve information from multiple sources in succession, we ran into difficulties with asynchronous calls, leading us into callback hell and issues with returning all the requested information.
- Synthesizing multiple APIs: our bot made calls to various APIs. Managing the amount of data and async calls became difficult at times. That's when we created Promises and utilized Promise.all to retrieve information.
- Managing multiple states: after submitting a request for an event or reminder, we moved that request to a "pending" state. That would enable us to do a few last checks and run our cron jobs to ensure that the requested slot was available and that we could schedule an event across multiple people's calendars. This became difficult since we were storing our state in our database and managing this for each request.
- Code design and delegation: working in a team to create this bot was difficult since there were so many moving pieces. At first, we were progressing feature by feature as a team of four. However, we soon realized it was unproductive since we were more or less working off one computer. We then began to delegate various features and wrote helper functions on separate files which could be easily integrated into the main file by requiring. Our code was ultimately commented for readability.
- More AI training: we utilized API.AI for our natural language processing. Though our bot currently evaluates most of our speech, we hope to further train it to learn all possible event subjects as well as names.
- Better structure work flow: we became comfortable with delegating features as helper functions later in the development process. However, we believe there are better options to task delegation and aim to improve on our current process.
- Version management: as we improve upon our development, we look to better track our versions and preserve working versions in various states. We currently create branches for features and should preserve working versions in allocated branches.