著者は、 Write for DOnations プログラムの一環として、 Free and Open SourceFundを選択して寄付を受け取りました。

序章

このチュートリアルでは、 Node.js telegraf jimp 、および Pexels APIを使用して、Telegramを構築します。 ファクトがオーバーレイされたランダムに選択された画像を送信するチャットボット。 Telegramボットは、好みのTelegramクライアントを介してカスタムスラッシュコマンドを使用して対話できるボットです。 Telegramを使用してボットを作成し、JavaScriptを使用してランダムな動物の画像と動物のファクトを選択するロジックを定義します。

このチュートリアルの最後に、次のようなTelegramチャットボットがあります。

ボットを完成させると、カスタムのTelegramスラッシュコマンドを送信するたびに、動物に関する事実を受け取ることができます。

前提条件

このチュートリアルに従うには、読者は次のツールが必要になります。

このチュートリアルは、Nodev12.18.2およびnpmv6.14.8で検証されました。

ステップ1—プロジェクトルートディレクトリを作成する

このセクションでは、チャットボットをビルドするディレクトリを作成し、Nodeプロジェクトを作成して、必要な依存関係をインストールします。

ターミナルウィンドウを開き、という名前の新しいディレクトリを作成します facts-bot:

  1. mkdir facts-bot

ディレクトリに移動します。

  1. cd facts-bot

という名前のディレクトリを作成します temp:

  1. mkdir temp

上記のコマンドを使用して、という名前のディレクトリを作成しました temp. このディレクトリには、ボットがユーザーに送信する画像を一時的に保存します。

次に、新しいNode.jsプロジェクトを作成します。 npmの実行 init コマンドは作成します package.json ファイル。依存関係とメタデータを管理します。

初期化コマンドを実行します。

  1. npm init

デフォルト値を受け入れるには、を押します ENTER すべてのプロンプトに。 または、応答をパーソナライズすることもできます。 これを行うには、チュートリアルnpmおよびpackage.jsonでNode.jsモジュールを使用する方法のステップ1でnpmの初期化設定を確認します。

package.jsonファイルを開き、編集します。

  1. nano package.json

次に、のプロパティを更新します package.json ファイル。 ファイル内の内容を強調表示されたコードに置き換えます。

package.json
{
  "name": "facts-bot",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "nodemon main.js"
  },
  "author": "",
  "license": "ISC"
}

ここで変更しました mainscripts プロパティ。 を変更することにより main プロパティ、アプリケーションのメインファイルをに設定しました main.js. これにより、ノードに通知されます main.js ファイルは、プログラムへの主要なエントリポイントです。 の中に scripts 追加したプロパティ script 名前付き start、これにより、アプリケーションの起動時に実行されるはずのコマンドを設定できます。 あなたが電話したら script コマンド nodemon を実行します main.js 次のステップで作成するファイル。

設定が定義されました package.json ファイル、環境変数を保存するファイルを作成します。 ターミナルで、という名前のファイルを作成します .env:

touch .env

あなたの中で .env ファイルには、TelegramボットトークンとPexelsAPIキーを保存します。 Telegram Botトークンを使用すると、Telegramボットと対話できます。 Pexels APIキーを使用すると、PexelsAPIを操作できます。 後のステップで環境変数を保存します。

今回は使用します npm 依存関係をインストールするには telegraf, dotenv, pexels, jimp、 と uuid. また、 --save 依存関係を保存するためのフラグ。 ターミナルで、次のコマンドを実行します。

  1. npm install telegraf dotenv pexels jimp uuid --save

