Discord 봇을 구축 및 배포하는 단계

이 문서에서는 Node.js, 공식 discord.js 라이브러리 및 Back4app 컨테이너를 사용하여 Discord 봇을 구축하고 배포하는 방법을 설명합니다.

Discord 봇은 Discord에서 자동화된 작업을 수행하는 프로그램입니다. 이러한 봇은 사용자와 상호작용하고, 커뮤니티 행위를 관리하며, 음악 재생, 콘텐츠 중재, 투표 관리, 외부 서비스 또는 API와의 통합 등 기본적으로 Discord에서 사용할 수 없는 추가 기능을 제공할 수 있습니다.

개발 환경 설정

이 글에서는 Discord 서버에서 사용자가 선호하는 난이도와 질문 유형에 따라 사용자가 답할 수 있는 퀴즈 문제를 제공하는 Discord 봇을 소개합니다.

이 튜토리얼을 따라 하려면 다음이 필요합니다:

아래 명령을 실행하여 프로젝트 디렉터리를 설정합니다:

mkdir discord-bot && cd discord-bot && npm init -y

위의 명령은 discord-bot 디렉토리를 생성하고 그 안에 npm을 초기화합니다.

다음으로 package.json 파일로 이동하여 아래에 시작 스크립트를 추가합니다:

"start": "node server.js"

그런 다음 아래 명령을 실행하여 프로젝트에 필요한 종속성을 설치합니다:

npm install discord.js axios dotenv 

위에 설치한 종속성에는 다음이 포함됩니다:

  • discord.js: 이 라이브러리를 사용하면 Node.js 애플리케이션에서 Discord API와 상호 작용할 수 있습니다.
  • dotenv: 이 패키지는 봇의 토큰과 같은 민감한 데이터를 관리하는 데 도움이 됩니다.
  • axios: 이 패키지를 사용하면 퀴즈 API를 요청할 수 있습니다.

이제 개발 환경을 설정하고 필요한 종속성을 설치했습니다. 다음으로 Discord 봇 계정을 만듭니다.

Discord 봇 계정 만들기

Discord 봇 계정은 봇을 실행하기 위해 만든 Discord 계정입니다. 사람이 제어하는 일반 사용자 계정과 달리 봇 계정은 소프트웨어가 제어합니다.

이 계정은 봇이 서버 리소스에 액세스하고, 이벤트에 응답하고, Discord 커뮤니티 내에서 작업을 실행하는 데 필요한 권한을 부여하는 게이트웨이 역할을 합니다.

Discord 봇 계정을 만들려면 먼저 Discord 애플리케이션을 만들어야 합니다. 앱을 만들려면 아래 이미지와 같이 Discord의 개발자 포털로 이동하여 “앱 만들기” 버튼을 클릭합니다.

Discord 봇 앱 만들기

버튼을 클릭하면 Discord 계정에 로그인하라는 메시지가 표시됩니다. 로그인한 후 아래 이미지와 같이 앱 이름을 지정하고 “만들기” 버튼을 클릭합니다.

Discord 앱 이름 지정

그런 다음 공개 봇 스위치를 꺼서 본인만 봇을 서버에 추가할 수 있도록 합니다.

그런 다음 모든 “권한 있는 게이트웨이 의도”를 토글하여 봇의 권한을 구성하여 회원의 존재 여부와 같은 서버 활동에 대한 실시간 업데이트에 액세스할 수 있도록 합니다.

게이트웨이 인텐트 구성

다음으로 왼쪽 사이드바의 ‘OAuth2’ 탭으로 이동합니다. 아래 이미지와 같이 ‘범위’ 섹션에서 application.commands 확인란을 선택합니다.

봇 범위

범위를 선택하면 Discord에서 애플리케이션을 봇으로 인식할 수 있으며, application.commands 범위를 선택하면 봇이 수신할 슬래시 명령을 만들 수 있습니다.

봇 확인란을 선택하면 “봇 권한” 섹션이 열립니다. “봇 권한” 섹션에서 아래 이미지와 같이 관리자 확인란을 선택합니다.

봇 권한

이 확인란을 선택하면 봇에게 서버 내에서 가능한 모든 권한을 부여합니다. 이러한 권한에는 메시지 및 채널 관리 기능이 포함됩니다.

