Боты в Telegram стали неотъемлемой частью этого мессенджера: каждый день сотни тысяч людей пользуются ими, и неспроста. Telegram-боты легки в использовании для пользователей, а разработчики могут быстро и комфортно их создавать благодаря развивающемуся API Telegram, который старается становиться лучше с каждым днём.
Идеей Telegram-ботов является автоматизация задач и расширение функционала мессенджера. Боты могут выступать как в роли простых помощников, выполняя команды, так и в роли сложных систем с полноценной бизнес-логикой. От рассылки новостей до сложных игровых механик — возможности ботостроения практически безграничны.
На Node.js можно реализовать практически любой функционал для Telegram-бота, благодаря экосистеме библиотек и фреймворков. Node.js, как платформа с асинхронной обработкой запросов, идеально подходит для построения ботов, которые должны работать в режиме реального времени и взаимодействовать с тысячами пользователей одновременно. Вот некоторые возможности, которые можно реализовать:
Базовый функционал:
Интеграции с внешними сервисами:
Уведомления:
Аналитика:
Сперва нужно создать бота внутри Telegram. Воспользуйтесь официальным ботом BotFather, чтобы зарегистрировать бота. Используйте кнопку «Запустить» (а если вы уже пользовались ботом, то отправьте команду /start
), в ответе бота найдите и выберите команду /newbot
. BotFather предложит указать имя бота, а затем его username
. При этом нужно, чтобы в конце было слово bot
. Например, если у вашего бота название Tetris, то username
должен быть таким:
Если всё указано верно, то бот будет создан. BotFather также выдаст вам уникальный токен бота, который нельзя никому показывать.
Мы создадим бота, который будет отправлять различные викторины, в виде опросов Telegram. Тематикой вопросов будут школьные предметы. В боте будет две команды, одна для отправки вопросов, а другая для выбора тем вопросов.
Перед началом разработки нужно, чтобы на вашем ПК были установлены Node.js и npm. Скачать Node.js можно с официального сайта, а npm установится автоматически вместе с Node.js. Если же вы используете Linux, то установить npm можно, воспользовавшись инструкцией.
Если Node.js установлен, можно приступать к разработке бота. Сперва создайте на GitHub новый приватный репозиторий и в пункте Add .gitignore выберите Node
.
Теперь клонируйте этот репозиторий себе на ПК используя консоль. Если вы хотите, чтобы проект находился на рабочем столе, то введите:
cd Desktop
Затем введите:
git clone https://github.com/Tulopex/School-Quiz
Вместо ссылки на мой репозиторий, используйте свою.
Далее, после клонирования, не закрывая консоль, введите:
cd School-Quiz
Вместо School-Quiz используйте реальное название папки вашего проекта, которая клонировалась с GitHub.
Для инициализации проекта выполните команду:
npm init
Вам предложат ввести имя пакета, версию, описание, главный файл по умолчанию, тест команду, Git репозиторий, ключевые слова, автора и лицензию. Вы можете оставить значения по умолчанию, нажимая «Enter».
Теперь установим библиотеку, с помощью которой и будем писать код для бота. Введите в консоль (убедившись, что находитесь в папке с проектом) команду:
npm install node-telegram-bot-api
После завершения процесса установки можно приступать к написанию кода. Откройте файл package.json
и найдите строку scripts
, внутрь неё над командой test
, введите:
"start": "node index.js",
Это необходимо для того, чтобы можно было запускать проект вводя в консоль npm start
, а не node
и имя файла.
Теперь создайте файле index.js
и внутри него напишите следующее:
const TelegramBot = require('node-telegram-bot-api');
const fs = require('fs');
const bot = new TelegramBot('TOKEN', { polling: true }); // Вместо слова TOKEN, укажите реальный токен вашего бота, который выдал вам BotFather
const ADMIN_ID = '1402655980';
let awaitingSupportMessage = {}; // Хранение информации о пользователях, ожидающих поддержки
// Хранение выбранных тем для пользователей
let userTopics = {};
// Темы и файлы с вопросами
const topics = {
math: { name: 'Математика', file: 'questions/math.json' },
english: { name: 'Английский', file: 'questions/english.json' },
history: { name: 'История', file: 'questions/history.json' }
};
// Функция для получения вопросов по выбранным темам
function getQuestionsByTopics(userId) {
const selectedTopics = userTopics[userId] || Object.keys(topics);
let allQuestions = [];
selectedTopics.forEach(topic => {
const questions = JSON.parse(fs.readFileSync(topics[topic].file, 'utf8'));
allQuestions = allQuestions.concat(questions);
});
return allQuestions;
}
function getRandomQuestion(userId) {
const questions = getQuestionsByTopics(userId);
const randomIndex = Math.floor(Math.random() * questions.length);
return questions[randomIndex];
}
bot.onText(/\/quiz/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id;
// Получаем случайный вопрос
const questionData = getRandomQuestion(userId);
// Отправляем опрос в виде викторины
bot.sendPoll(
chatId,
questionData.question, // Вопрос
questionData.options, // Варианты ответов
{
type: 'quiz', // Тип викторины
correct_option_id: questionData.correct_option_id, // Правильный ответ
is_anonymous: false // Вопрос не будет анонимным
}
).then(pollMessage => {
// Обрабатываем результаты опроса
bot.on('poll_answer', (answer) => {
if (answer.poll_id === pollMessage.poll.id) {
const selectedOption = answer.option_ids[0];
// Проверяем, правильный ли ответ
if (selectedOption !== questionData.correct_option_id) {
bot.sendMessage(chatId, questionData.explanation);
}
}
});
});
});
bot.onText(/\/settopic/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id;
const keyboard = Object.keys(topics).map(topicKey => ({
text: `${(userTopics[userId] || []).includes(topicKey) ? '✅ ' : ''}${topics[topicKey].name}`,
callback_data: topicKey
}));
bot.sendMessage(chatId, 'Выберите темы для вопросов:', {
reply_markup: {
inline_keyboard: [keyboard]
}
});
});
// Обработчик выбора тем
bot.on('callback_query', (callbackQuery) => {
const message = callbackQuery.message;
const userId = callbackQuery.from.id;
const topicKey = callbackQuery.data;
// Инициализируем выбранные темы для пользователя, если их нет
if (!userTopics[userId]) {
userTopics[userId] = Object.keys(topics);
}
// Добавляем или удаляем тему
if (userTopics[userId].includes(topicKey)) {
userTopics[userId] = userTopics[userId].filter(t => t !== topicKey);
} else {
userTopics[userId].push(topicKey);
}
// Обновляем сообщение с кнопками
const keyboard = Object.keys(topics).map(topicKey => ({
text: `${userTopics[userId].includes(topicKey) ? '✅ ' : ''}${topics[topicKey].name}`,
callback_data: topicKey
}));
bot.editMessageReplyMarkup({
inline_keyboard: [keyboard]
}, { chat_id: message.chat.id, message_id: message.message_id });
});
bot.onText(/\/start/, (msg) => {
const chatId = msg.chat.id;
bot.sendMessage(chatId, "Привет! Напиши /quiz, чтобы начать викторину. Для выбора тем используй /settopic.");
});
console.log('Бот запущен.');
Теперь создайте папку внутри проекта под названием questions
, а внутри этой папки нужно создать три JSON-файла:
english.json
[
{
"question": "Как будет 'я' на английском языке?",
"options": ["I", "You", "We"],
"correct_option_id": 0,
"explanation": "Правильный ответ: I."
},
{
"question": "Как переводится глагол 'run'?",
"options": ["бежать", "идти", "стоять"],
"correct_option_id": 0,
"explanation": "Правильный ответ: бежать."
},
{
"question": "Как будет 'он' на английском языке?",
"options": ["He", "She", "It"],
"correct_option_id": 0,
"explanation": "Правильный ответ: He."
}
]
history.json
[
{
"question": "В каком году началась Вторая мировая война?",
"options": ["1939", "1941", "1914"],
"correct_option_id": 0,
"explanation": "Правильный ответ: 1939."
},
{
"question": "Кто был первым президентом США?",
"options": ["Авраам Линкольн", "Джордж Вашингтон", "Франклин Рузвельт"],
"correct_option_id": 1,
"explanation": "Правильный ответ: Джордж Вашингтон."
},
{
"question": "Какая страна первой отправила человека в космос?",
"options": ["США", "Россия", "Китай"],
"correct_option_id": 1,
"explanation": "Правильный ответ: Россия."
}
]
math.json
[
{
"question": "Сколько будет 2 + 2?",
"options": ["3", "4", "5"],
"correct_option_id": 1,
"explanation": "Правильный ответ: 4."
},
{
"question": "Сколько будет 5 * 5?",
"options": ["10", "20", "25"],
"correct_option_id": 2,
"explanation": "Правильный ответ: 25."
},
{
"question": "Сколько будет 10 / 2?",
"options": ["4", "5", "6"],
"correct_option_id": 1,
"explanation": "Правильный ответ: 5."
}
]
Внутри этих JSON-файлов находятся заголовок вопроса, варианты ответов, номер правильного ответа, а также пояснение, которое будет отправляться, если пользователь ответил неверно.
Недавно в Telegram добавили внутреннюю валюту Telegram Stars, а также предоставили обновление для API, с помощью которого можно добавить донат в вашем боте в Stars. Добавим команду donate
внутрь файла index.js
, при отправке которой бот будет присылать счёт для оплаты.
bot.onText(/\/donate/, (msg) => {
const chatId = msg.chat.id;
bot.sendInvoice(chatId,
'Донат',
'Донат на поддержку проекта',
'unique_payload',
'', // Пустой provider_token для Stars Payments
'XTR', // Валюта "XTR"
[{ label: 'Донат', amount: 1 }], // Сумма: 1 Stars
);
});
Также добавим ещё одну команду — support
. С её помощью большое количество пользователей вашего бота смогут написать обращение к вам, при этом у вас не будет множества лишних чатов с различными людьми! Пользователи смогут отправлять текст, фото и видео, а бот будет пересылать эти обращения администратору (в данном случае вам). Эту команду также расположите внутри файла index.js
.
В начале файла добавьте:
const ADMIN_ID = 'ID';
let awaitingSupportMessage = {}; // Хранение информации о пользователях, ожидающих поддержки
Благодаря этому ID
бот будет понимать, кому нужно переслать сообщение от пользователей. Чтобы узнать свой ID
, можно воспользоваться ботом Get My ID, в котором достаточно отправить команду /start
.
Далее в конце файла добавьте:
bot.onText(/\/support/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id;
// Сообщаем пользователю, что ожидаем его обращение
bot.sendMessage(chatId, "Пожалуйста, отправьте ваше обращение в одном сообщении, включая текст, фото или видео!");
// Отмечаем, что этот пользователь сейчас пишет обращение
awaitingSupportMessage[userId] = true;
});
// Обработка всех сообщений
bot.on('message', (msg) => {
const userId = msg.from.id;
// Проверяем, что пользователь отправил сообщение после команды /support
if (awaitingSupportMessage[userId]) {
const chatId = msg.chat.id;
const caption = msg.caption || ''; // Подпись, если есть
// Проверка на тип сообщения и пересылка соответствующего контента администратору
if (msg.text) {
// Если сообщение содержит текст
bot.sendMessage(ADMIN_ID, `Новое обращение от пользователя @${msg.from.username || msg.from.first_name} (ID: ${userId}):\n\n${msg.text}`);
} else if (msg.photo) {
// Если сообщение содержит фото
const photo = msg.photo[msg.photo.length - 1].file_id; // Берём фото с максимальным разрешением
bot.sendPhoto(ADMIN_ID, photo, { caption: `Новое обращение от @${msg.from.username || msg.from.first_name} (ID: ${userId})\n\n${caption}` });
} else if (msg.video) {
// Если сообщение содержит видео
const video = msg.video.file_id;
bot.sendVideo(ADMIN_ID, video, { caption: `Новое обращение от @${msg.from.username || msg.from.first_name} (ID: ${userId})\n\n${caption}` });
} else {
// Если тип сообщения не поддерживается
bot.sendMessage(msg.chat.id, "К сожалению, данный тип сообщения не поддерживается.");
}
// Подтверждаем пользователю, что его обращение отправлено
bot.sendMessage(chatId, "Ваше обращение отправлено. Администратор свяжется с вами в ближайшее время.");
// Убираем пользователя из списка тех, кто пишет обращение
delete awaitingSupportMessage[userId];
}
});
Теперь, чтобы бот мог работать на постоянной основе, необходимо загрузить и запустить его на сервере. Для развёртывания я буду использовать сервис Timeweb Cloud.
Перед запуском бота на сервере, необходимо загрузить файлы проекта на GitHub.
Вводите эти команды в консоль последовательно.
Добавляем все изменения в текущей директории к следующему коммиту:
git add .
Создаем коммит с сообщением «first commit», фиксируя все изменения, добавленные командой git add
:
git commit -m "first commit"
Отправляем изменения на GitHub:
git push
Если вы ещё не являетесь клиентом Timeweb Cloud, предварительно нужно зарегистрироваться.
Для начала нужно создать новый проект. При создании вы можете указать иконку, название, описание, а также пользователей.
Далее, нам нужно создать облачный сервер. При создании сервера, в первом пункте перейдите во вкладку «Маркетплейс» и выберите Node.js, а версию Ubuntu поставьте самую новую. С помощью этого, когда ваш сервер начнёт работать, на нем сразу будет установлен Node.js и вам не придется устанавливать его вручную.
В регионе выберите тот, который ближе всего, где минимальный пинг.
Конфигурацию выбираете по своему усмотрению. Для запуска проекта достаточно минимальной конфигурации. Если в будущем проекту потребуется больше ресурсов, их можно будет добавить для уже работающего сервера.
В сети обязательно должен быть установлен публичный IP, а дополнительные услуги настраивайте по своему усмотрению.
В авторизации и Cloud-init ничего не меняйте. В информации о сервере введите имя сервера, его описание, а также выберите проект, который мы создали ранее.
Когда всё выбрали, нажимайте на кнопку «Заказать». Через некоторое время, сервер запустится и можно продолжить работу.
После создания сервера, на вкладке «дашборд», скопируйте Root-пароль для входа и перейдите на вкладку «консоль». Введите логин пользователя «root» и нажмите «Enter». Далее, вставьте пароль, который вы скопировали и также нажмите «Enter». При вставке или написании пароля, он не будет виден! Если всё правильно указали, то вас поприветствуют.
Теперь введите команду, чтобы получить последние обновления:
sudo apt-get update
Первоначально создадим новую папку, куда и поместим нашего бота. Вводите эти команды последовательно:
cd /
sudo mkdir Bot
cd Bot
Вместо папки «Bot», вы можете создать папку с другим именем.
Перенесем код с GitHub на наш сервер.
Чтобы удостовериться, что Git установлен на сервере (по умолчанию он всегда установлен) выполните:
git --version
Установим глобальные настройки Git, чтобы он был настроен на ваш профиль на GitHub:
git config --global user.name "ваш username на Github"
git config --global user.email "email, который указан при регистрации"
После этого, введите команду для клонирования репозитория, указав свою ссылку:
git clone https://github.com/Tulopex/School-Quiz
При клонировании у вас снова попросят ввести username
, а затем пароль. Если у вас установлена двухфакторная аутентификация на аккаунте, то при вводе обычного пароля, вам будет выдавать ошибку о том, что пароль неверный. Чтобы вы могли клонировать репозиторий с 2FA на аккаунте, вам нужно создать личный токен доступа.
Для создания личного токена доступа на GitHub выполните следующие шаги:
Перейдите в настройки профиля:
Нажмите на свою аватарку в правом верхнем углу и выберите «Settings»
В левом меню выберите «Developer settings».
Создание нового токена:
Установите параметры токена:
repo
. Нажмите кнопку «Generate token».
Скопируйте сгенерированный токен и сохраните его в безопасном месте. Учтите, что вы не сможете увидеть токен повторно после закрытия страницы.
Перейдите в вашу папку с проектом с помощью команды:
cd School-Quiz
Вместо School-Quiz укажите название своего проекта. Чтобы установить пакеты вашего проекта, выполните команду:
npm install
После установки пакетов, можно запустить проект, с помощью:
npm start
В консоли появится сообщение «Бот запущен». Но есть одна проблема, если вы перезапустите сервер или закроете консоль, то бот перестает работать! Чтобы бот работал постоянно, а также автоматически запускался после перезагрузки, достаточно установить менеджера процессов pm2
.
Установите pm2
командой:
sudo npm install pm2 -g
Затем запустите сервер Node.js, используя pm2
:
sudo pm2 start index.js --name "bot-quiz" --watch
В примере используется имя «bot-quiz». Так будет называться запущенный процесс. Вы можете придумать любое другое имя.
Настройте автозапуск при запуске или перезагрузке сервера:
sudo pm2 startup
Сохраните все введенные изменения:
sudo pm2 save
В данной статье мы подробно рассмотрели процесс создания Telegram-бота на платформе Node.js, начиная с регистрации бота через BotFather и заканчивая развертыванием готового решения на сервере.