このコマンドでは、以下をインストールしました。

  • telegraf :JavaScriptまたはTypeScriptを使用して独自のTelegramボットを開発するのに役立つライブラリ。 これを使用してボットを構築します。
  • dotenv :環境変数をからロードするゼロ依存モジュール .env ファイルに process.env. このモジュールを使用して、ボットトークンとPexelsAPIキーを .env 作成したファイル。
  • pexels :Node.jsのサーバーとブラウザーの両方で使用できるPexelsAPIの便利なラッパー。 このモジュールを使用して、Pexelsから動物の画像を取得します。
  • jimp :Node用に完全にJavaScriptで記述された画像処理ライブラリで、外部またはネイティブの依存関係はありません。 このライブラリを使用して、Pexelsから取得した画像を編集し、動物に関する事実を挿入します。
  • uuid :JavaScriptでRFC準拠のUUIDを生成できるようにするモジュール。 このモジュールを使用して、Pexelsから取得した画像の一意の名前を作成します。

次に、nodemonを開発依存関係としてインストールします。

npm install nodemon --save-dev

nodemon は、ディレクトリ内のファイルの変更を検出したときにNodeアプリケーションを自動的に再起動することにより、Node.jsベースのアプリケーションを開発するツールです。 このモジュールを使用して、ボットをテストしながらアプリを起動して実行し続けます。

注:これを書いている時点では、使用されているモジュールのバージョンは次のとおりです。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に登録し、PexelsAPIのAPIキーを取得します。

ステップ2—ボットを登録してPexelsAPIからAPIキーを取得する

このセクションでは、最初にボットを BotFather に登録し、次にPexelsAPIのAPIキーを取得します。 BotFatherは、Telegramによって管理されるチャットボットであり、ユーザーがチャットボットを作成および管理できるようにします。

お好みのテレグラムクライアントを開き、検索します @BotFather、チャットを開始します。 を送信します /newbot コマンドをスラッシュし、BotFatherから送信された指示に従います。

ボット名とユーザー名を選択すると、ボットアクセストークンを含むメッセージが表示されます。

ボットトークンをコピーして、 .env ファイル:

  1. nano .env

ボットトークンをという名前の変数に保存します BOT_TOKEN:

.env
BOT_TOKEN = "Your bot token"

これで、ボットトークンが .env ファイル、PexelsAPIキーを取得する時が来ました。

Pexels に移動し、Pexelsアカウントにログインします。 クリックしてください画像と動画のAPI タブをクリックして、新しいAPIキーを作成します。

APIキーをコピーして、 .env ファイル:

  1. nano .env

APIキーをという名前の変数に保存します PEXELS_API_KEY. 君の .env 次のようになります。

.env
BOT_TOKEN = "Your_bot_token"
PEXELS_API_KEY = "Your_Pexels_API_key"

このセクションでは、ボットを登録し、Pexels APIキーを取得し、ボットトークンとPexelsAPIキーをに保存しました。 .env ファイル。 次のセクションでは、ボットの実行を担当するファイルを作成します。

ステップ3—作成 main.js ファイル

このセクションでは、ボットを作成して構築します。 ラベルの付いたファイルを作成します main.js、これにはボットのロジックが含まれます。

プロジェクトのルートディレクトリで、を作成して開きます main.js お好みのテキストエディタを使用したファイル:

  1. nano main.js

以内 main.js ファイルに次のコードを追加して、使用するライブラリをインポートします。

main.js
const { Telegraf } = require('telegraf')
const { v4: uuidV4 } = require('uuid')
require('dotenv').config()
let factGenerator = require('./factGenerator')

このコードブロックでは、 telegrafuuiddotenv モジュール、およびという名前のファイル factGenerator.js. あなたは使用しようとしています telegraf ボットを起動および管理するためのモジュール、 uuid画像の一意のファイル名を生成するモジュール、および dotenv TelegramボットトークンとPexelsAPIキーを取得するモジュール .env ファイル。 The factGenerator.js ファイルは、Pexelsからランダムな動物の画像を取得し、動物に関する事実を挿入し、ユーザーに送信された後に画像を削除するために使用されます。 このファイルは次のセクションで作成します。

require ステートメントに次のコードを追加して、ボットのインスタンスを作成します。

main.js
. . .