“BOT PERMISSIONS” 섹션 아래에서 Discord가 이 봇을 서버에 추가할 수 있는 URL을 생성합니다. 웹 브라우저에 URL을 붙여넣고 봇을 추가할 서버를 선택하세요.

Discord 봇 생성 URL

다음으로, 아래 이미지와 같이‘토큰 재설정‘ 버튼을 클릭하여 ‘봇’ 탭에서 봇 토큰을 가져옵니다.

버튼을 처음 클릭하면 봇의 기본 토큰이 재설정되고 새 토큰이 제공됩니다. 토큰을 복사하여 안전하게 보관하세요. 토큰은 한 번만 표시되므로 토큰을 분실할 경우 다시 초기화해야 합니다.

.env 파일을 생성하여 봇 토큰과 같은 환경 변수와 봇을 추가한 길드 ID봇의 클라이언트 ID와 같은 기타 데이터를 추가합니다:

TOKEN = "<BOT TOKEN>"
GUILD_ID = "<GUILD ID>"
CLIENT_ID = "<BOT'S CLIENT ID>"

이제 Discord 봇 계정을 설정했습니다. 다음으로 Discord 봇을 구축합니다.

Node.js로 Discord 봇 프로젝트 빌드하기

이 섹션에서는 Discord 퀴즈 봇을 만들고, 봇 슬래시 명령을 Discord에 등록하고 봇과 길드원과의 상호작용을 처리하기 위해 설치한 패키지를 통합하는 방법을 안내합니다.

이 튜토리얼을 따라 하려면 프로젝트의 디렉터리를 아래 그림과 유사하게 구성하세요.

quiz-bot/
│
├── src/
│   ├── register-commands.js   # Script to register slash commands with Discord
│   └── quiz-bot.js                # Script for message handling and fetching questions
│
├── server.js                  # Entry point for your bot and script for running a server
├── node_modules/              # Node.js modules
│
├── .env                       
├── .gitignore                   
├── package.json                         
└── package-lock.json

봇 명령 등록하기

봇을 사용하려면 사용자가 명령을 입력해야 합니다. Discord 봇에서는 슬래시(/) 접두사를 사용하여 봇이 듣기를 원하는 명령을 정의할 수 있습니다.

봇의 /quiz 명령을 Discord 서버에 등록하려면 먼저 discord.js에서 다음 가져오기를 register-commands.js 파일에 추가하세요:

// register-commands.js
const { REST, Routes, ApplicationCommandOptionType } = require('discord.js');

위에서 임포트한 클래스에는 다음이 포함됩니다:

  • REST: 이 클래스를 사용하면 Discord API에 REST API 호출을 할 수 있습니다.
  • 경로: 이 클래스는 Discord API 엔드포인트를 생성하는 유틸리티 함수를 제공합니다.
  • ApplicationCommandOptionType: 이 클래스를 사용하면 명령이 허용할 옵션의 데이터 유형을 정의할 수 있습니다.

다음으로 봇의 모든 명령어를 포함하는 명령어 객체 배열을 정의해야 합니다. 명령 객체에는 이름, 설명, 옵션 배열이 포함됩니다.

이러한 옵션을 통해 사용자는 봇의 명령을 사용자 지정할 수 있습니다. 이 경우 옵션 배열을 통해 사용자는 퀴즈 봇이 질문할 난이도와 질문 유형을 지정할 수 있습니다.

아래 코드 블록을 register-commands.js 파일에 추가하여 명령 배열을 생성합니다:

// register-commands.js
const commands = [
  {
    name: 'quiz',
    description:
      'Select difficulty and question type to tailor the quiz experience.',
    options: [
      {
        type: ApplicationCommandOptionType.String,
        name: 'difficulty',
        description: "Options include 'easy', 'medium', or 'hard'.",
        required: true,
      },
      {
        type: ApplicationCommandOptionType.String,
        name: 'type',
        description:
          " Choose 'multiple' for multiple choice or 'boolean' for true/false",
        required: true,
      },
    ],
  },
];

