Создание бота в дискорде с деплоем на сервер за 5 минут

В этой статье мы поговорим о том как сделать простого бота в Discord на Python с базой данных SQlite3.

Функционал бота будет следующим:

1. Вывод пинга:  

— Бот отвечает на команду /пинг, отправляя обратно сообщение с текущим пингом на запущенном сервере.

2. Выдача роли:  

— Бот может выдавать роль пользователю по команде /выдать_роль. Находит упомянутого пользователя и добавляет ему указанную роль. 

3. Удаление роли:  

— Бот осуществляет отзыв роли у пользователя командой /забрать_роль. Находит упомянутого пользователя и убирает у него указанную роль. 

4. Смена никнейма:  

— Бот может менять никнейм пользователя по команде /изменить_ник. Находит упомянутого пользователя и меняет его никнейм на новый. 

5. Вывод баланса:

— Бот получает данные о баланса пользователя по его ID с помощью

команды /баланс. Данные получаются из базы данных и вставляются если их нет.

После написания кода бота, мы развернем его облаке Amvera буквально за пару минут и три команды в IDE, используя GitOps-подход. Это позволит осуществлять обновления проекта существенно проще, чем при использовании классического VPS.

Создание бота

Для создания бота нам нужно зайти на сайт разработчиков Discord. Нажимаем New application. Вводим имя вашего бота, подтверждаем согласие и нажимаем Create.

Создание бота в Discord

Создание бота в Discord

После создания переходим во вкладку Bot, листаем чуть ниже и включаем Intents

Включение Intents

Включение Intents

Теперь нам нужно добавить бота на сервер, для этого нам нужна ссылка авторизации. Переходим во вкладку OAuth2. В разделе SCOPES выбираем bot

далее нам нужно выбрать разрешения, листаем ещё вниз и выбираем Administrator

ad79cc2d3d638b8e7ef4cddcb57a0018.png

Теперь мы можем получить ссылку для авторизации бота на сервере. Листаем ещё вниз и копируем ссылку

import disnake

from disnake.ext import commands

import sqlite3

Копируем ссылку и вставляем в браузер

Копируем ссылку и вставляем в браузер

Скопированную ссылку нужно вставить в поисковую строку браузера. Теперь мы можем добавить бота на сервер

Добавление бота на сервер Discord

Добавление бота на сервер Discord

После добавления бота мы можем перейти к написанию его кода. 

Написание кода с использованием disnake библиотеки

Для начала установим библиотеку disnake. Альтернативой является использование библиотеки discord.py, но disnake больше подходит для новичков из-за своей простоты.

Переходим в командную строку и пишем команду pip install disnake.  Теперь можно приступить к написанию кода.

  1. Создаем файл bot.py и открываем его.

  2. Импортируем библиотеки

    import disnake
    from disnake.ext import commands
    import sqlite
  3. Подключаем интенты и создаем экземпляр бота

    intents = disnake.Intents.default()
    intents.message_content = True
    bot = commands.Bot(command_prefix='+', intents=intents)
  4. Подключаем базу данных

    conn = sqlite3.connect('/data/bot.db')
    cursor = conn.cursor()
  5. Создаем событие, которое выведет в консоль готовность бота когда он будет запущен, а так же создадим таблицу в базе данных

    @bot.event 
    async def on_ready():
        cursor.execute("""CREATE TABLE IF NOT EXISTS users (
            id BIGINT 
            cash INT )""")
        conn.commit()
        print(f'{bot.user.name} ready!')

    Мы сделали основу бота, теперь можно приступить к созданию команд.

    1. Создадим обычную текстовую команду выводящую задержку бота

      @bot.command()
      async def ping(ctx):
          await ctx.reply(f'Понг! {round(bot.latency * 1000)} мс')
    2. Создадим слэш-команду с обращением к базе данных

      @bot.slash_command(name='баланс', description='Вывод баланса пользователя')
      async def balance(interaction):
          user_id = interaction.author.id 
          user_cash = cursor.execute('SELECT cash FROM users WHERE id = ?', (user_id,)).fetchone()[0]
          if user_cash is None:
              cursor.execute("INSERT INTO users VALUES (?, ?)", (user_id, 0))
              conn.commit()
              await interaction.response.send_message(f'Ваш баланс: {user_cash}')
          else:
              await interaction.response.send_message(f'Ваш баланс: {user_cash}')
    3. Теперь сделаем команду для выдачи и отзыва роли пользователю

      @bot.slash_command(name='выдать_роль', description='Выдача роли пользователю')
      async def give_role(interaction, member: disnake.Member, role: disnake.Role):
          await member.add_roles(role)
          await interaction.response.send_message('Роль выдана!')
      
      @bot.slash_command(name='забрать_роль', description='Отзыв роли у пользователя')
      async def take_role(interaction, member: disnake.Member, role: disnake.Role):
          await member.remove_roles(role)
          await interaction.response.send_message('Роль отозвана!')
    4. Осталась команда изменения ника

      @bot.slash_command(name='изменить_ник', description='Изменяет никнейм пользователя')
      async def set_nick(interaction, member: disnake.Member, nick: str):
      await member.edit(nick=nick)
      await interaction.response.send_message('Никнейм изменен!')
    5. Когда все команды добавлены, в самый конец файла требуется добавить 

      bot.run('TOKEN')