const bot = new Telegraf(process.env.BOT_TOKEN)

bot.start((ctx) => {
    let message = ` Please use the /fact command to receive a new fact`
    ctx.reply(message)
})

ここでは、を取得して使用しました BOT_TOKEN そのBotFatherが送信し、新しいボットインスタンスを作成し、それをという変数に割り当てました。 bot. 新しいボットインスタンスを作成した後、次のコマンドリスナーを追加しました /start 指図。 このコマンドは、ユーザーとボットの間の会話を開始する役割を果たします。 ユーザーが以下を含むメッセージを送信すると /start ボットは、ユーザーに使用するように求めるメッセージで応答します。 /fact 新しい事実を受け取るコマンド。

これで、チャットボットとの対話を開始するコマンドハンドラーが作成されました。 それでは、ファクトを生成するためのコマンドハンドラーを作成しましょう。 下 .start() コマンド、次のコードを追加します。

main.js
. . .

bot.command('fact', async (ctx) => {
    try {
        ctx.reply('Generating image, Please wait !!!')
        let imagePath = `./temp/${uuidV4()}.jpg`
        await factGenerator.generateImage(imagePath)
        await ctx.replyWithPhoto({ source: imagePath })
        factGenerator.deleteImage(imagePath)
    } catch (error) {
        console.log('error', error)
        ctx.reply('error sending image')
    }
})

bot.launch()

このコードブロックでは、カスタムのコマンドリスナーを作成しました /fact スラッシュコマンド。 このコマンドがTelegramユーザーインターフェイスからトリガーされると、ボットはユーザーにメッセージを送信します。 The uuid モジュールは、画像の名前とパスを生成するために使用されます。 画像はに保存されます /temp ステップ1で作成したディレクトリ。 その後、画像パスはという名前のメソッドに渡されます generateImage() で定義します factGenerator.js 動物に関する事実を含む画像を生成するファイル。 画像が生成されると、画像がユーザーに送信されます。 次に、画像パスがという名前のメソッドに渡されます deleteFile の中に factGenerator.js 画像を削除するファイル。 最後に、 bot.launch() 方法。

The main.js ファイルは次のようになります。

main.js
const { Telegraf } = require('telegraf')
const { v4: uuidV4 } = require('uuid')
require('dotenv').config()
let factGenerator = require('./factGenerator')


const bot = new Telegraf(process.env.BOT_TOKEN)

bot.start((ctx) => {
    let message = ` Please use the /fact command to receive a new fact`
    ctx.reply(message)
})


bot.command('fact', async (ctx) => {
    try {
        ctx.reply('Generating image, Please wait !!!')
        let imagePath = `./temp/${uuidV4()}.jpg`
        await factGenerator.generateImage(imagePath)
        await ctx.replyWithPhoto({ source: imagePath })
        factGenerator.deleteImage(imagePath)
    } catch (error) {
        console.log('error', error)
        ctx.reply('error sending image')
    }
});


bot.launch()

ボットの実行と管理を担当するファイルを作成しました。 ここで、動物の事実を設定し、ボットのロジックを構築します。 factGenerator.js ファイル。

ステップ4—ファクトジェネレータファイルの作成とボットロジックの構築

このセクションでは、という名前のファイルを作成します fact.jsfactGenerator.js. fact.js 動物に関する事実を1つのデータソースに保存します。 The factGenerator.js ファイルには、ファイルから動物に関するランダムな事実を取得し、Pexelsから画像を取得し、使用するために必要なコードが含まれます。 jimp 取得した画像にファクトを書き込み、画像を削除します。

プロジェクトのルートディレクトリで、を作成して開きます facts.js お好みのテキストエディタを使用したファイル:

  1. nano facts.js

以内 facts.js ファイルに次のコードを追加して、データソースを作成します。