위의 코드 블록은 명령어 배열에서 퀴즈 명령을 정의합니다. 퀴즈 개체에는 봇이 질문할 질문의 난이도 및 질문 유형 등 사용자가 /quiz 명령과 함께 입력해야 하는 두 가지 옵션이 포함되어 있습니다.

다음으로, 봇을 통해 /quiz 명령에 액세스할 수 있도록 등록해야 합니다. 명령을 등록하려면 먼저 Discord 봇 토큰과 선호하는 REST 버전으로 REST 클래스의 인스턴스를 만들어야 합니다.

퀴즈 명령을 등록하고 봇을 통해 액세스할 수 있도록 하려면 먼저 Discord 봇 토큰을 사용하여 REST 클래스 인스턴스를 만들고 원하는 REST 버전을 지정하세요.

이렇게요:

// register-commands.js
const rest = new REST({ version: '10' }).setToken(process.env.TOKEN);

Discord는 정기적으로 API를 업데이트하여 엔드포인트, 응답 구조 및 동작을 변경합니다.

Discord 프로젝트의 특정 REST 버전을 정의하면 프로젝트에서 사용할 수 있는 기능을 효과적으로 관리할 수 있습니다. 위의 코드 블록은 Discord API v10을 사용합니다.

다음으로, Routes 클래스의 applicationGuildCommands 메서드를 사용하여 길드 서버에 봇 명령을 등록하는 비동기 함수를 정의해야 합니다.

이렇게요:

// register-commands.js
(async () => {
  try {
    console.log('Started refreshing SLASH (/) commands.');
    await rest.put(
      Routes.applicationGuildCommands(
        process.env.CLIENT_ID,
        process.env.GUILD_ID
      ),
      { body: commands }
    );
    console.log('Successfully reloaded SLASH (/) commands.');
  } catch (error) {
    console.error(error);
  }
})();

위의 코드 블록은 명령어 배열을 요청 본문으로 사용하여 Discord API 엔드포인트에 PUT 요청을 수행합니다.

봇의 클라이언트 ID와 대상 길드 ID를 받아 applicationGuildCommands 메서드를 사용하여 API 엔드포인트를 구성합니다.

명령을 등록한 후에는 봇과 길드원 간의 상호작용 흐름을 관리해야 합니다.

Discord 봇으로 사용자 상호작용 처리하기

봇과 길드원 간의 상호작용 흐름을 처리하려면 먼저 quiz-bot.js 파일에 다음 임포트를 추가하세요:

// quiz-bot.js
const { Client, IntentsBitField } = require('discord.js');
const axios = require('axios');

새 Discord 봇 인스턴스를 만들려면 Client 클래스를 사용하고, 봇이 Discord API에서 수신할 인텐트(이벤트)를 지정하려면 IntentsBitField 클래스를 사용해야 합니다.

그런 다음, quiz-bot.js 파일에 아래 코드 블록을 추가하여 봇의 새 클라이언트 인스턴스를 만들고 봇 애플리케이션에 대한 특정 인텐트를 지정합니다:

// quiz-bot.js
const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMembers,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.MessageContent,
  ],
});

위의 코드 블록은 봇이 작동하는 데 필요한 특정 의도를 정의하며, 여기에는 다음이 포함됩니다:

  • IntentsBitField.Flags.Guilds: 이 인텐트를 사용하면 봇이 소속된 길드(서버)에 대한 이름, 아이콘, 역할 등의 정보를 수신할 수 있습니다.
  • IntentsBitField.Flags.GuildMembers: 이 인텐트를 사용하면 봇이 길드원의 사용자명, 상태, 역할 등의 정보를 수신할 수 있습니다.
  • 인텐트비트필드.플래그.길드메시지: 이 인텐트는 봇이 속한 길드에서 전송된 메시지에 대한 액세스 권한을 부여하여 메시지에 의해 트리거된 명령이나 이벤트에 응답할 수 있도록 합니다.
  • IntentsBitField.Flags.MessageContent: 이 인텐트를 사용하면 봇이 길드에서 보낸 메시지의 실제 콘텐츠에 액세스할 수 있습니다. 이 인텐트가 없으면 메시지 콘텐츠는 비어 있습니다.

