作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。
介绍
在本教程中,您将使用 Node.js, telegraf
, jimp
,以及 Pexels API 来构建 Telegram)聊天机器人,它将向您发送随机选择的图像,其中包含一个事实。 电报机器人是一个机器人,您可以通过您喜爱的电报客户端使用自定义削减命令进行交互。 您将通过电报创建机器人,并定义其逻辑,以选择随机的动物图像和使用JavaScript的动物事实。
在本教程结束时,您将有一个Telegram聊天机器人,看起来如下:
一旦你完成了你的机器人,你会收到一个关于动物的事实,每次你发送一个自定义的Telegram削减命令。
前提条件
为了遵循本教程,读者将需要以下工具:
- Node.js 本地安装,您可以按照 如何安装 Node.js 和创建本地开发环境进行操作。 * 一个 Telegram帐户来注册并选择您喜爱的 Telegram 客户端。 * 一个 Pexels帐户,允许您免费下载照片和视频。
本教程已通过 Node v12.18.2 和 npm v6.14.8 进行验证。
步骤 1 – 创建项目根目录
在本节中,你将创建目录,在那里你将建立聊天机器人,创建一个节点项目,并安装所需的依赖。
打开终端窗口,创建一个名为facts-bot
的新目录:
1mkdir facts-bot
导航到目录:
1cd facts-bot
创建一个名为temp
的目录:
1mkdir temp
使用上述命令,您创建了一个名为temp
的目录. 在此目录中,您将暂时存储您的机器人将发送给用户的图像。
运行npm的init
命令将创建一个package.json
文件,该文件将管理您的依赖和元数据。
运行初始化命令:
1npm init
若要接受默认值,请按ENTER
按一下所有提示,或者您可以个性化您的响应。 要做到这一点,请在教程如何使用 Node.js 模块与 npm 和 package.json
(https://andsky.com/tech/tutorials/how-to-use-node-js-modules-with-npm-and-package-json# step-1-%E2%80%94-creating-a-packagejson-file)的步骤 1 中查看 npm 的初始化设置。
打开 package.json 文件并编辑它:
1nano package.json
现在,您将更新您的 package.json
文件中的属性. 用突出的代码取代文件内部的内容:
1[label package.json]
2{
3 "name": "facts-bot",
4 "version": "1.0.0",
5 "description": "",
6 "main": "main.js",
7 "scripts": {
8 "start": "nodemon main.js"
9 },
10 "author": "",
11 "license": "ISC"
12}
在这里,你更改了主
和脚本
的属性. 通过更改主
属性,你将应用程序的主文件设置为main.js
。 这将通知节点main.js
文件是你的程序的主要输入点。 在脚本
属性中,你已添加了名为开始
的脚本
,允许你设置在启动应用程序时应该运行的命令。 一旦你打电话给脚本
,命令nodemon
将运行你在下一步创建的main.js
文件。
有了你的设置现在在你的 package.json
文件中定义,你现在将创建一个文件,将存储你的环境变量. 在你的终端,创建一个名为 .env
的文件:
1touch .env
在您的 .env
文件中,您将存储您的 Telegram 机器人代币和 Pexels API 密钥. 一个 Telegram 机器人代币允许您与您的 Telegram 机器人进行交互. Pexels API 密钥允许您与 Pexels API 进行交互。
这一次,你将使用npm
来安装依赖性telegraf
,dotenv
,pexels
,jimp
和uuid
。你还将使用--save
旗帜来保存依赖性。
1npm install telegraf dotenv pexels jimp uuid --save
在这个命令中,你已经安装了:
telegraf
:一个帮助您开发自己的Telegram机器人库,使用JavaScript或TypeScript。您将使用它来构建您的机器人。 *dotenv
:一个零依赖模块,将环境变量从.env 文件加载到process.env
。您将使用该模块从您创建的.env
文件中获取bot代码和Pexels API密钥。 *pexels
:一个方便的包装器,可以在Node.js和浏览器中的服务器上使用Pexels API,您将使用该模块从Pexels获取动物图像。 *jimp
:一个完全用JavaScript
现在,安装 nodemon
作为 dev 依赖:
1npm install nodemon --save-dev
nodemon
是一个开发基于Node.js的应用程序的工具,通过自动重新启动Node应用程序,当它检测到文件更改的目录。
<$>[注] 注: 在写作时,这些是正在使用的模块的版本:telegraf
: 4.3.0 ; dotenv
: 8.2.0 ; pexels
: 1.2.1 ;jimp
: 0.16.1 ; uuid
: 8.3.2 ; nodemon
: 2.0.12 <$>
在此步骤中,您创建了一个项目目录,并为您的机器人初始化了一个Node.js项目,您还安装了构建机器人所需的模块,在下一步,您将在Telegram中注册机器人,并获取Pexels API的API密钥。
步骤 2 – 注册您的机器人并从 Pexels API 获取 API 密钥
在本节中,您将首先使用 BotFather注册机器人,然后获取Pexels API的API密钥。
打开您喜爱的 Telegram 客户端,搜索@BotFather
,然后开始聊天。
选择您的机器人名称和用户名后,您将收到包含您的机器人访问代码的消息:
复制机器人代码,并打开您的 .env
文件:
1nano .env
在一个名为BOT_TOKEN
的变量中保存 Bot 代币:
1[label .env]
2BOT_TOKEN = "Your bot token"
现在你已经将你的机器人代币保存到.env 文件中,是时候获取 Pexels API 密钥了。
点击 Pexels,然后登录您的 Pexels 帐户。 点击 Image & Video API 选项卡,创建一个新的 API 密钥:
复制 API 密钥,然后打开您的 .env
文件:
1nano .env
将 API 密钥保存到名为 PEXELS_API_KEY
的变量中。
1[label .env]
2BOT_TOKEN = "Your_bot_token"
3PEXELS_API_KEY = "Your_Pexels_API_key"
在本节中,您已经注册了您的机器人,获取了您的 Pexels API 密钥,并将您的机器人代码和 Pexels API 密钥存储在您的 .env
文件中。
步骤 3 – 创建main.js
文件
在本节中,你将创建并构建你的机器人,你将创建一个标签为main.js 的文件,这将包含你的机器人的逻辑。
在项目的 root 目录中,使用您偏好的文本编辑器创建并打开main.js 文件:
1nano main.js
在main.js
文件中,添加以下代码来导入您要使用的库:
1[label main.js]
2const { Telegraf } = require('telegraf')
3const { v4: uuidV4 } = require('uuid')
4require('dotenv').config()
5let factGenerator = require('./factGenerator')
在这个代码块中,你需要在telegraf
,uuid
,dotenv
模块和一个名为factGenerator.js
的文件。你将使用telegraf
模块来启动和管理机器人,uuid
模块来生成图像的唯一文件名称,以及dotenv
模块来将你的Telegram机器人标记和Pexels API密钥存储在.env
文件中。
在要求
语句下方,添加以下代码来创建机器人的实例:
1[label main.js]
2. . .
3
4const bot = new Telegraf(process.env.BOT_TOKEN)
5
6bot.start((ctx) => {
7 let message = ` Please use the /fact command to receive a new fact`
8 ctx.reply(message)
9})
在这里,您检索并使用了BotFather发送的BOT_TOKEN
,创建了一个新的bot实例,并将其分配给一个名为bot
的变量。创建一个新的bot实例后,您添加了/start
命令的命令倾听器。
你现在已经创建了负责开始与你的聊天机器人交互的命令处理器。现在,让我们创建命令处理器来生成一个事实。
1[label main.js]
2. . .
3
4bot.command('fact', async (ctx) => {
5 try {
6 ctx.reply('Generating image, Please wait !!!')
7 let imagePath = `./temp/${uuidV4()}.jpg`
8 await factGenerator.generateImage(imagePath)
9 await ctx.replyWithPhoto({ source: imagePath })
10 factGenerator.deleteImage(imagePath)
11 } catch (error) {
12 console.log('error', error)
13 ctx.reply('error sending image')
14 }
15})
16
17bot.launch()
在这个代码块中,你为自定义 /fact
slash 命令创建了一个命令倾听器。一旦这个命令从 Telegram 用户界面启动,机器人会向用户发送一个消息。 uuid
模块被用来生成图像名称和路径。图像将存储在您在 Step 1 中创建的 /temp
目录中。之后,图像路径被传递到名为 generateImage()
的方法中,您将在 factGenerator.js
文件中定义,以生成包含有关动物事实的图像。一旦图像被生成,图像将被发送给用户。然后,图像路径被传递到名为 deleteFile
的方法中,在 `factGenerator
main.js
文件将看起来如下:
1[label main.js]
2const { Telegraf } = require('telegraf')
3const { v4: uuidV4 } = require('uuid')
4require('dotenv').config()
5let factGenerator = require('./factGenerator')
6
7const bot = new Telegraf(process.env.BOT_TOKEN)
8
9bot.start((ctx) => {
10 let message = ` Please use the /fact command to receive a new fact`
11 ctx.reply(message)
12})
13
14bot.command('fact', async (ctx) => {
15 try {
16 ctx.reply('Generating image, Please wait !!!')
17 let imagePath = `./temp/${uuidV4()}.jpg`
18 await factGenerator.generateImage(imagePath)
19 await ctx.replyWithPhoto({ source: imagePath })
20 factGenerator.deleteImage(imagePath)
21 } catch (error) {
22 console.log('error', error)
23 ctx.reply('error sending image')
24 }
25});
26
27bot.launch()
你已经创建了负责运行和管理你的机器人的文件,现在你将为动物设置事实,并在factGenerator.js
文件中构建机器人的逻辑。
步骤 4 – 创建事实生成器文件并构建机器人逻辑
在本节中,你将创建名为fact.js
和factGenerator.js
的文件。fact.js
将存储有关动物的事实在一个数据源中。factGenerator.js
文件将包含从文件中获取关于动物的随机事实所需的代码,从Pexels中获取图像,使用jimp
在获取的图像中写出事实,并删除图像。
在项目的 root 目录中,使用您喜爱的文本编辑器创建并打开 facts.js
文件:
1nano facts.js
在facts.js
文件中,添加以下代码来创建您的数据源:
1[label facts.js]
2const facts = [
3 {
4 fact: "Mother pandas keep contact with their cub nearly 100% of the time during their first month - with the cub resting on her front and remaining covered by her paw, arm or head.",
5 animal: "Panda"
6 },
7 {
8 fact: "The elephant's temporal lobe (the area of the brain associated with memory) is larger and denser than that of people - hence the saying 'elephants never forget'.",
9 animal: "Elephant"
10 },
11 {
12 fact: "On average, males weigh 190kg and females weigh 126kg . They need this weight and power behind them to hunt large prey and defend their pride. ",
13 animal: "Lion"
14 },
15 {
16 fact: "The Amazon river is home to four species of river dolphin that are found nowhere else on Earth. ",
17 animal: "Dolphin"
18 },
19]
20
21module.exports = { facts }
在此代码块中,您定义了一个包含动物事实的数组对象,并存储在名为事实
的变量中。每个对象都有以下属性:事实
和动物
。在名为事实
的属性中,其值是关于动物的事实,而动物
的属性存储了动物的名称。
现在,创建一个名为factGenerator.js
的文件:
1nano factGenerator.js
在factGenerator.js
文件中,添加以下代码,以便在您使用的依赖中构建动物图像的逻辑:
1[label factGenerator.js]
2let { createClient } = require('pexels')
3let Jimp = require('jimp')
4const fs = require('fs')
5let { facts } = require('./facts')
在这里,您需要的像素
,jimp
,fs
模块和您的facts.js
文件. 您将使用pexels
模块从Pexels中获取动物图像,jimp
模块来编辑从Pexels获取的图像,以及fs
模块从文件目录中删除图像,然后发送给用户。
在要求
语句下方,添加以下代码来生成图像:
1[label factGenerator.js]
2. . .
3
4async function generateImage(imagePath) {
5 let fact = randomFact()
6 let photo = await getRandomImage(fact.animal)
7 await editImage(photo, imagePath, fact.fact)
8}
在这个代码块中,你创建了一个名为generateImage()
的函数。这个函数作为一个参数,在你的文件目录中使用Pexel图像的路径。一旦这个函数被称为randomFact()
的函数,返回的值被存储在一个名为fact
的变量中。randomFact()
函数随机选择了facts.js
文件中的一个对象。收到对象后,其属性动物
被转移到名为getRandomImage()
的函数中。getRandomImage()
函数将使用pexels
模块来搜索含有被传输的动物名称的图像,并选择随机图像。返回的值被存储在一个名为`
在这里,您创建了当您向机器人发送/fact
切片命令时呼叫的函数,现在您将创建getRandomImage()
和editImage()
函数,并构建选择和编辑随机图像背后的逻辑。
在generateImage()
函数下方,添加以下代码来设置随机化逻辑:
1[label factGenerator.js]
2. . .
3
4function randomFact() {
5 let fact = facts[randomInteger(0, (facts.length - 1))]
6 return fact
7}
8
9function randomInteger(min, max) {
10 return Math.floor(Math.random() * (max - min + 1)) + min;
11}
你现在已经创建了函数 randomFact()
和 randomInteger()
. randomFact()
函数通过调用 randomInteger()
函数在 facts.js
文件中选择一个随机 fact
,然后返回这个对象。
现在您已经定义了返回随机事实和随机整数的函数,您需要创建一个函数来从 Pexels 获取随机图像。
1[label factGenerator.js]
2. . .
3
4async function getRandomImage(animal) {
5 try {
6 const client = createClient(process.env.PEXELS_API_KEY)
7 const query = animal
8 let image
9
10 await client.photos.search({ query, per_page: 10 }).then(res => {
11 let images = res.photos
12 image = images[randomInteger(0, (images.length - 1))]
13
14 })
15
16 return image
17
18 } catch (error) {
19 console.log('error downloading image', error)
20 getRandomImage(animal)
21 }
22}
在这个代码块中,你创建了一个名为getRandomImage()
的函数。这个函数作为一个动物名称的论点。当这个函数被称为客户端
对象时,它是通过使用createClient()
方法对象从pexels
模块和存储在.env
文件中的Pexels API密钥创建的。 动物名被存储在一个名为query
的变量中,然后使用client
对象来搜索包含在query
中的值的图像。 一旦图像被找到,则使用randomInteger()
函数选择随机图像。 最后,随机图像返回你的main.js
文件中的generateImage()
方法。
有了您的getRandomImage()
函数,选择的图像需要有一个文本重叠,然后发送到您的Telegram机器人。
1[label factGenerator.js]
2. . .
3
4async function editImage(image, imagePath, fact) {
5 try {
6 let imgURL = image.src.medium
7 let animalImage = await Jimp.read(imgURL).catch(error => console.log('error ', error))
8 let animalImageWidth = animalImage.bitmap.width
9 let animalImageHeight = animalImage.bitmap.height
10 let imgDarkener = await new Jimp(animalImageWidth, animalImageHeight, '#000000')
11 imgDarkener = await imgDarkener.opacity(0.5)
12 animalImage = await animalImage.composite(imgDarkener, 0, 0);
13
14 } catch (error) {
15 console.log("error editing image", error)
16 }
17
18}
在这里,你创建了一个名为editImage()的函数。这个函数以随机动物标记为图像
、imagePath和关于这种随机动物的事实
为参数。在变量imgURL
中,图像的中等大小的URL从Pexels API中获取。随后,使用了jimp
的read()
方法来加载图像。一旦图像被加载并存储在名为animalImage
的变量中,图像的宽度和高度被检索并存储在变量animalImageWidth
和animalImageHeight
中。变量imgGardenDer
存储了Jimp()
的新实例并使图像变暗。imgimp
的`opacity()
注: 默认情况下,Jimp提供了名为color()
的方法,允许您调整图像的语音水平。 为本教程的目的,您将编写自定义语音调节器,因为color()
方法不提供这里所需的精度。
在editImage()函数内的试用
块的底部,添加以下代码:
1[label factGenerator.js]
2. . .
3
4async function editImage(image, imagePath,fact) {
5 try {
6 . . .
7
8 let posX = animalImageWidth / 15
9 let posY = animalImageHeight / 15
10 let maxWidth = animalImageWidth - (posX * 2)
11 let maxHeight = animalImageHeight - posY
12
13 let font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE)
14 await animalImage.print(font, posX, posY, {
15 text: fact,
16 alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
17 alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
18 }, maxWidth, maxHeight)
19
20 await animalImage.writeAsync(imagePath)
21 console.log("Image generated successfully")
22
23 } catch (error) {
24 . . .
25 }
26}
在这个代码块中,你使用了animalImageWidth
和animalImageHeight
来获取将用于在animalImage
中中心化文本的值。 然后,你使用了loadFont()
方法的jimp
来加载字体,并将字体存储在名为font
的变量中。 字体颜色为白色,类型为 sans-serif(SANS
)和尺寸为16。 最后,你使用了jimp
的print()
方法将事实
插入到animalImage
,并使用write()
方法将animalImage
保存到image Path
。
现在你已经创建了负责编辑图像的函数,你需要一个函数来删除图像从你的文件结构后,它被发送给用户。
1[label factGenerator.js]
2. . .
3
4const deleteImage = (imagePath) => {
5 fs.unlink(imagePath, (err) => {
6 if (err) {
7 return
8 }
9 console.log('file deleted')
10 })
11}
12
13module.exports = { generateImage, deleteImage }
在这里,您创建了一个名为 deleteImage()
的函数. 这个函数将变量 imagePath
作为参数。 一旦这个函数被调用,则使用 fs
模块来删除存储在 imagePath
变量中的图像。
有了您的函数, factGenerator.js
文件将看起来如下:
1[label factGenerator.js]
2let { createClient } = require('pexels')
3let Jimp = require('jimp')
4const fs = require('fs')
5let { facts } = require('./facts')
6
7async function generateImage(imagePath) {
8 let fact = randomFact()
9 let photo = await getRandomImage(fact.animal)
10 await editImage(photo, imagePath, fact.fact)
11}
12
13function randomFact() {
14 let fact = facts[randomInteger(0, (facts.length - 1))]
15 return fact
16}
17
18function randomInteger(min, max) {
19 return Math.floor(Math.random() * (max - min + 1)) + min;
20}
21
22async function getRandomImage(animal) {
23 try {
24 const client = createClient(process.env.PEXELS_API_KEY)
25 const query = animal
26 let image
27
28 await client.photos.search({ query, per_page: 10 }).then(res => {
29 let images = res.photos
30 image = images[randomInteger(0, (images.length - 1))]
31
32 })
33
34 return image
35
36 } catch (error) {
37 console.log('error downloading image', error)
38 getRandomImage(animal)
39 }
40}
41
42async function editImage(image, imagePath, fact) {
43 try {
44 let imgURL = image.src.medium
45 let animalImage = await Jimp.read(imgURL).catch(error => console.log('error ', error))
46 let animalImageWidth = animalImage.bitmap.width
47 let animalImageHeight = animalImage.bitmap.height
48 let imgDarkener = await new Jimp(animalImageWidth, animalImageHeight, '#000000')
49 imgDarkener = await imgDarkener.opacity(0.5)
50 animalImage = await animalImage.composite(imgDarkener, 0, 0);
51
52 let posX = animalImageWidth / 15
53 let posY = animalImageHeight / 15
54 let maxWidth = animalImageWidth - (posX * 2)
55 let maxHeight = animalImageHeight - posY
56
57 let font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE)
58 await animalImage.print(font, posX, posY, {
59 text: fact,
60 alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
61 alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
62 }, maxWidth, maxHeight)
63
64 await animalImage.writeAsync(imagePath)
65 console.log("Image generated successfully")
66
67 } catch (error) {
68 console.log("error editing image", error)
69 }
70
71}
72
73const deleteImage = (imagePath) => {
74 fs.unlink(imagePath, (err) => {
75 if (err) {
76 return
77 }
78 console.log('file deleted')
79 })
80}
81
82module.exports = { generateImage, deleteImage }
保存你的 factGenerator.js
文件. 返回您的终端,并运行以下命令来启动您的机器人:
1npm start
打开您喜爱的Telegram客户端,并搜索您的机器人. 发送一个消息以/start
命令启动对话,或点击 Start 按钮。
您将收到类似于以下的图像:
您现在在您偏好的Telegram客户端中看到图像,并在图像上创建了文件和功能,负责从facts.js
文件中获取随机事实,从Pexels中获取动物图像,并将事实插入图像中。
结论
在本教程中,你创建了一个Telegram聊天机器人,该机器人通过电报
模块为机器人创建了命令处理器,通过电报
模块发送了一个动物的图像,通过像素
模块发送随机图像,并使用jimp
模块插入随机图像上的事实。有关Pexels API、电报
和电报
模块的更多信息,请参阅有关Pexels API(https://www.pexels.com/api/documentation/),[`电报](https://telegraf.js.org/),[`jimp](https://github.com/oliver-moran/jimp/tree/master/packages/jimp)的文档。