Developing and deploying a Slack bot

In this article, we'll walk through the process of developing a Slack bot in Python using popular libraries and frameworks like Flask and the Slack SDK. We'll start by choosing the tools needed to build the bot and walk through the development process step-by-step, from setting up the environment and writing the code to testing and deploying to the server.

What will our Slack bot do?

Our Slack bot will be a multifunctional tool integrated into Slack workflows. It will have the following functionality:

  1. Greeting and interacting with users:

    • Upon receiving the command /hellothe bot sends a personalized greeting and provides interactive options. The user is offered a choice between receiving a weather report or an overview of current tasks through interactive interface elements.

  2. Getting weather forecast:

    • On command /weather or by selecting the “Get weather” button, the bot receives data on the current weather in the specified city (Moscow by default) and sends it to the user.

  3. Task Management:

    • The bot allows users to add tasks to the database and view them via the command /taskor via the corresponding button. This is useful for organizing personal matters and small tasks right inside Slack.

  4. Reaction to messages:

    • The bot can respond to certain text messages (such as “hello”) by sending an appropriate response to the channel.

Deployment we will implement in Amveraas it is a cloud + app engine, where deploying and updating projects is much easier than setting up a VPS. Deployment is done via git push amvera master (or via drag and drop in the interface), and everything is configured and deployed by itself.

Selecting tools and setting up the environment

Before we start developing our Slack bot, we need to select the right tools and set up a development environment. We will be using Python 3, which has a powerful set of libraries and frameworks for working with APIs and creating web applications. Let's look at the main components that will be needed to develop our bot:

1. Python and libraries

To create the bot we will use the following libraries:

  • Flask – It is a popular web framework for Python that allows you to easily create web applications and APIs. In our case, Flask will be used to handle HTTP requests from Slack.

  • Slack SDK – A set of tools provided by Slack to interact with their API. With it, we can send and receive messages, process commands and events.

  • Requests – A lightweight library for making HTTP requests. We'll use it to interact with external APIs, such as the weather service.

  • python-dotenv -This library allows you to load sensitive data (such as tokens and API keys) from a file. .env. This is important for the security of your project.

  • SQLite -Built-in Python database that will be used to store tasks added by users. SQLite is easy to use and ideal for small projects.

2. Install Python and pip

If you don't have Python 3 installed yet, download and install it from the official website python.org. Along with Python, a package manager will also be installed. pipwhich will be needed to install the required libraries.

Check that Python and pip are installed by running the following commands in the terminal:

python3 --version 
pip3 --version

3. Creating a virtual environment

To avoid conflicts with other projects and isolate dependencies, let's create a virtual environment for our bot. This can be done using the command:

python3 -m venv venv

Then activate the virtual environment:

venv\Scripts\activate
source venv/bin/activate

After activating the virtual environment, you will see the prefix (venv) before the command line interface.

4. Installing dependencies

Create a file requirements.txtwhich will list all the necessary libraries:

Flask==3.0.3 
slack-sdk==3.11.0 
requests==2.26.0 
python-dotenv==0.19.2

Install all dependencies with the command:

pip install -r requirements.txt

5. Creating a .env file

To store confidential data, create a file .env in the root of your project. This file should not be in version control, so add it to .gitignore.

Example of file content .env:

SLACK_BOT_TOKEN=YOUR_SLACK_BOT_TOKEN  
  
SLACK_SIGNING_SECRET=YOUR_SECRET_SLACK_BOT_TOKEN  
  
WEATHER_API_KEY=YOUR_WEATHER_BOT_TOKEN

6. Setting up Git and .gitignore

To ensure that your project is protected from accidentally adding sensitive data to version control, such as API tokens and environment settings, it is important to set up .gitignore. This file specifies which files and directories Git should ignore so that they don't end up in your repository.

7. Initializing the Git repository

If you haven't yet initialized a Git repository in your project, do so by running the following command in the project's root folder:

git init

This command will create a hidden directory .gitwhich will store all the information about your repository.

8. Creating and configuring .gitignore

Create a file .gitignore in the root directory of your project. This file should contain all the files and directories that should not be tracked by Git.

Here is an example of the file contents .gitignore:

# Игнорируем виртуальное окружение 
venv/  
# Игнорируем конфиденциальные файлы 
.env  
# Игнорируем файлы кеша и временные файлы 
__pycache__/ 
*.pyc  
# Игнорируем файлы редакторов кода 
.idea/`
  • venv/: This line tells Git to ignore the virtual environment directory so that virtual environment files are not pushed into the repository.

  • .env: This file contains your sensitive data such as API tokens and access keys. Adding it to .gitignore prevents accidental leakage of this data.

  • __pycache__/ And *.pyc: These files and directories are created by Python for bytecode caching and do not need to be stored in the repository.

  • Editing files: If you use an IDE like VS Code or PyCharm, they may create service directories (*.vscode/, .idea/), which are also not needed in the repository.

9. Checking .gitignore

After creation .gitignore execute the command git statusto ensure that the files specified in .gitignoreno longer appear in the list of files to commit.

git status

If everything is set up correctly, you will not see ignored files in the list, such as venv/ And .env.

10. Setting up the configuration file

Create a file config.pywhich will load data from .env and store them in variables:

import os from dotenv 
import load_dotenv  

load_dotenv()  

SLACK_BOT_TOKEN = os.getenv("SLACK_BOT_TOKEN") 
SLACK_SIGNING_SECRET = os.getenv("SLACK_SIGNING_SECRET") 
WEATHER_API_KEY = os.getenv("WEATHER_API_KEY")`

Now that your environment is set up, you're ready to start building your Slack bot! In the next section, we'll start implementing the basic functionality of our bot.

Implementing the Basic Structure of a Slack Bot

Now that we have the environment and configuration files set up, we can begin implementing the basic structure of our Slack bot. In this section, we will create the basis of our bot using Flask and the Slack SDK. We will set up how to handle commands, send messages, and interact with users.

1. Creating a project structure

For ease of development and code support, it is important to organize the project in accordance with generally accepted standards. Let's create the following directory and file structure:


`slack_bot/ 
│ 
├── app.py              # Главный файл приложения 
├── config.py           # Конфигурационный файл 
├── requirements.txt    # Зависимости проекта
├── .env                # Файл с переменными окружения 
├── .gitignore          # Файл для исключения из контроля версий
├── venv/               # Виртуальное окружение 
└── __pycache__/        # Кэш Python (будет создан автоматически)`

2. Setting up a Flask application

File app.py will be the main file of our bot. In it, we will set up a Flask application and connect the Slack SDK to handle events and commands. Let's start by writing the code that will set up the server and provide basic processing of Slack commands.

The Flask application is a web server that will accept HTTP requests from Slack, process commands, and send responses via the Slack API. We also use the Slack SDK library to manage events and messages.

Let's start our development with imports and creating an application:

from flask import Flask, request, jsonify
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
import logging
from weather import fetch_weather
from db import init_db, add_task, get_tasks
from config import SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET

# Создание Flask-приложения
app = Flask(__name__)

# Инициализация Slack клиента с токеном бота
client = WebClient(token=SLACK_BOT_TOKEN)

# Настройка логирования для удобства отладки
logging.basicConfig(level=logging.INFO)

# Инициализация базы данных для задач
init_db()
  • Flask application: Initializes a Flask instance that will handle requests from Slack.

  • Slack SDK: Client is used WebClient to send messages in Slack.

  • Logging: Allows you to track the bot's operation and possible errors.

  • Initializing the database: The function is called init_db to create tables.

Now let's move on to Slack's command handler:

@app.route('/slack/command', methods=['POST'])
def command_handler():
    # Получение данных о команде
    data = request.form
    command = data.get('command')
    user_id = data.get('user_id')

    # Определение команды
    if command == '/hello':
        return hello_command(user_id)
    elif command == '/weather':
        return weather_command(user_id)
    elif command == '/task':
        return task_command(user_id)
    else:
        return jsonify(response_type="ephemeral", text="Команда не поддерживается."), 200
  • Routes: Flask accepts requests by route /slack/command.

  • Teams: The bot processes commands /hello, /weatherAnd /taskcalling the appropriate functions. It's time to get to the command handlers for our bot

Command processing /hello:

def hello_command(user_id):
   try:
       client.chat_postMessage(
           channel=user_id,
           text="Привет! Как я могу помочь вам сегодня?",
           attachments=[
               {
                   "text": "Выберите опцию:",
                   "fallback": "Выберите опцию",
                   "callback_id": "hello_options",
                   "actions": [
                       {
                           "name": "option",
                           "text": "Получить погоду",
                           "type": "button",
                           "value": "weather"
                       },
                       {
                           "name": "option",
                           "text": "Просмотреть задачи",
                           "type": "button",
                           "value": "tasks"
                       }
                   ]
               }
           ]
       )
       return jsonify(response_type="in_channel", text="Опции отправлены."), 200
   except SlackApiError as e:
       logging.error(f"Ошибка отправки сообщения: {e.response['error']}")
       return jsonify(response_type="ephemeral", text="Произошла ошибка при отправке сообщения."), 500
  • Sending messages: Slack bot sends a message asking you to select an action via buttons.

  • Action buttons: The user can select actions to get the weather forecast or view tasks.