Итоговый файл нашего бота

import disnake
from disnake.ext import commands
import sqlite3

conn = sqlite3.connect('/data/bot.db')
cursor = conn.cursor()

intents = disnake.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix='+', intents=intents)

@bot.event 
async def on_ready():
    cursor.execute("""CREATE TABLE IF NOT EXISTS users (
        id BIGINT, 
        cash INT )""")
    conn.commit()
    print(f'{bot.user.name} ready!')

@bot.command()
async def ping(ctx):
    await ctx.reply(f'Понг! {round(bot.latency * 1000)} мс')

@bot.slash_command(name='баланс', description='Вывод баланса пользователя')
async def balance(interaction):
    user_id = interaction.author.id 
    user_cash = cursor.execute('SELECT cash FROM users WHERE id = ?', (user_id,)).fetchone()[0]
    if user_cash is None:
        cursor.execute("INSERT INTO users VALUES (?, ?)", (user_id, 0))
        conn.commit()
        await interaction.response.send_message(f'Ваш баланс: {user_cash}')
    else:
        await interaction.response.send_message(f'Ваш баланс: {user_cash}')

@bot.slash_command(name='выдать_роль', description='Выдача роли пользователю')
async def give_role(interaction, member: disnake.Member, role: disnake.Role):
    await member.add_roles(role)
    await interaction.response.send_message('Роль выдана!')


@bot.slash_command(name='забрать_роль', description='Забор роли у пользователя')
async def take_role(interaction, member: disnake.Member, role: disnake.Role):
    await member.remove_roles(role)
    await interaction.response.send_message('Роль убрана!')

@bot.slash_command(name='изменить_ник', description='Изменяет никнейм пользователя')
async def set_nick(interaction, member: disnake.Member, nick: str):
await member.edit(nick=nick)
await interaction.response.send_message('Никнейм изменен!')

bot.run('TOKEN')

Подготовка к деплою

Деплой мы произведем в облаке Amvera.

Встроенный функционал CI/CD Amvera позволит нам накатывать обновления простой командой git push amvera master и максимально упростить процесс развертывания в сравнении с классической VPS.

Но перед деплоем нам необходимо создать конфигурационный файл amvera.yml и файл с зависимостями requirements.txt

Файл amvera.yaml

Используем генератор для создания этого файла

Выбираем окружение Python

f6dac254ff32b8052ef8836a30deaf22.jpg

Далее вводим версию Python, в нашем случае 3.8

Указываем путь к файлу с зависимостями, requirements.txt

Вводим имя вашего основного файла, к примеру bot.py

49f97d80a85a03c679e5ae86285f23d2.jpg

Нажимаем Generate YAML

Вот так выглядит файл конфигурации:

meta:
  environment: python
  toolchain:
    name: pip
    version: 3.8
build:
  requirementsPath: requirements.txt