준비 이벤트에 대한 이벤트 리스너를 만듭니다. 이 이벤트는 Discord 봇이 Discord 서버에 성공적으로 연결되고 작동할 준비가 되면 트리거됩니다.

아래 코드 블록을 quiz-bot.js 파일에 추가하여 준비된 이벤트 리스너를 만듭니다:

// quiz-bot.js
client.on('ready', () => {
  console.log(`✅ Bot is online and ready`);
});

다음으로 interactionCreate 이벤트에 대한 이벤트 리스너를 만들어야 합니다. 이 이벤트는 사용자가 슬래시 명령 사용과 같이 봇이 처리할 수 있는 상호작용을 수행할 때 발생합니다.

이벤트 리스너는 이벤트가 발생하면 인터랙션 객체와 함께 인터랙션 생성 이벤트를 수신합니다.

이 객체에는 상호작용 유형 및 사용자가 제공한 데이터 등 상호작용에 대한 모든 세부 정보가 포함됩니다.

아래 코드 블록을 quiz-bot.js 파일에 추가하여 인터랙션 생성 이벤트 리스너를 생성합니다:

// quiz-bot.js
client.on('interactionCreate', async (interaction) => {
 if (!interaction.isChatInputCommand()) return;
 
 if (interaction.commandName === 'quiz') {
  // Rest of the code goes here...
 }
});

위의 코드 블록은 interactionCreate 이벤트 리스너를 설정합니다.

이벤트 리스너는 사용자와 봇 간의 상호작용이 채팅 입력 명령(슬래시 명령)인지 확인하고 다른 유형의 상호작용은 필터링합니다.

그런 다음 명령 이름이 퀴즈인지 확인하고 봇과 사용자 간의 퀴즈 세션을 처리합니다.

명령명이 퀴즈인 경우, Axios로 퀴즈 API의 URL에 GET 요청을 보내 문제와 정답(정답 및 오답)을 가져옵니다.

답을 섞어 옵션을 무작위로 선택한 다음 사용자에게 렌더링합니다.

이렇게요:

// quiz-bot.js

await interaction.deferReply();

const difficulty = interaction.options.getString("difficulty");
const type = interaction.options.getString("type");

try {
  const url = `https://opentdb.com/api.php?amount=1&difficulty=${difficulty}&type=${type}`;
  const response = await axios.get(url);
  const data = response.data.results[0];
  const question = data.question;
  const correctAnswer = data.correct_answer;
  const options = [...data.incorrect_answers, correctAnswer];

  // Shuffle the options
  for (let i = options.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [options[i], options[j]] = [options[j], options[i]];
  }

  await interaction.editReply({
    content: `Question: ${question}\\nOptions: ${options.join(", ")}`,
  });
} catch (error) {
  console.error(error);
  // Notify the user in case of an error after deferring
  await interaction.followUp("Failed to fetch the question. Please try again.");
}

위의 코드 블록은 먼저 봇이 GET 요청을 처리할 수 있도록 일정 시간 간격을 두고 deferReply 메서드를 사용하여 봇의 응답을 지연시킵니다.

그런 다음 코드 블록은 인터랙션 객체에서 사용자가 선택한 난이도 및 문제 유형을 인터랙션.options.getString()을 사용하여 검색합니다.

그 후 봇은 가져온 데이터에서 질문, 정답, 오답을 추출합니다.

정답과 오답을 섞어 선택 순서를 무작위로 정한 후 퀴즈 문제와 옵션으로 초기 지연된 답안을 편집합니다.

다음으로, 질문에 대한 사용자의 답변을 정답과 대조하여 정답인지 오답인지 사용자에게 알려주는 방식으로 처리해야 합니다.

사용자 응답 수집

질문에 대한 사용자의 응답을 수집하려면 인터랙션의 채널(interaction.channel)에서 createMessageCollector 메서드를 사용합니다.

이 방법을 사용하면 /quiz 명령을 시작한 사용자가 보내지 않은 메시지를 필터링하고, 사용자의 응답에 대한 시간 제한을 설정하고, 수집할 최대 메시지 수를 지정할 수 있습니다.

사용자가 응답을 보내면 createMessageCollector 메서드가 수집 이벤트를 트리거합니다.