Handling interactive actions:

@app.route('/slack/interactive', methods=['POST'])
def interactive_handler():
    payload = request.json
    actions = payload.get('actions', [])
    action = actions[0] if actions else None

    if action and action['value'] == 'weather':
        return weather_command(payload['user']['id'])
    elif action and action['value'] == 'tasks':
        return task_command(payload['user']['id'])
    else:
        return jsonify(text="Неизвестное действие."), 200

Command handler /weather:

def weather_command(user_id):
    weather_info = fetch_weather()
    try:
        client.chat_postMessage(
            channel=user_id,
            text=weather_info
        )
        return jsonify(response_type="in_channel", text="Прогноз погоды отправлен."), 200
    except SlackApiError as e:
        logging.error(f"Ошибка отправки сообщения: {e.response['error']}")
        return jsonify(response_type="ephemeral", text="Произошла ошибка при отправке сообщения."), 500

  • Weather: Bot calls a function fetch_weatherwhich returns the weather forecast and sends it to the user in Slack.

Command processing /task:

def task_command(user_id):
    tasks = get_tasks(user_id)
    if tasks:
        tasks_list = "\n".join([task[0] for task in tasks])
        message = f"Ваши задачи:\n{tasks_list}"
    else:
        message = "У вас нет задач."

    try:
        client.chat_postMessage(
            channel=user_id,
            text=message
        )
        return jsonify(response_type="in_channel", text="Список задач отправлен."), 200
    except SlackApiError as e:
        logging.error(f"Ошибка отправки сообщения: {e.response['error']}")
        return jsonify(response_type="ephemeral", text="Произошла ошибка при отправке сообщения."), 500

Handling Slack events:

@app.route('/slack/events', methods=['POST'])
def slack_events():
    if 'challenge' in request.json:
        return jsonify({'challenge': request.json['challenge']})

    event = request.json.get('event', {})
    
    if event.get('type') == 'message' and not event.get('bot_id'):
        user = event.get('user')
        text = event.get('text')
        channel = event.get('channel')

        if 'привет' in text.lower():
            try:
                client.chat_postMessage(
                    channel=channel,
                    text=f"Привет, <@{user}>! Как дела?"
                )
            except SlackApiError as e:
                logging.error(f"Ошибка отправки сообщения: {e.response['error']}")

    return '', 200
  • Events: The bot responds to text messages sent by users and replies if the user writes “hello”.

The most important thing remains – this is the launch of our application

if __name__ == "__main__":
    app.run(port=3000)

weather.py file

File weather.py contains logic for getting up-to-date weather information using an external API. We use the OpenWeatherMap service, which provides weather data for cities, such as temperature, weather conditions, and other metrics.

import requests
from config import WEATHER_API_KEY

# Функция для получения данных о погоде
def fetch_weather(city="Москва"):
    # Формирование URL для запроса к API OpenWeatherMap
    url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={WEATHER_API_KEY}&units=metric&lang=ru"
    
    # Выполнение GET-запроса к API
    response = requests.get(url)
    
    # Преобразование ответа в JSON
    data = response.json()
    
    # Проверка успешности запроса
    if response.status_code == 200:
        weather = data['weather'][0]['description']  # Описание погоды
        temperature = data['main']['temp']  # Температура
        return f"Погода в {city}: {weather}, {temperature}°C"
    else:
        return "Не удалось получить данные о погоде."

Key points of the code:

  1. OpenWeatherMap API: We use the public API of the OpenWeatherMap service to get weather data. This requires an API key, which is stored in the configuration file config.py.

  2. Request weather data: Function fetch_weather takes a city (default is “Moscow”) and makes an HTTP request to get current weather data. The API returns data in JSON format, which we process.

  3. Processing the response: If the request is successful (response code 200), the function returns a string with a description of the current weather and temperature. In case of an error, a message is returned about the impossibility of obtaining data.

Explanation of working with OpenWeatherMap:

This file is used for integration with an external service and is used in the main application (app.py) to send a weather forecast to a user in Slack.

Once you have a basic Flask application set up, the next step is to hook up other components, such as working with a database for tasks and setting up an API for getting weather data, which we'll cover in the following sections.

3. Setting up a database for tasks