run:
  scriptName: bot.py
  persistenceMount: /data
  containerPort: 80

Следует обратить внимание, что порт в конфигурации должен соответствовать порту в коде. Это поможет избежать 502 ошибки.

И так как мы используем SQLite3, сохраняем ее в постоянном хранилище /data. Это позволит избежать ее утери при пересборке проекта.

Файл requirements.txt

Для его создания, используем командную строку.

Открываем ее и вводим команду pip freeze > requirements.txt

Переходим к папке которая была указана в командной строке и забираем оттуда файл с зависимостями. 

Вот так выглядит файл с зависимостями:

aiohttp==3.9.5
aiosignal==1.3.1
async-timeout==4.0.3
attrs==23.2.0
disnake==2.9.2
frozenlist==1.4.1
idna==3.7
multidict==6.0.5
psycopg2==2.9.9
yarl==1.9.4

Примечание: в файл будут записаны все библиотеки которые у вас установлены, будьте осторожнее и не загружайте лишние библиотеки в проект. Лучше составить данный файл руками.

Деплой через интерфейс

  1. Нажимаем на кнопку создать.

  2. Вводим название для проекта, выбираем тип сервиса — приложение и выбираем тарифный план

  3. Нажимаем далее

458ff30dc02ef20f53ec6a585142bdba.jpg

Выбираем файлы которые нужно закинуть в проект и перемещаем их в это окошко.

26a2b084cc8dc5a0cf27cb96b17125c5.jpg

Нажимаем на кнопку далее

У нас появится вот это окно

a3be4cc63313192b8b78be61f08ea3cc.jpg

Тут ничего делать не надо так как мы закинули файл amvera.yaml и все настраивается автоматически.

Теперь нам нужно добавить секрет — токен нашего бот в bot.run () мы указали просто слово TOKEN, теперь нужно добавить переменную как секрет. Для этого заходим во вкладку переменные в проекте и нажимаем создать секрет. В поле название вводим нашу переменную TOKEN, а в поле значение, вводим сам токен

157f34b6830e17c83e170dee81f5ea0d.jpg

Нажимаем кнопку завершить и начнется сборка проекта.

Если вы все сделали правильно, то после сборки начнется запуск.

Если вы сделал все правильно то ваше приложение будет запущено.

Деплой через Git

Деплой через git push является альтернативным способом развернуть приложение. Он чуть сложнее, но в дальнейшем позволит обновлять наш проект тремя командами в терминале не переходя на сайт облака, что намного удобнее.

Создаем папку и закидываем туда  все файлы. Открываем командную строку, и переходим в нашу папку с помощью команды cd «путь к папке». Создаем репозиторий с помощью команды git init. Заходим в Amvera и создаем проект. 

На данном этапе мы выбираем метод «Через Git» и нажимаем отмена.

40d6f4a7d9cf4d1512b675ebf1c21352.jpg

Теперь нам нужно подключиться к существующему репозиторию, для этого копируем команду ниже и вставляем в командную строку.

2d906927e0e253536c250299c6b3ba26.jpg

После чего вводим команды для добавления файлов и создания коммита:

git add .

git commit -m "initial commit" 

Теперь нам остается запушить все файлы и сборка начнется автоматически. Для этого вводим команду:  git push amvera master

Результат

Если вы все сделали правильно, то после сборки начнется запуск.

c4a426b0e6ff1a4a244e2ec03abc8351.jpg

Если же выдает ошибку, полезно ознакомиться с Логом сборки и Логом приложения и посмотреть частые ошибки в документации сервиса.

Приложение запущено, а значит наш бот должен появиться в сети

de6655c64d9b48bdd33ebc4472a29afb.jpg

Теперь мы можем ввести команды

0446e4df871e25ea7f1aed979aa48a76.jpg

В этой статье мы поговорили о том как сделать и задеплоить python бота в Discord, научили работать его с базой данных и взаимодействовать с участниками сервера и развернули его в облаке Amvera, используя GitOps-подход.

Данный пример содержит самый базовый функционал, практически «hello world», но надеюсь, даст первое представление о работе discord-ботов.

© Habrahabr.ru