facts.js
const facts = [
    {
        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.",
        animal: "Panda"
    },
    {
        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'.",
        animal: "Elephant"
    },
    {
        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.  ",
        animal: "Lion"
    },
    {
        fact: "The Amazon river is home to four species of river dolphin that are found nowhere else on Earth. ",
        animal: "Dolphin"
    },
]

module.exports = { facts }

このコードブロックでは、動物に関する事実を含む配列を使用してオブジェクトを定義し、という名前の変数に格納しました。 facts. 各オブジェクトには次のプロパティがあります。 factanimal. 名前の付いたプロパティで fact、その価値は動物についての事実ですが、プロパティ animal 動物の名前を保存します。 最後に、エクスポートします facts 配列。

次に、という名前のファイルを作成します factGenerator.js:

  1. nano factGenerator.js

内部 factGenerator.js ファイルに、動物の画像を作成するためのロジックを構築するために使用する依存関係に必要な次のコードを追加します。

factGenerator.js
let { createClient } = require('pexels')
let Jimp = require('jimp')
const fs = require('fs')
let { facts } = require('./facts')

ここでは、 pexelsjimpfs モジュール、およびあなたの facts.js ファイル。 を使用します pexels Pexelsから動物の画像を取得するモジュール jimp Pexelsから取得した画像を編集するモジュール、および fs ユーザーに送信された後、ファイルディレクトリから画像を削除するモジュール。

require ステートメントに、次のコードを追加して画像を生成します。

factGenerator.js
. . .

async function generateImage(imagePath) {
  let fact = randomFact()
  let photo = await getRandomImage(fact.animal)
  await editImage(photo, imagePath, fact.fact)
}

このコードブロックでは、という名前の関数を作成しました generateImage(). この関数は、ファイルディレクトリ内のPexelイメージのパスを引数として取ります。 この関数が呼び出されると、 randomFact() が呼び出され、返された値がという名前の変数に格納されます fact. The randomFact() 関数はランダムにオブジェクトを選択します facts.js ファイル。 オブジェクトを受け取った後、そのプロパティ animal 名前の付いた関数に渡されます getRandomImage(). The getRandomImage() 関数はを使用します pexels 渡された動物の名前を含む画像を検索し、ランダムな画像を選択するモジュール。 返される値は、という名前の変数に格納されます photo. 最後に、 photo, imagePath、 そしてその fact からのプロパティ facts.js ファイルはという名前の関数に渡されます editImage(). The editImage() 関数はを使用します jimp ランダムな事実をランダムな画像に挿入し、編集した画像を imagePath.

ここでは、送信時に呼び出される関数を作成しました /fact ボットへのスラッシュコマンド。 次に、関数を作成します getRandomImage()editImage() ランダムな画像の選択と編集の背後にあるロジックを構築します。

generateImage() 関数、ランダム化ロジックを設定するために次のコードを追加します。

factGenerator.js
. . .

function randomFact() {
  let fact = facts[randomInteger(0, (facts.length - 1))]
  return fact
}