To manage tasks in our Slack bot, we will use SQLite, an embedded database that is great for small projects. The database will store user tasks, and the bot will be able to add and retrieve them on demand.

Let's create a file db.pywhich will contain the logic for working with the database:

import sqlite3  
  
def init_db():  
    conn = sqlite3.connect('bot.db')  
    cursor = conn.cursor()  
    cursor.execute('''  
        CREATE TABLE IF NOT EXISTS tasks (            id INTEGER PRIMARY KEY,            user_id TEXT NOT NULL,            task TEXT NOT NULL        )    ''')  
    conn.commit()  
    conn.close()  
  
def add_task(user_id, task):  
    conn = sqlite3.connect('bot.db')  
    cursor = conn.cursor()  
    cursor.execute('INSERT INTO tasks (user_id, task) VALUES (?, ?)', (user_id, task))  
    conn.commit()  
    conn.close()  
  
def get_tasks(user_id):  
    conn = sqlite3.connect('bot.db')  
    cursor = conn.cursor()  
    cursor.execute('SELECT task FROM tasks WHERE user_id = ?', (user_id,))  
    tasks = cursor.fetchall()  
    conn.close()  
    return tasks

Key points of the code:

  1. Initializing the database: Function init_db creates a table tasksif it does not already exist. The table will store tasks that are associated with the user through his user_id.

  2. Adding tasks: Function add_task adds a new task to the database, associating it with the user via user_id.

  3. Getting a list of tasks: Function get_tasks Returns all tasks that the user has added to the database.

Now that we have the code to work with the database, we can integrate it into our main application (app.py). The bot will respond to commands /taskadding new tasks or returning the user's task list.

To fully operate our Slack application and interact with the API, we need to take the final step, namely, get several tokens for all APIs to work.

How to get the required tokens?

To run your Slack bot, you will need three tokens:

  1. SLACK_BOT_TOKEN — your bot's token for interacting with the Slack API.

  2. SLACK_SIGNING_SECRET — a secret to verify the authenticity of requests from Slack.

  3. WEATHER_API_KEY — API key for getting weather data from OpenWeather.

1. How to get SLACK_BOT_TOKEN

  1. Go to API.Slack (api.slack.com) and sign in to your Slack account.

  2. Select or create an application for your bot.

  3. In the menu on the left, go to the section OAuth & Permissions.

  4. Scroll down to the section OAuth Tokens for Your Workspace.

  5. Click Install App to Workspace and confirm the permissions.

  6. After successful installation you will be provided Bot User OAuth Token – this is yours SLACK_BOT_TOKEN. Save it.

2. How to get SLACK_SIGNING_SECRET

  1. On the same app page in the Slack dashboard, go to Basic Information.

  2. Scroll down to the section App Credentials.

  3. There you will find a field Signing Secret. This is yours. SLACK_SIGNING_SECRET. Copy and save it.

3. How to get WEATHER_API_KEY

  1. Go to the OpenWeather website and register if you don't have an account.

  2. After registration, log in to your account and go to the section API keys.

  3. Create a new key or use an existing one. This key will be yours. WEATHER_API_KEY.

4. Testing on a local server

To test our bot on your local machine, run the command:

python app.py

Your Flask app will run on port 3000. However, in order for Slack to send events to your bot, it must be accessible from the internet. For this, you can use the tool ngrokwhich will create a tunnel to your local server

Installing and Configuring Ngrok on Mac and Windows

Ngrok is a tool that allows you to create a secure tunnel from your local server to the public internet. This is useful for developing web applications and bots when you need to test webhooks or integration with external services, such as Slack.

Step 1: Install Ngrok

Installing on Mac

  1. Open terminal and install Homebrew (if it is not already installed) using the command:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  1. Install ngrok using Homebrew:

brew install ngrok/ngrok/ngrok
  1. Check that ngrok is installed:

ngrok version

Installation on Windows

  1. Download the latest version of ngrok from the official website: ngrock

  2. Unzip the file ngrok.zip.

  3. Move the file ngrok.exe to any directory of your choice, for example, C:\ngrok.

  4. Open Command line (cmd) and go to the directory with ngrok:

cd C:\ngrok
  1. Check your ngrok version:

ngrok version

Step 2: Authentication in Ngrok

Ngrok requires authentication to manage tunnels through your account.

  1. Register on the website ngrok.com.

  2. On the main page of your account, copy your auth token.

  3. Enter the following command in Terminal (on Mac) or Command Prompt (on Windows) to connect your account to ngrok:

ngrok config add-authtoken YOURTOKEN

Replace YOUR_TOKEN to your token copied from your ngrok account.

