如何使用 Node.js、Telegraf、Jimp 和 Pexels 构建 Telegram 语录生成器机器人

作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。

介绍

在本教程中,您将使用 Node.js, telegraf, jimp,以及 Pexels API 来构建 Telegram)聊天机器人,它将向您发送随机选择的图像,其中包含一个事实。 电报机器人是一个机器人,您可以通过您喜爱的电报客户端使用自定义削减命令进行交互。 您将通过电报创建机器人,并定义其逻辑,以选择随机的动物图像和使用JavaScript的动物事实。

在本教程结束时,您将有一个Telegram聊天机器人,看起来如下:

Imgur

一旦你完成了你的机器人,你会收到一个关于动物的事实,每次你发送一个自定义的Telegram削减命令。

前提条件

为了遵循本教程,读者将需要以下工具:

本教程已通过 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,jimpuuid。你还将使用--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,然后开始聊天。

Imgur

选择您的机器人名称和用户名后,您将收到包含您的机器人访问代码的消息:

Imgur

复制机器人代码,并打开您的 .env 文件:

1nano .env

在一个名为BOT_TOKEN的变量中保存 Bot 代币:

1[label .env]
2BOT_TOKEN = "Your bot token"

现在你已经将你的机器人代币保存到.env 文件中,是时候获取 Pexels API 密钥了。

点击 Pexels,然后登录您的 Pexels 帐户。 点击 Image & Video API 选项卡,创建一个新的 API 密钥:

Imgur

复制 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.jsfactGenerator.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中获取。随后,使用了jimpread()方法来加载图像。一旦图像被加载并存储在名为animalImage的变量中,图像的宽度和高度被检索并存储在变量animalImageWidthanimalImageHeight中。变量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}

在这个代码块中,你使用了animalImageWidthanimalImageHeight来获取将用于在animalImage中中心化文本的值。 然后,你使用了loadFont()方法的jimp来加载字体,并将字体存储在名为font的变量中。 字体颜色为白色,类型为 sans-serif(SANS)和尺寸为16。 最后,你使用了jimpprint()方法将事实插入到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 按钮。

您将收到类似于以下的图像:

Imgur

您现在在您偏好的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)的文档。

Published At
Categories with 技术
comments powered by Disqus