이 이벤트에 리스너를 추가해야 하며, 리스너는 사용자의 응답을 질문에 대한 정답과 비교하여 확인하고 적절한 메시지를 보냅니다.

반면에 사용자가 지정된 시간 제한 내에 적절한 응답을 보내지 않으면 createMessageCollector 메서드가 종료 이벤트를 트리거합니다.

사용자에게 응답하는 리스너를 추가하여 이 이벤트까지 시간이 남았음을 알려야 합니다.

이렇게요:

// quiz-bot.js
const filter = (m) => m.author.id === interaction.user.id;

const collector = interaction.channel.createMessageCollector({
  filter,
  time: 15000,
  max: 1,
});

collector.on("collect", async (m) => {
  if (m.content.toLowerCase() === correctAnswer.toLowerCase()) {
    await m.reply("Correct answer! 🎉");
  } else {
    await m.reply(`Wrong answer! The correct answer was: ${correctAnswer}`);
  }
});

collector.on("end", (collected) => {
  if (collected.size === 0) {
    interaction.followUp("Time is up! No answer was provided.");
  }
});

위의 코드 블록은 상호작용이 발생한 채널에 대한 메시지 수집기(수집기)를 생성합니다. 수집기는 작성자의 ID를 기준으로 메시지를 필터링하여 퀴즈를 시작한 사용자만 15초 제한 시간 내에 답을 제공할 수 있도록 합니다.

그런 다음 코드 블록은 수집기에 대한 두 개의 이벤트 리스너를 생성합니다. 첫 번째 이벤트 리스너인 collect는 콜백을 트리거하여 사용자의 응답을 확인하고 그에 따라 사용자에게 응답합니다.

두 번째 이벤트 리스너인 end는 콜백을 트리거하여 사용자가 제한 시간 내에 답변을 제공하지 않았음을 알립니다.

다음으로, quiz-bot.js 파일 끝에 코드 줄을 추가하여 봇과 Discord 간의 연결을 설정합니다:

// quiz-bot.js
client.login(process.env.TOKEN);

엔트리 파일 만들기

전체 봇 애플리케이션을 초기화할 단일 파일인 엔트리 파일을 생성합니다. 이 파일은 두 가지 기능을 수행합니다:

  • 봇 로직 가져오기: 입력 파일은 봇 명령을 Discord 서버에 등록하고 사용자 메시지에 응답하는 작업을 처리하는 JavaScript 파일을 요구하여 봇의 로직을 실행합니다.
  • 서버 시작하기: 엔트리 파일은 봇이 Back4app 컨테이너에서 실행될 수 있도록 서버를 설정합니다. 애플리케이션을 성공적으로 배포하려면 Back4app 컨테이너에 노출된 포트가 필요합니다.

서버를 생성하려면 아래 코드 블록을 server.js 파일에 추가합니다:

// server.js
require('dotenv').config();
const http = require('http');
require('./src/register-commands.js');
require('./src/quiz-bot.js');

http
  .createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Bot is running!');
  })
  .listen(3000, () => {
    console.log('Server is ready.');
  });

위의 코드 블록은 간단한 HTTP 서버를 생성하여 Discord 봇을 실행하도록 설정합니다. 이 서버는 봇이 컨테이너 환경 내에서 작동할 수 있도록 하는 진입점 역할을 합니다.

위의 코드 블록은 봇의 핵심 로직을 가져오고 봇이 Back4app 컨테이너에 배포할 수 있도록 Back4app 포트를 지정합니다.

엔트리 파일을 생성한 후에는 Discord 봇을 로컬에서 테스트한 후 Back4app 컨테이너에 배포할 수 있습니다.

Discord 봇 테스트하기

애플리케이션의 터미널에서 아래 코드 블록을 실행하여 Discord 봇을 시작하세요:

node server.js

이 명령은 봇을 성공적으로 등록했으며 봇이 준비되어 있고 온라인 상태임을 나타내는 메시지를 기록합니다.

로컬에서 봇 시작

봇을 추가한 서버로 이동합니다. 이제 온라인 상태인 것을 확인할 수 있을 것입니다.

퀴즈 앱 테스트

봇과 상호작용하려면 /quiz 명령을 보내세요. 봇은 퀴즈 질문이 어떻게 표시되기를 원하는지 자세히 설명하는 옵션으로 응답해야 합니다.