function randomInteger(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

これで関数が作成されました randomFact()randomInteger(). The randomFact() 関数はランダムを選択します fact の中に facts.js を呼び出すことによってファイル randomInteger() 関数であり、このオブジェクトを返します。 The randomInteger() 関数は、0の間隔のランダムな整数とファクトの数を返します。 facts.js ファイル。

ランダムなファクトとランダムな整数を返す関数を定義したので、Pexelsからランダムな画像を取得する関数を作成する必要があります。 下 randomInteger() 関数、ランダムな画像を取得するには、次のコードを追加します。

factGenerator.js
. . .

async function getRandomImage(animal) {
  try {
    const client = createClient(process.env.PEXELS_API_KEY)
    const query = animal
    let image

    await client.photos.search({ query, per_page: 10 }).then(res => {
      let images = res.photos
      image = images[randomInteger(0, (images.length - 1))]

    })

    return image

  } catch (error) {
    console.log('error downloading image', error)
    getRandomImage(animal)
  }
}

このコードブロックでは、という名前の関数を作成しました getRandomImage(). この関数は、引数として動物の名前を取ります。 この関数が呼び出されたとき client オブジェクトはを使用して作成されます createClient() からのメソッドオブジェクト pexels モジュールと、に保存されているPexelsAPIキー .env ファイル。 動物の名前は、という変数に格納されます query、 そうして client オブジェクトは、の値を含む画像を検索するために使用されます query. 画像が見つかると、ランダムな画像が選択されます randomInteger() 関数。 最後に、ランダムな画像がに返されます generateImage() あなたの方法 main.js ファイル。

あなたと getRandomImage() 機能が適切に機能するため、選択した画像は、Telegramボットに送信する前にテキストオーバーレイを使用する必要があります。 下 getRandomImage() 関数、オーバーレイを設定するために次のコードを追加します。

factGenerator.js
. . .

async function editImage(image, imagePath, fact) {
  try {
    let imgURL = image.src.medium
    let animalImage = await Jimp.read(imgURL).catch(error => console.log('error ', error))
    let animalImageWidth = animalImage.bitmap.width
    let animalImageHeight = animalImage.bitmap.height
    let imgDarkener = await new Jimp(animalImageWidth, animalImageHeight, '#000000')
    imgDarkener = await imgDarkener.opacity(0.5)
    animalImage = await animalImage.composite(imgDarkener, 0, 0);


  } catch (error) {
    console.log("error editing image", error)
  } 

}

ここでは、という名前の関数を作成しました editImage(). この関数は、引数としてラベル付けされたランダムな動物を取ります image、imagePath、および fact このランダムな動物について。 変数内 imgURL、中サイズの画像のURLはPexelsAPIから取得されます。 その後、 read() の方法 jimp 画像の読み込みに使用されます。 画像がロードされ、名前の付いた変数に格納されたら animalImage、画像の幅と高さが取得され、変数に格納されます animalImageWidthanimalImageHeight それぞれ。 変数 imgDarkener の新しいインスタンスを格納します Jimp() 画像を暗くします。 The opacity() の方法 jimp 設定に使用されます imgDarkenerの不透明度を50%にします。 最後に、 composite() の方法 jimp 内容を入れるために使用されます imgDarkener の画像の上に animalImage. これは見返りに画像を作成します animalImage に保存されているテキストを追加する前に暗くします fact 変数を入力し、画像上にテキストを表示します。

注: Jimpはデフォルトで、という名前のメソッドを提供します color() これにより、画像の色調レベルを調整できます。 このチュートリアルでは、カスタムトーンアジャスターを次のように記述します。 color() メソッドは、ここで必要な精度を提供しません。

の下部に try 内部のブロック editImage() 関数、次のコードを追加します。

factGenerator.js
. . .

async function editImage(image, imagePath,fact) {
  try {
    . . .

    let posX = animalImageWidth / 15
    let posY = animalImageHeight / 15
    let maxWidth = animalImageWidth - (posX * 2)
    let maxHeight = animalImageHeight - posY

    let font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE)
    await animalImage.print(font, posX, posY, {
      text: fact,
      alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
      alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
    }, maxWidth, maxHeight)

    await animalImage.writeAsync(imagePath)
    console.log("Image generated successfully")
    

  } catch (error) {
    . . .
  }
}

このコードブロックでは、 animalImageWidth、 と animalImageHeight テキストを中央揃えにするために使用される値を取得するには animalImage. その後、あなたは loadFont() の方法 jimp フォントをロードし、フォントをという名前の変数に格納します font. フォントの色は白、タイプはsans-serif(SANS)、サイズは16です。 最後に、 print() の方法 jimp 挿入するには fact の中に animalImage、 そしてその write() 保存する方法 animalImage の中に imagePath.

画像の編集を担当する関数を作成したので、ユーザーに画像を送信した後、ファイル構造から画像を削除する関数が必要になります。 あなたの下に editImage() 関数、次のコードを追加します。

