Как создать и развернуть бота Telegram?
В этой статье вы создадите Telegram-бота с помощью Node.js и Backend-as-a-service от Back4app. Затем вы развернете его с помощью контейнеров Back4app.
Боты – это программное обеспечение, которое может выполнять автоматические повторяющиеся задачи в сети или на платформе. Боты Telegram создаются с помощью Telegram bot API и специально разработаны для работы в Telegram.
Вы можете создать ботов Telegram, которые будут выполнять различные задачи в Telegram, например, получать информацию о погоде или заголовки новостей, а также проводить викторины для развлечения.
Кроме того, они могут автоматизировать такие задачи, как планирование напоминаний и простая аутентификация пользователей.
Contents
Настройка среды разработки
В этой статье рассказывается о боте для Telegram, который позволяет пользователям настроить автоматическое обновление погоды в их любимом городе каждые 6 часов или получать мгновенную информацию о погоде в любом городе по их выбору.
Чтобы создать каталог проекта, выполните следующие команды:
# создайте свой каталог проекта
mkdir telegram-weather-bot
# cd в каталог вашего проекта
cd telegram-weather-bot
# Инициализировать npm
npm init -y
Приведенные выше команды создают каталог telegram-weather-bot
, перемещаются в него и инициализируют в нем npm.
В файл package.json
добавьте следующий скрипт запуска, чтобы запустить бота:
"start": "node server.js"
Затем выполните приведенную ниже команду, чтобы установить пакеты, необходимые для этого проекта:
npm install axios node-telegram-bot-api dotenv node-schedule parse
Вышеприведенная команда установила следующие пакеты:
- axios: Вы будете использовать эту библиотеку для выполнения HTTP-запросов к погодному API.
- node-telegram-bot-api: Эта библиотека упрощает взаимодействие с Telegram Bot API.
- dotenv: Этот пакет поможет вам загрузить переменные окружения из файла .env.
- node-schedule: Этот пакет понадобится вам для планирования задач и автоматизации обновления погоды.
- parse: Этот пакет понадобится вам для взаимодействия с Back4app Parse Backend.
Итак, вы настроили среду разработки. Далее вам нужно создать аккаунт бота в Telegram.
Создание учетной записи бота Telegram
Учетная запись бота Telegram будет служить идентификатором вашего бота на платформе Telegram. Пользователи смогут взаимодействовать с ботом через этот аккаунт.
Чтобы создать своего Telegram-бота, запустите приложение Telegram, введите в строке поиска “BotFather” и нажмите на проверенный топ-результат.
BotFather – это бот для Telegram, который позволяет вам быстро создавать других ботов. Введите команду /newbot, чтобы начать процесс создания бота. Вы укажете имя и уникальное имя пользователя для вашего бота.
После того как вы укажете имя и логин вашего бота, BotFather предоставит уникальный токен, который позволит вам взаимодействовать с ботом и управлять его аккаунтом.
Сохраните токен бота в вашем проекте, создав файл .env
в корневом каталоге и вставив в него токен бота. Например:
TELEGRAM_BOT_TOKEN = <YOUR_BOT_TOKEN>
Теперь, когда вы получили токен бота и сохранили его в своем проекте, вы можете создать своего Telegram-бота.
Создание бота Telegram
В этом разделе вы узнаете, как создать погодного бота в Telegram и интегрировать установленные библиотеки для выполнения таких функций, как обработка команд, управление состоянием пользователя и получение данных из погодного API.
Чтобы начать процесс сборки, структурируйте каталог вашего бота так, как показано ниже:
telegram-weather-bot/
├── node_modules/
├── src/
| ├── bot.js # файл для обработки взаимодействия бота с пользователем
| ├── weather.js # Модуль для получения данных о погоде
| ├── stateManager.js # Модуль для управления состоянием пользователя с помощью Back4App
| └── cityManager.js # Управляет настройками города пользователя и отправляет обновления погоды
├── .env
├── package.json
├── server.js # Точка входа для вашего приложения
└── package-lock.json
Получение информации о погоде
Для получения информации о погоде вы будете использовать API OpenWeatherMap.
Для выполнения запросов к этому API требуется ключ API. Чтобы получить этот API-ключ, войдите в свою учетную запись (или создайте ее, если у вас ее нет).
Затем перейдите в раздел “Мои API-ключи” в своем профиле и скопируйте свой API-ключ.
Сохраните ключ API OpenWeatherMap в файле .env
:
OPENWEATHERMAP_TOKEN = <YOUR_OPEN_WEATHER_MAP_APIKEY>
Поскольку функциональность бота связана с получением информации о погоде, определите функцию, которая будет делать GET-запрос к API OpenWeatherMap, чтобы получить информацию о погоде с помощью метода axios.get.
Добавьте приведенный ниже блок кода в ваш файл weather.js
, чтобы сделать GET-запрос на получение информации о погоде из API OpenWeatherMap:
const axios = require('axios');
const apiKey = process.env.OPENWEATHERMAP_TOKEN;
async function getWeather(city) {
try {
const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`;
const response = await axios.get(url);
const temp = response.data.main.temp;
const description = response.data.weather[0].description;
return `The weather in ${city} is ${temp}°C with ${description}.`;
} catch (error) {
console.error('Error fetching weather:', error);
throw error;
}
}
module.exports = { getWeather }
Приведенный выше блок кода определяет функцию getWeather
, которая принимает в качестве аргумента название города
и возвращает температуру и описание погоды из ответа API.
Чтобы обеспечить пользователей регулярными обновлениями погоды каждые 6 часов, необходимо реализовать функцию планировщика, которая будет запускать функцию getWeather
, чтобы вернуть обновления погоды для выбранного города.
Планирование обновлений погоды
Чтобы запланировать возврат обновлений погоды для выбранного города, добавьте приведенный ниже блок кода в файл cityManager.js:
const schedule = require('node-schedule');
const weather = require('./weather');
let userCities = {};
function setCity(chatId, city) {
userCities[chatId] = city;
}
function init(bot) {
schedule.scheduleJob('0 */6 * * *', function() {
for (let chatId in userCities) {
const city = userCities[chatId];
weather.getWeather(city).then(response => {
bot.sendMessage(chatId, response);
}).catch(error => {
bot.sendMessage(chatId, "Failed to retrieve weather.");
});
}
});
}
module.exports = { setCity, init };
В приведенном выше блоке кода создаются две функции: setCity
и init
.
В этом блоке кода объявляется объект userCities
для отслеживания городов, которыми интересуются пользователи бота, путем сопоставления их идентификаторов чатов Telegram с названиями городов с помощью функции setCity
.
Эта функция позволяет вашему боту учитывать предпочтения пользователей относительно того, для какого города они хотят получать обновления погоды.
Функция init
в этом блоке кода устанавливает запланированное задание каждые 6 часов, которое перебирает все идентификаторы чатов, хранящиеся в userCities
. Функция init
использует модуль погоды
для получения текущей погоды для данного города.
Вашему боту необходимо сохранять состояние пользователя, чтобы отслеживать различных пользователей и их предпочитаемые города. Для этого вы можете использовать бэкенд как сервис Back4app.
Чтобы ваш бот мог отслеживать различных пользователей и их предпочитаемые города, храните предпочитаемый город пользователя бота, используя бэкенд Back4app как сервис.
Создание бэкэнда Back4app
Чтобы использовать бэкэнд Back4app в качестве сервиса, вам нужен аккаунт Back4app. Если у вас его нет, вы можете зарегистрироваться бесплатно.
Войдите в свою учетную запись и нажмите кнопку “NEW APP” в правом верхнем углу. Назовите свое приложение и нажмите кнопку “СОЗДАТЬ”.
После нажатия кнопки “CREATE” Back4app сгенерирует ваше приложение и направит вас на панель приложений.
Подключение к экземпляру приложения на Back4App из вашего Node.js-проекта требует инициализации установленного вами parse SDK с учетными данными приложения Back4app: ID приложения
и Javascript KEY
.
Получите идентификатор приложения
и ключ JavaScript
от Back4app, перейдя в раздел “Безопасность и ключи”, нажав “Настройки приложения” на боковой панели.
Сохраните их в файле .env
. Ваш текущий файл .env
должен быть похож на приведенный ниже:
TELEGRAM_BOT_TOKEN= "<YOUR_TELEGRAM_BOT_TOKEN_HERE>"
OPENWEATHERMAP_TOKEN= "<YOUR_OPENWEATHERMAP_TOKEN_HERE>"
BACK4APP_APP_ID= "<YOUR_BACK4APP_APP_ID_HERE>"
BACK4APP_JAVASCRIPT_KEY= "<YOUR_BACK4APP_JAVASCRIPT_KEY_HERE>"
Далее вам нужно создать новый класс “UserState” с двумя полями: userId (строка) и state (объект). Для выполнения этой задачи вы будете использовать ИИ-агента Back4app.
Чтобы создать этот класс с соответствующими полями, перейдите на вкладку “AI Agent” на экране и дайте агенту следующую подсказку:
Create a new class, "UserState," in my Back4app application with the APP ID “<YOUR_BACK4APP_APP_ID_HERE>”. The "UserState" class will have two fields: userId (string) and state (object).
Вы должны получить ответ, аналогичный изображенному ниже:
Если вы проверите свою панель Back4app, то увидите, что класс UserState
успешно создан.
Управление состоянием пользователя в вашем Telegram-боте
Чтобы управлять потоком взаимодействия между пользователем и ботом, необходимо определить состояние пользователя, указывающее, какую команду бот ожидает от пользователя.
Помимо команды /start
, бот понимает две основные команды. Каждое взаимодействие с пользователем (включая команды) вызывает обновление его состояния, которое хранится вместе с идентификатором чата в классе UserState
.
Такое управление состоянием позволяет боту запоминать конкретные детали для каждого пользователя в рамках беседы, например, предпочитаемый город для получения обновлений погоды.
Чтобы начать отслеживать состояния пользователей с помощью класса UserState
, созданного в базе данных Back4App, необходимо инициализировать Parse SDK с помощью учетных данных.
Добавьте приведенный ниже блок кода в stateManager.js
, чтобы инициализировать Parse SDK с необходимыми учетными данными для подключения к Back4app Parse Backend:
// stateManager.js
const Parse = require('parse/node');
Parse.initialize(
process.env.BACK4APP_APP_ID,
process.env.BACK4APP_JAVASCRIPT_KEY
);
Parse.serverURL = '<https://parseapi.back4app.com/>';
Далее определите объект Parse в файле stateManager.js
, чтобы представить схему класса UserState
в бэкенде Back4app Parse, что позволит вашему боту взаимодействовать с состоянием пользователя, хранящимся в базе данных.
Например, так:
// stateManager.js
const UserState = Parse.Object.extend('UserState');
Далее вам нужно будет разрешить боту получать текущее состояние беседы конкретного пользователя на основе его идентификатора, хранящегося в базе данных.
Чтобы получить состояние пользователя, вам нужно выполнить запрос к классу UserState
с идентификатором пользователя, чтобы найти состояние, сохраненное в базе данных.
Например, так:
// stateManager.js
async function getUserState(userId) {
const query = new Parse.Query(UserState);
query.equalTo('userId', userId.toString());
const userState = await query.first();
return userState ? userState.get('state') : null;
}
В приведенном выше блоке кода определена функция getUserState
, которая асинхронно извлекает данные о состоянии пользователя.
Функция строит запрос для поиска объекта состояния пользователя на основе аргумента(userId
) и извлекает состояние пользователя, если оно найдено.
После получения данных о состоянии пользователя вам нужно будет разрешить боту обновлять состояние беседы, связанное с этим пользователем, на основе его идентификатора пользователя
и предоставленной информации о состоянии
.
Например, обновление состояния разговора позволит боту обновить предпочитаемый город для получения регулярных обновлений погоды.
Например, так:
// stateManager.js
async function setUserState(userId, state) {
const query = new Parse.Query(UserState);
query.equalTo('userId', userId.toString());
let userState = await query.first();
if (!userState) {
userState = new UserState();
userState.set('userId', userId.toString());
}
userState.set('state', state);
await userState.save();
}
Функция в приведенном выше блоке кода строит запрос для поиска объекта состояния пользователя на основе userId
, создает новый объект UserState
, если такового не существует, устанавливает атрибут state
и сохраняет объект в базе данных.
Затем определите функцию для сброса состояния пользователя, добавив следующий блок кода в файл stateManager.js
:
// stateManager.js
async function resetUserState(userId) {
await setUserState(userId, {});
}
Функция resetUserState
асинхронно устанавливает состояние пользователя в пустой объект {}
, чтобы сбросить состояние пользователя в базе данных.
Убедитесь, что объект state всегда присутствует, чтобы отслеживать действия бывшего и нового пользователя бота. Добавьте следующий блок кода в файл stateManager.js
:
// stateManager.js
async function ensureUserState(userId) {
let state = await getUserState(userId);
if (!state) {
await setUserState(userId, {});
}
}
Этот блок кода определяет функцию ensureUserState
, которая извлекает объект состояния на основе идентификатора пользователя, убеждаясь, что данные о состоянии пользователя существуют для указанного идентификатора пользователя
в классе UserState
на бэкенде Back4app Parse.
Он получает состояние пользователя с помощью функции getUserState
и, если состояние не существует, устанавливает состояние в пустой объект {}
с помощью функции setUserState
.
Экспортируйте все функции, чтобы иметь возможность использовать их в других исходных файлах Javascript:
// stateManager.js
module.exports = {
getUserState,
setUserState,
resetUserState,
ensureUserState,
};
Обработка взаимодействия пользователя с ботом
Чтобы ваш бот мог прослушивать команды start
, getWeather
и setCity
, вы определите слушателей событий, которые будут сопоставлять текст с этими тремя командами для запуска функций обратного вызова.
Это позволит боту выполнять задания, связанные с командами.
Чтобы взаимодействовать с Telegram Bot API и определить поведение вашего бота, импортируйте класс TelegramBot
из библиотеки node-telegram-bot-api
и создайте новый экземпляр класса:
// bot.js
const TelegramBot = require('node-telegram-bot-api');
const token = process.env.TELEGRAM_BOT_TOKEN;
const bot = new TelegramBot(token, { polling: true });
Приведенный выше блок кода создает новый экземпляр класса TelegramBot
с двумя аргументами: токеном бота и объектом.
Объект устанавливает значение polling в true
, чтобы бот мог постоянно проверять сообщения и обновления с серверов Telegram.
Затем импортируйте модули, которые вы создали в этом проекте. Вы будете использовать эти модули для реализации функций бота, таких как получение обновлений погоды, установка предпочитаемого города и управление состоянием пользователя.
Добавьте следующий код, чтобы импортировать необходимые модули:
// bot.js
const weather = require('./weather');
const cityManager = require('./cityManager');
const stateManager = require('./stateManager');
Блок кода выше импортирует функции, созданные вами во всех исходных файлах, позволяя вызывать их в файле bot.js
.
Чтобы задать команду, вы используете метод onText
, доступный классу TelegramBot
. Этот метод устанавливает слушатель для реализации функции обратного вызова для выполнения определенной логики.
Добавьте приведенный ниже блок кода в файл bot.js
, чтобы установить обработчик команды /start
, которую бот будет активно прослушивать с помощью метода onText
:
// bot.js
bot.onText(/\\/start/, async (msg) => {
const welcomeMessage = "Welcome to the Weather Bot! Use the commands below to interact:\\n" +
"/setCity - Set your preferred city for weather updates.\\n" +
"/getWeather - Get instant weather information for any city.\\n";
await bot.sendMessage(msg.chat.id, welcomeMessage);
stateManager.ensureUserState(msg.chat.id);
});
Блок кода выше позволит боту запустить функцию обратного вызова, отправив пользователю приветственное сообщение, в котором подробно описано, как работает бот.
Бот устанавливает начальное состояние пользователя с помощью функции ensureUserState
, обеспечивая “чистый лист” для каждого взаимодействия с пользователем.
Далее добавьте приведенный ниже блок кода в файл bot.js
, чтобы установить обработчик команды /setCity
, которую бот будет активно прослушивать с помощью метода onText
:
// bot.js
bot.onText(/\\/setCity$/, async (msg) => {
stateManager.setUserState(msg.chat.id, { expect: 'SET_CITY' });
bot.sendMessage(msg.chat.id, "Which city do you want to set as your preferred city for weather updates?");
});
Блок кода выше позволяет пользователям указать предпочитаемый город для обновления погоды с помощью команды"/setCity
“.
Получив эту команду, бот обновляет состояние пользователя до “SET_CITY” с помощью функции setUserState
и предлагает пользователю ввести желаемый город.
Добавьте приведенный ниже блок кода в файл bot.js
, чтобы установить обработчик команды /getWeather
, которую бот будет активно прослушивать с помощью метода onText
:
// bot.js
bot.onText(/\\/getWeather$/, async (msg) => {
stateManager.setUserState(msg.chat.id, { expect: 'GET_WEATHER' });
bot.sendMessage(msg.chat.id, "Which city do you want to get weather information for?");
});
Команда “/getWeather
” заставляет бота обновить состояние пользователя до “GET_WEATHER” и предлагает ему указать город, для которого ему срочно нужна информация о погоде.
Обработка входящих сообщений
Чтобы обрабатывать входящие сообщения для вашего Telegram-бота, вам нужно настроить слушатель событий, который будет запускать функцию обратного вызова каждый раз, когда бот получает новое сообщение.
Добавьте приведенный ниже блок кода в файл bot.js
, чтобы настроить обработчик сообщений для прослушивания команд и ответов пользователя:
// bot.js
// Handle incoming messages
bot.on('message', async (msg) => {
if (msg.text.startsWith('/')) {
// If the message is a command, reset the user state
stateManager.resetUserState(msg.chat.id);
} else {
// If it's not a command, check user state
const state = await stateManager.getUserState(msg.chat.id);
if (state && state.expect === 'SET_CITY') {
// If expecting SET_CITY, set city and reset state
const city = msg.text;
cityManager.setCity(msg.chat.id, city);
bot.sendMessage(msg.chat.id, `City set to ${city}. You will receive weather updates every 2 minutes.`);
stateManager.resetUserState(msg.chat.id);
} else if (state && state.expect === 'GET_WEATHER') {
// If expecting GET_WEATHER, get weather and reset state
const city = msg.text;
weather.getWeather(city).then(response => {
bot.sendMessage(msg.chat.id, response);
}).catch(error => {
bot.sendMessage(msg.chat.id, "Failed to retrieve weather.");
});
stateManager.resetUserState(msg.chat.id);
}
}
});
// Initialize the init function from cityManager.js for regular weather updates
cityManager.init(bot);
Этот блок кода устанавливает общий обработчик сообщений, который прослушивает отправленные ему текстовые сообщения и служит ядром логики взаимодействия.
Если сообщение начинается с прямой косой черты (“/”), оно считается командой. В этом случае обработчик сбрасывает состояние пользователя, чтобы обеспечить новый старт для новой команды.
В противном случае обработчик проверяет текущее состояние пользователя(stateManager.getUserState
), чтобы понять его намерения.
Если пользователь передает команду “/setCity”, обработчик бота использует cityManager.setCity
для сохранения выбранного города и подтверждает обновление.
Если пользователь передает команду “/getWeather
“, обработчик получает информацию о погоде в указанном городе с помощью функции weather.getWeather
и отправляет ответ обратно пользователю.
В приведенном выше блоке кода выполняется cityManager.init(bot)
, чтобы запустить запланированную задачу получения обновлений погоды для выбранного города.
Теперь, когда вы закончили работу с логикой бота, настройте сервер, чтобы он мог запускаться при развертывании в контейнере Back4app.
Создание файла записи
Вы создадите входной файл, который будет инициализировать все приложение бота. Этот файл будет выполнять две функции.
- Входной файл запускает логику бота, требуя файл JavaScript, который управляет взаимодействием вашего бота с API Telegram и отвечает на сообщения пользователей.
- Файл записи также настроит сервер, чтобы ваш бот мог работать в контейнере Back4app. Контейнеры Back4app требуют открытых портов для успешного развертывания вашего приложения.
Перейдите к файлу server.js
в каталоге вашего проекта. Этот файл будет управлять созданием сервера. Добавьте приведенный ниже блок кода в файл server.js
:
const http = require('http');
require('./src/bot'); // Import bot logic
const port = 3000;
http
.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('My Telegram bot is running\\n');
})
.listen(port, () => {
console.log(`Server running on port ${port}`);
});
Приведенный выше блок кода настраивает бота Telegram на работу, создавая простой HTTP-сервер. Этот сервер выступает в качестве точки входа, позволяя боту функционировать в среде контейнера.
Скрипт импортирует основную логику вашего бота и указывает порт Back4app, чтобы ваш бот мог развернуться в контейнере Back4app.
После создания файла записи вы можете протестировать Telegram-бота локально, прежде чем развернуть его в контейнере Back4app.
Тестирование бота Telegram
Запустите своего бота Telegram, выполнив следующую команду:
node server.js
Чтобы взаимодействовать с ботом, откройте приложение Telegram и найдите имя бота в строке поиска. Войдите в чат с ботом и отправьте команду /start.
В ответ бот должен выдать приветственное сообщение и список команд. Отправьте боту команду.
Бот позволяет задать предпочитаемый город и получать регулярные обновления погоды с помощью команды /setCity
.
Команда /getWeather
, как показано на рисунке выше, позволяет мгновенно получить информацию о погоде в конкретном городе.
Бот должен вести себя примерно так же, как показано на изображении выше, реагировать на ваши команды и взаимодействовать с вами, как и предполагалось.
Развертывание бота Telegram в контейнерах Back4App
После тестирования бота и проверки его работоспособности вы можете развернуть его в контейнерах Back4app. Для этого сначала нужно создать Dockerfile
для вашего проекта.
В корневом каталоге вашего проекта создайте файл Dockerfile
и добавьте в него блок кода, приведенный ниже:
# Specify base image
FROM node:18-alpine
# Specify the working directory
WORKDIR /app
# Copy package.json and package-lock.json
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
# Run the app
CMD ["npm", "start"]
После создания Dockerfile
отправьте локальный репозиторий на GitHub, чтобы сделать его доступным для развертывания в контейнерах Back4app.
Затем установите приложение Back4App Containers GitHub App на свой аккаунт GitHub и предоставьте приложению необходимые разрешения для доступа к репозиторию кода вашего приложения.
После того как вы закончите с настройкой GitHub, перейдите на главную страницу Back4app и нажмите кнопку “Новое приложение” в правом верхнем углу экрана.
Это приведет вас к экрану инициализации, где вам нужно будет выбрать тип приложения, которое вы хотите создать. Выберите вариант агента Back4app, как показано на изображении ниже.
Когда вы выберете опцию Back4app Agent, вы будете перенаправлены на страницу агента Back4app AI.
Введите указанный ниже запрос для развертывания приложения в контейнерах Back4app:
Deploy my "YOUR_REPOSITORY_URL" repository on GitHub to Back4App Containers.
Here are the required environmental variables:
TELEGRAM_BOT_TOKEN = "TELEGRAM_BOT_TOKEN"
OPENWEATHERMAP_TOKEN = "WEATHER_API_TOKEN"
BACK4APP_APP_ID = "BACK4APP_APP_ID"
BACK4APP_JAVASCRIPT_KEY = "BACK4APP_JAVASCRIPT_KEY"
Замените заполнители их реальными значениями. Приведенная выше подсказка запустит процесс развертывания. По завершении агент AI ответит, сообщив об успехе или ожидании развертывания.
Вы должны получить ответ, аналогичный приведенному ниже:
Если вы получили уведомление о предстоящем развертывании, вы можете отслеживать статус развертывания вашего приложения на панели управления контейнерами Back4app. Кроме того, вы можете развернуть свое приложение на контейнерах Back4app вручную.
Заключение
В этой статье вы узнали, как создать бота Telegram с помощью Node.js. Вы узнали, как создать аккаунт бота Telegram, обрабатывать команды бота и взаимодействовать с пользователями.
Вы также создали бэкэнд для своего бота с помощью ИИ-агента Back4app, что позволило вам эффективно управлять состоянием пользователя и сохранять информацию в разговорах, например, предпочитаемый город пользователя, чтобы регулярно получать обновления погоды.
Полный код можно найти в этом репозитории GitHub.