Building a Conversational Slack Bot with Graphlit
Kaushil Kundalia
March 23, 2024
Guest Author: Kaushil Kundalia (kaushil.kundalia@gmail.com)
Prerequisites:
Slack workspace with admin privileges
Ngrok installed
Install all the requirements
Basic understanding of Flask
Source Code: The code for this tutorial can be found here on GitHub.
Step 1: Setting up your backend
Creating a Flask Server
To build a Slack bot, we will have a backend server that will receive events (aka messages) from Slack, process the event (by calling Graphlit APIs) and respond back by sending a message on Slack. We will use Flask, and Python to build our backend server. Let’s first create a basic Flask server:
Let us break this down. We define a route /slack-incoming
that listens for POST requests. This route is intended to handle incoming events from Slack. Later in the tutorial, we will tell Slack about this endpoint and it will hit this endpoint with an HTTP POST request whenever it receives a new event.
But before that, we need to make sure our endpoint is verifiable by Slack. Slack sends a verification token (challenge) to the specified endpoint to confirm that the server is prepared to receive events.
In the provided code, when our Flask application receives a POST request with this challenge token, it simply reads the token from the incoming JSON payload and responds back with the same token encapsulated in a JSON response, thereby verifying the endpoint's authenticity to Slack.
We can start our server by simply running this as a Python script:
Exposing it to the outside world
Since this is a locally hosted app, our backend service will not be able to communicate with the outside world. To solve this, we create a secure tunnel from the public internet to a local server running on your machine using a tool called ngrok
.
Since our Flask server is running on port 5000, we run:
Here, ngrok exposes your local Flask server to the internet by providing a publicly accessible URL. This URL can then be used to configure Slack's Event Subscriptions, allowing Slack to send event notifications, such as new messages, to your /slack-incoming
endpoint.
Now that our backend is ready, we move over to the next step of setting up our Slack App.
Step 2: Setting up Slack App
Creating a Slack App
Our first step is to create a Slack bot. To do this, head over to Slack API and click on “Create New App”.
And now select “From Scratch”:
Enter your app’s name (which is “Graphlit Bot” here) and select a workspace. Hit “Create App”:
Permissions
Next step is to grant permission that will allow our Graphlit powered app to communicate with Slack via our newly created app. Head over to “OAuth and Permissions”, and add the following “Bot Token Scopes”:
Enabling Events
Next step is to tell Slack about the endpoint on which it will make a POST request whenever an event occurs. Here, we will use the URL that Ngrok created. First turn on the Event Subscriptions and paste the URL (make sure you include the /slack-incoming
endpoint).
Once the URL is verified, will subscribe to new messages coming in a channel. To do this, subscribe to the message.channels
event.
Hit “Save Changes”
This finishes the Slack App setup. Now we will install the app to our workspace.
Installing to Slack Workspace
Navigate to “Basic Information” section and click on “Install your app”.
Once the installation is complete you should be able to see “Graphlit Bot” under “Your apps” section on Slack.
Creating Slack Channel
Finally, let’s create a new channel on Slack and add our bot to it. We will use this channel to run our conversational bot. Here I’ve created a new channel named #graphlit-conversation
and add Graphlit Bot.
Voila!! This concludes our Slack setup. Now let’s dive into the interesting part.
Step 3: Getting started with Graphlit
Getting started with Graphlit is straightforward and easy. Let’s start by creating a new project.
Creating Project on Graphlit
Head over to the Graphlit Developer Portal and create a new project. You can read more information about creating a project here.
We are naming our project “My Project”.
Once you create a project, Graphlit provides an API endpoint on which you can make GraphQL queries. Graphlit provides an API that does all the heavy lifting work behind building an LLM application.
This means that as a developer, you do not need to worry about managing vector databases, generating embeddings, integrating with external data sources, building wrappers over LLM models, etc--Graphlit abstracts away all this.
That’s all the setup you need to get started with Graphlit. Let’s start building our chatbot.
Ingesting Slack messages as Feed
A feed in Graphlit allows you to ingest bulk contents into your Graphlit Project. Feed supports ingestion of multiple types of data such as PDFs, messages, images, audios, videos, and even RSS or Reddit posts. Here we will be using the Slack Feed to ingest messages from Slack into our project, and we will schedule our feel to pull new messages from Slack every minute. We will use this content to create a conversation over it in the subsequent step. But for now, let’s focus on how to create a feed.
Content in Graphlit is referred to as any form of complex or unstructured data such as PDFs, images, Slack messages, Word documents etc.
We will use the createFeed
mutation via the API Explorer. API Explorer provides an in-browser IDE within your Graphlit project that you can use to run your GraphQL queries or mutations.
Request
Variables
Response
Let us jump over to Slack to see our feed work in action.
Request
Variables
Response
Perfect, now that we have data coming in, we will use this to build our conversational chatbot.
Creating Conversation
Conversation on Graphlit is a data model that lets you build chatbot based applications.
Internally a conversation does the following:
When you ingest content, Graphlit will internally create a knowledge graph on it.
A conversation will be across content, based on the optional filter provided with the CreateConversation mutation. If no filter is provided, the conversation will be across all content in your project. It will then use the knowledge graph that makes it easy to converse about the filtered content.
You can prompt a conversation; i.e. you can give a message to a conversation and it will search for relevant content from the knowledge graph, parse it to an LLM & generate a response.
Each time you prompt a conversation, it will add 2 new messages to its knowledge graph (the user message and assistant message) which updates your context.
You can continue a conversation by specifying a conversation id.
Hence using Conversation abstracts away the process of generating vector embeddings, storing to a vector database, running similarity search, etc.
To create a conversation you can run the createConversation mutation. Graphlit will use Azure OpenAI GPT-3.5 Turbo 16k by default to complete the conversation prompts. But you optionally provide a Specification when creating the conversation and select any model from OpenAI, Anthropic, Mistral etc. Notice that we’re using a feeds
filter here. This tells Graphlit on what content to converse over, i.e. the Slack feed.
Request
Variables
Response
Again, we will use the API Explorer to create a conversation and then prompt over that conversation by making calls using Python.
Note the conversation ID as it will be used later.
Step 4: Bringing it all together
Let us recap what we did so far:
Created a Python backend that can receive slack messages
Created a Slack Bot and added it to a channel
Created a Conversation on Graphlit that we will use to build the chatbot
Now let’s glue it all together in our backend.
Reading environment variables
Create a file .env
and provide the following variables:
Import these in the Flask application app.py
.
Authenticating Graphlit API
Graphlit uses JWT based authentication for its API. To create a JWT, you can add the following function in app.py
.
This function returns an HS256 encoded token string, and this token will be passed in the header while making any request to the Graphlit APIs.
Using PromptConversation API
The PromptConversation API facilitates the creation and management of conversational chatbots. PromptConversation API expects a user prompt and returns with essential details, including the LLM response, conversation ID, messages count etc.
Upon receiving a request, the API will fetch relevant data by performing a similarity search on content and past conversation, and generate a response through LLM by using the fetched data. Besides, it will also store the user prompt and the LLM response in embeddings which can be queried upon by future prompts.
Here, we will use gql which is a Python GraphQL client. We wrap calls to Graphlit inside graphlit_request function, that will take a user prompt str as an input, call the PromptConversation API and return the LLM response as a string.
Breaking this down:
We fetch Graphlit tokens by calling
get_graphlit_token
, and then use it to initialize a GraphQL Client.Query and Variables:
As seen in the query, the PromptConversation mutation expects 2 arguments ($prompt: String!, $promptConversationId: ID). The $prompt would be the user message coming from Slack and the $promptConversationId is the conversationId received as a response after we created a conversation. Optionally you can also query Conversations.
And the API will respond with the following fields mentioned in the mutation.
Payload and Request: We wrap the query and variables inside payload and execute the query.
Response: A sample Graphlit API response in this case would look like this
We will extract the LLM response message from the query response in Flask function:
Bringing it all together
Now that our backend is able to authenticate and call the Graphlit API we can now connect it with our slack_challenge()
function to handle incoming messages. Modify the function in app.py
as given below:
The code checks if the incoming payload contains an "event" key, signifying an event notification from Slack. Specifically, for message events without subtypes (i.e., standard messages, not updates or deletions). We extract user and text from the message and pass the text to the graphlit_request to get a response. The response from this operation is then conditionally posted back into the Slack channel, provided the message wasn't sent by the bot itself (thereby preventing the bot from responding to its own messages).
Result
And there we have it!!! Let’s head over to Slack and see the symphony in action.
We now have a production ready Slack bot that can listen to, remember and respond to conversation messages.
Summary
Please email any questions on this tutorial or the Graphlit Platform to questions@graphlit.com.
For more information, you can read our Graphlit Documentation, visit our marketing site, or join our Discord community.