문제 난이도 및 유형 선택

원하는 옵션(예: 퀴즈 카테고리 또는 난이도 선택)을 선택하고 Enter 키를 누릅니다. 봇이 질문으로 답하고 답변에 15초의 제한 시간을 설정합니다.

제한 시간 내에 답을 제출하면 봇이 정답과 비교하여 정답이 맞는지 틀린지 알려줍니다.

디스코드에 대한 봇 응답

봇이 처리하도록 설계한 모든 기능을 처리할 수 있다고 판단했다면, 이제 Discord 봇을 Back4app 컨테이너에 배포합니다.

AI 에이전트를 사용하여 Back4app 컨테이너에 Discord 봇 배포하기

이 섹션에서는 Back4app AI 에이전트를 사용하여 Back4app 컨테이너에 Discord 봇을 배포합니다.

Back4app 컨테이너에 앱을 배포하려면 다음이 필요합니다:

  • 프로젝트의 도커파일
  • GitHub 리포지토리: 프로젝트는 GitHub 리포지토리에 업로드해야 합니다.
  • Back4app GitHub 앱: 리포지토리에 대한 Back4app GitHub 앱을 설치하고 필요한 권한을 부여합니다.

먼저 프로젝트의 루트 디렉터리에 Docker파일을 생성하고 아래 코드 블록을 추가합니다:

# Dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

그런 다음 배포에 액세스할 수 있도록 코드를 GitHub 리포지토리에 업로드해야 합니다.

다음 단계를 수행하기 전에 GitHub 계정에 Back4App 컨테이너 GitHub 앱이 설치되어 있는지 확인하고 배포하려는 앱에 액세스하는 데 필요한 권한이 있는지 확인하세요.

Back4app 홈페이지로 이동하여 화면 오른쪽 상단에 있는 ‘새 앱‘ 버튼을 클릭합니다.

그러면 초기화 화면으로 이동하여 만들려는 앱의 유형을 선택해야 합니다.

아래 이미지와 같이 Back4app 에이전트 옵션을 선택합니다.

Back4app 에이전트 옵션을 선택하면 Back4app AI 에이전트 페이지로 리디렉션됩니다.

AI 에이전트에게 앱을 배포하려면 아래 프롬프트를 입력하세요:

Deploy my "YOUR_REPOSITORY_URL" repository on GitHub to a Back4App Container.
Here are the required environmental variables:
TOKEN = "YOUR_DISCORD_BOT_TOKEN"
GUILD_ID = "YOUR_GUILD_ID"
CLIENT_ID = "YOUR_CLIENT_ID"

위 프롬프트의 자리 표시자를 실제 값으로 바꿉니다.

아래와 유사한 응답이 표시될 것입니다:

AI 상담원 응답

위의 응답은 배포 프로세스가 진행 중이며 애플리케이션이 온라인 상태이며 제공된 URL에서 사용할 수 있음을 보여줍니다.

Back4app 컨테이너 대시보드에서 배포 프로세스를 모니터링하거나 잠시 후 AI 에이전트에게 현재 배포 상태를 확인하기 위해 아래 프롬프트를 제공할 수 있습니다.

What is the current deployment status of my web app?

아래와 유사한 응답이 표시될 것입니다:

AI 상담원 응답

또는 Back4App에 앱을 수동으로 배포하도록 선택할 수 있습니다.

결론

이 도움말에서는 Node.js로 Discord 봇을 구축하는 방법을 배웠습니다. Discord 봇 계정을 만들고, 봇 명령을 등록하고, 사용자 응답을 처리하는 방법을 살펴보았습니다.

또한 AI 에이전트의 도움을 받아 Discord 봇을 테스트하고 Back4app 컨테이너에 배포했습니다.

Discord 봇은 작업 자동화, 엔터테인먼트 제공 등에 매우 유용할 수 있으며, 사용 사례에 따라 필요에 맞는 특정 기능을 수행하도록 봇을 조정할 수 있습니다.

이 튜토리얼에 사용된 전체 코드는 이 GitHub 리포지토리에서 확인할 수 있습니다.


Leave a reply

Your email address will not be published.