如何构建和部署 Telegram 机器人?
在本文中,您将使用 Node.js 和 Back4app 的后台即服务(backend-as-a-service)构建一个 Telegram 机器人。然后,您将使用 Back4app 容器进行部署。
机器人是一种软件,可以在网络或平台上自动执行重复性任务。Telegram 机器人是使用 Telegram 机器人 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:您将使用该库向天气 API 发出 HTTP 请求。
- node-telegram-bot-api:该库可简化与 Telegram Bot API 的交互。
- dotenv:该软件包可帮助你从 .env 文件中加载环境变量。
- node-schedule:您需要使用该软件包来安排任务和自动更新天气。
- parse:您需要使用此软件包与 Back4app 解析后台交互。
现在,您已经设置好了开发环境。接下来,您需要在 Telegram 上创建一个机器人账户。
创建 Telegram Bot 账户
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
获取天气信息
要获取天气信息,您需要使用OpenWeatherMap API。
请求此 API 需要一个 API 密钥。要获取此 API 密钥,请登录您的账户(如果没有账户,请创建一个)。
然后,导航至个人资料中的 “我的 API 密钥 “部分,复制您的 API 密钥。
在.env
文件中存储 OpenWeatherMap 的 API 密钥:
OPENWEATHERMAP_TOKEN = <YOUR_OPEN_WEATHER_MAP_APIKEY>
由于机器人的功能围绕获取天气信息展开,因此需要定义一个函数,向 OpenWeatherMap 的 API 发送 GET 请求,使用axios.get
方法获取天气信息。
将下面的代码块添加到您的weather.js
文件中,以便从 OpenWeatherMap API 请求 GET 天气信息:
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
对象,通过使用setCity
函数将 Telegram 聊天 ID 映射到城市名称,跟踪机器人用户感兴趣的城市。
该功能可让您的机器人根据用户的偏好,持续接收哪个城市的天气更新。
代码块中的init
函数每 6 小时设置一次计划任务,遍历userCities
中存储的所有聊天 ID。init
函数使用天气
模块获取该城市的当前天气。
您的机器人需要持续保持用户状态,以跟踪不同用户及其偏好的城市。您可以使用 Back4app 的后台服务来实现这一点。
要让机器人跟踪不同用户及其首选城市,可使用 Back4app 的后台服务存储机器人用户的首选城市。
创建 Back4app 后台
要使用 Back4app 后台服务,您需要一个 Back4app 账户。如果您没有账户,可以免费注册。
登录您的账户,点击右上角的 “NEW APP “按钮。为您的应用程序命名,然后点击 “创建 “按钮。
点击 “创建 “按钮后,Back4app 将生成您的应用程序,并引导您进入应用程序控制面板。
从 Node.js 项目连接到 Back4App 上的应用程序实例需要用 Back4app 的应用程序凭据初始化您安装的解析 SDK:应用程序 ID
和Javascript KEY
。
点击侧边栏上的 “应用程序设置”,进入 “安全与密钥 “部分,从 Back4app 获取应用程序 ID
和JavaScript
密钥。
将它们保存在.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 的人工智能代理来完成这项任务。
要创建这个带有相应字段的类,请导航到屏幕上的 “人工智能代理 “选项卡,并向代理发出以下提示:
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
命令外,机器人还能理解两个主要命令。每次用户交互(包括命令)都会触发用户状态的更新,用户状态和聊天 ID 一起存储在UserState
类中。
通过这种状态管理,机器人可以在对话中记住每个用户的特定细节,比如他们偏好的天气更新城市。
要开始使用在 Back4App 数据库中创建的UserState
类跟踪用户状态,需要使用凭据初始化 Parse SDK。
将下面的代码块添加到stateManager.js
中,用连接到 Back4app Parse 后台所需的凭据初始化 Parse SDK:
// 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/>';
接下来,在stateManager.js
文件中定义一个 Parse 对象,以表示 Back4app Parse 后端中UserState
类的模式,从而让机器人与存储在数据库中的用户状态进行交互。
就像这样
// stateManager.js
const UserState = Parse.Object.extend('UserState');
接下来,您需要让机器人根据数据库中存储的用户 ID 获取特定用户的当前对话状态。
要检索用户的状态,需要使用用户 ID 在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
)构造一个查询,以查找用户的状态对象,如果找到,则检索用户状态。
获取用户状态后,您需要启用机器人,根据用户 ID
和提供的状态
信息更新与该用户相关的对话状态。
例如,更新对话状态可使机器人更新首选城市,从而定期获得天气更新。
就像这样
// 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
对象,设置状态
属性,并将该对象保存到数据库中。
接下来,在stateManager.js
文件中添加以下代码块,定义一个重置用户状态的函数:
// stateManager.js
async function resetUserState(userId) {
await setUserState(userId, {});
}
resetUserState
函数异步将用户状态设置为空对象{}
,以重置数据库中的用户状态。
确保始终存在一个状态对象,以跟踪前机器人用户和新机器人用户的操作。在stateManager.js
文件中添加以下代码块:
// stateManager.js
async function ensureUserState(userId) {
let state = await getUserState(userId);
if (!state) {
await setUserState(userId, {});
}
}
该代码块定义了一个ensureUserState
函数,用于根据用户 ID 检索状态对象,确保 Back4app Parse 后台的UserState
类中存在所提供用户
ID 的用户状态数据。
它使用getUserState
函数获取用户状态,如果不存在用户状态,则使用setUserState
函数将用户状态设置为空对象{}
。
导出所有函数,以便在其他 Javascript 源文件中使用:
// stateManager.js
module.exports = {
getUserState,
setUserState,
resetUserState,
ensureUserState,
};
处理用户与机器人的交互
为了让您的机器人能够监听start
、getWeather
和setCity
命令,您需要定义事件监听器,将文本与这三个命令相匹配,以运行回调函数。
这将允许机器人执行与命令相关的任务。
要与 Telegram Bot API 交互以定义机器人行为,请从node-telegram-bot-api
库导入TelegramBot
类,并创建该类的新实例:
// bot.js
const TelegramBot = require('node-telegram-bot-api');
const token = process.env.TELEGRAM_BOT_TOKEN;
const bot = new TelegramBot(token, { polling: true });
上面的代码块创建了一个TelegramBot
类的新实例,包含两个参数:机器人令牌和一个对象。
该对象会将轮询值设置为true
,使机器人能够持续检查 Telegram 服务器的消息和更新。
接下来,导入在本项目中创建的模块。您将使用这些模块来实现机器人的功能,例如获取天气更新、设置首选城市和管理用户状态。
添加以下代码,导入必要的模块:
// bot.js
const weather = require('./weather');
const cityManager = require('./cityManager');
const stateManager = require('./stateManager');
上面的代码块导入了您在所有源文件中创建的函数,使您可以在bot.js
文件中调用这些函数。
要设置命令,可以使用TelegramBot
类的onText
方法。该方法会设置一个监听器来实现回调函数,以执行某些逻辑。
将下面的代码块添加到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
“命令指定自己喜欢的城市以获取天气更新。
收到该命令后,机器人会使用setUserState
函数将用户状态更新为 “SET_CITY”,并提示用户输入所需的城市。
将下面的代码块添加到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 文件来处理机器人如何与 Telegram 的 API 交互并响应用户消息。
- 该入口文件还将设置一个服务器,允许你的机器人在 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}`);
});
上面的代码块通过创建一个简单的 HTTP 服务器来设置 Telegram 机器人的运行。该服务器作为入口点,允许机器人在容器环境中运行。
脚本会导入机器人的核心逻辑,并指定 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 容器上部署。
接下来,在GitHub账户上安装Back4App Containers GitHub 应用程序,并授予该应用程序访问应用程序代码库所需的权限。
完成 GitHub 配置后,请访问 Back4app 主页并点击屏幕右上角的 “新建应用程序“按钮。
这将带您进入初始化界面,您需要在此选择要创建的应用程序类型。选择 Back4app 代理选项,如下图所示。
选择 Back4app 代理选项后,您将被重定向到 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"
用实际值替换占位符。上述提示将启动部署过程。完成后,人工智能代理将作出回应,表示部署成功或待定。
您应该会收到类似下面的回复:
如果您收到待部署,您可以在Back4app 容器仪表板上监控应用程序的部署状态。或者,您也可以在 Back4app 容器上手动部署应用程序。
结论
在本文中,您将学习如何使用 Node.js 创建 Telegram 机器人。您将学习如何创建 Telegram 机器人账户、处理机器人命令和用户交互。
在 Back4app 人工智能代理的帮助下,您还为机器人创建了一个后台,这使您能够有效管理用户状态,并在对话中存储信息,例如用户喜欢的城市,以便定期接收天气更新。
您可以在此GitHub 代码库中找到完整代码。