factGenerator.js
. . .

const deleteImage = (imagePath) => {
    fs.unlink(imagePath, (err) => {
        if (err) {
            return
        }
        console.log('file deleted')
    })
}


module.exports = { generateImage, deleteImage }

ここでは、という名前の関数を作成しました deleteImage(). この関数は引数として変数を取ります imagePath. この関数が呼び出されると、 fs モジュールは、変数に格納されている画像を削除するために使用されます imagePath. 最後に、 generateImage() 機能と deleteImage() 関数。

機能が整ったら、 factGenerator.js ファイルは次のようになります。

factGenerator.js
let { createClient } = require('pexels')
let Jimp = require('jimp')
const fs = require('fs')
let { facts } = require('./facts')

async function generateImage(imagePath) {
  let fact = randomFact()
  let photo = await getRandomImage(fact.animal)
  await editImage(photo, imagePath, fact.fact)
}


function randomFact() {
  let fact = facts[randomInteger(0, (facts.length - 1))]
  return fact
}


function randomInteger(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}


async function getRandomImage(animal) {
  try {
    const client = createClient(process.env.PEXELS_API_KEY)
    const query = animal
    let image

    await client.photos.search({ query, per_page: 10 }).then(res => {
      let images = res.photos
      image = images[randomInteger(0, (images.length - 1))]

    })

    return image

  } catch (error) {
    console.log('error downloading image', error)
    getRandomImage(animal)
  }
}


async function editImage(image, imagePath, fact) {
  try {
    let imgURL = image.src.medium
    let animalImage = await Jimp.read(imgURL).catch(error => console.log('error ', error))
    let animalImageWidth = animalImage.bitmap.width
    let animalImageHeight = animalImage.bitmap.height
    let imgDarkener = await new Jimp(animalImageWidth, animalImageHeight, '#000000')
    imgDarkener = await imgDarkener.opacity(0.5)
    animalImage = await animalImage.composite(imgDarkener, 0, 0);

    let posX = animalImageWidth / 15
    let posY = animalImageHeight / 15
    let maxWidth = animalImageWidth - (posX * 2)
    let maxHeight = animalImageHeight - posY

    let font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE)
    await animalImage.print(font, posX, posY, {
      text: fact,
      alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
      alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
    }, maxWidth, maxHeight)

    await animalImage.writeAsync(imagePath)
    console.log("Image generated successfully")

  } catch (error) {
    console.log("error editing image", error)
  }

}


const deleteImage = (imagePath) => {
  fs.unlink(imagePath, (err) => {
    if (err) {
      return
    }
    console.log('file deleted')
  })
}


module.exports = { generateImage, deleteImage }

あなたの factGenerator.js ファイル。 ターミナルに戻り、次のコマンドを実行してボットを起動します。

  1. npm start

好みのTelegramクライアントを開き、ボットを検索します。 でメッセージを送信します /start コマンドで会話を開始するか、開始ボタンをクリックします。 次に、メッセージを送信します /fact 画像を受信するコマンド。

次のような画像が表示されます。

これで、画像にファクトが課された、好みのTelegramクライアントに画像が表示されます。 からランダムなファクトを取得するためのファイルと関数を作成しました facts.js ファイル、Pexelsから動物の画像を取得し、画像にファクトを挿入します。

結論

このチュートリアルでは、カスタムのスラッシュコマンドを使用してファクトをオーバーレイした動物の画像を送信するTelegramチャットボットを作成しました。 ボットのコマンドハンドラーは、 telegraf モジュール。 また、Pexelsからランダムなファクト、ランダムな画像を取得する関数を作成しました。 pexels モジュール、およびを使用してランダム画像にファクトを挿入します jimp モジュール。 Pexels APIの詳細については、 telegrafjimp モジュールは、 Pexels API telegraf jimpのドキュメントを参照してください。