Step 3: Launch Ngrok

Now that ngrok is installed and authenticated, you can start the tunnel.

  1. Make sure your Flask application is running on port 3000:

 python app.py
  1. Open a terminal (or command line) and run ngrok to proxy your local server:

ngrok http 3000

After launching, we will receive a window like this with all the data on our bot.

You can now use this URL to set up webhooks and interact with Slack.

Step 4: Set Up Slack

  1. Go to your app's control panel at api.slack.com/apps.

  2. In the menu on the left, select Event Subscriptions.

  3. Turn on events by flipping the switch Enable Events.

  4. In the field Request URL paste the public URL that ngrok gave you, adding to it /slack/events. For example:

http://your-ngrok-url.ngrok.io/slack/events
  1. Slack will now begin checking the URL. If everything is OK, you can continue setting up events.

  2. Scroll down to the section Subscribe to Bot Events and add the events you need, such as message.im (to receive private messages).

  3. Save your changes and your app will now receive events from Slack via ngrok.

The bot is now configured to interact with Slack via a local server!

Deployment to Amvera servers

After successfully testing your Slack bot on a local server using ngrok, the next step is to deploy it to a remote server to ensure it is available 24/7 and free from dependence on your local machine.
In this section we will look at the deployment process to servers. Amveraincluding setting up a virtual machine, installing dependencies, and configuring the application to start automatically.

Why Amvera?

  • this is our blog)

  • Deploying code and rolling out updates is much easier than setting up a VPS. Basic CI/CD is already built in and is performed via git push amvera master

  • There are many built-in features that make it easier to use (free SSL certificates, database clusters with backups, etc.).

Registration in the service

  1. Create an account:

  2. Project setup:

    • Give your project a name (preferably in English).

    • Select a tariff plan. The most basic tariff will be enough to deploy the bot.

    • The initial balance will be enough for our bot to work for free and continuously for the first time.

  3. Preparing code for deployment:

  • Amvera uses git to deliver code to the cloud. You will need to create a configuration file amvera.ymlwhich will tell the cloud how to run your project.

  • To make it easier to create this file, use graphic generation tool.

    Setting the configuration

  • Selecting environment and dependencies:

    • Specify the Python version and path to the file requirements.txtwhich contains all the necessary packages.

    • Specify the path to the main file of your project, for example main.py.

  • Generating and loading a file:

Configuration file amvera.yml serves to ensure that the Amvera platform knows how to properly build and run your project. This file contains key information about the environment, dependencies, and instructions for running the application.

File structure amvera.yml:

meta:
  environment: python  # Указывает, что проект использует Python в качестве окружения.
  toolchain:
    name: pip          # Определяет менеджер пакетов для установки зависимостей.
    version: "3.8"     # Задает версию Python для окружения проекта.

build:
  requirementsPath: requirements.txt  # Путь к файлу, где указаны все необходимые зависимости.

run:
  scriptName: app.py  # Основной файл вашего проекта, который будет запущен после сборки.
  persistenceMount: /data  # Директория для хранения постоянных данных.
  containerPort: 3000    # Порт, на котором будет доступен ваш проект в контейнере.

In order for our project to work correctly in the Amvera environment, it is important to specify all the necessary packages in the file requirements.txt. This file defines all Python dependencies that are needed to run the code.

This is what our file looks like requirements.txt :

Flask==3.0.3  
slack-sdk==3.11.0  
requests==2.26.0  
python-dotenv==0.19.2

Initializing and sending the project to the repository:

  • Initialize a git repository at the root of your project if you haven't already:

    git init
  • Link your local repository to the remote one on Amvera:

    git remote add amvera <https://git.amvera.ru/ваш_юзернейм/ваш_проект>
  • Add and commit the changes:

    git add .
    git commit -m "Initial commit"
  • Send your project to the cloud:

    git push amvera master

Building and deploying the project:

  • After sending the project to the system, the status on the project page will change to “Building”. After the build is complete, the project will move to the “Deploying” stage, and then to the “Successfully deployed” status.

  • If the project does not deploy, check the build logs and application logs for debugging.

  • If the project is stuck at the “Build” stage, make sure the file is correct amvera.yml

Well, let's sum it up?

So, we've gone all the way from creating a Slack bot on a home device to running it on a real server. Cool, huh? You now know how to build a Flask app that will respond to commands in Slack, show the weather, and even manage a to-do list.

We also figured out how to use ngrok for testing and how to run a bot on Amvera for 24/7 work.

Author: Alexey Ponomarev


Relevant articles:

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *