先生の名言を画像にして排出するだけの、誰得かわからないLINE BOT を作った話

TOC

  1. 作ったもの「某先生と会話bot」
  2. 仕組み
    1. ①② メッセージ送信
    2. ③ メッセージ応答
    3. ④ 画像 URL 送信
    4. ⑤ 画像 URL 参照
    5. ⑥ 画像合成・⑦⑧ 画像送信
  3. まとめ

こんにちは。shundroid です。お久しぶりです。
期末考査も終わって、一段落したところです。

何かひと書きしてみたいところだったので、
クラスメートみんなで使える、何かを作ってみたいと思いました。

そこで LINE BOT の開発をしてみることにしました。

作ったもの「某先生と会話bot」

「(名前)、○○」と話すと、某先生の写真と文字を合成した画像を返すbotです。
特徴はただ一定の画像を返すのでなく、「○○」の内容によって文字が合成されるので、
新たに名言が生まれても画像と合成できるようにしていることです。

仕組み

次のようになっています。

①② メッセージ送信

LINEユーザーがメッセージを送信します。

これを bot 側は、Messaging API のメッセージイベントとして受け取ることができます。

そして、bot 側で登録した Webhook URL に POST リクエストが飛ぶので、
それを使って Heroku でデプロイしている node.js アプリケーションにメッセージを送信します。

ここですね。

node.js のほうとしては、LINE の Node.js SDK を使うと簡単に書くことができます。
内容も example の中身を少し変えただけなので、そっちを参考にしてもらったほうがよいでしょう。

Express を使っています。

ちなみに、ここはどうでもいいかもしれないんですけど、
最初は now というのを使おうとしていました。
しかし、これだと後ほど出てくる node-canvas をなぜかコンパイルしに行き、失敗するということをするので、

localtunnel というトンネリングツールで自分のPCに直接アクセスするようにしました。
しかしこれだと自分の PC がついていないとだめなので、Heroku を使うようになった次第です。

初めて Heroku 使いましたけど、かなり便利ですね。すごい。

③ メッセージ応答

画像形式でメッセージを送ります。
Messaging API のリファレンス を参考にして、

1
2
3
4
5
{
"type": "image",
"originalContentUrl": "https://example.com/original.jpg",
"previewImageUrl": "https://example.com/preview.jpg"
}

こういう形式で作ります。

ここで気を付けなければならないのは、画像の形式とサイズですね。
どちらもJPEGでなければなりません。なんと。
サイズは originalContentUrl のほうが1024x1024まで、
previewImageUrl のほうが240x240までです。

ここでの URL は今回は(original…、preview…どちらも)次のようにしました。

1
https://xxxxx.herokuapp.com/image/<名言>

後で URL を参照したとき、名言の文字が入っていないといけないからです。

④ 画像 URL 送信

さっき作ったメッセージを送りますね。
これも example と同じなのでそっちを見てください。

⑤ 画像 URL 参照

bot 側が URL を参照してきます。ここで初めて画像の合成をするようにしています。

先ほど名言は URL に含まれていたので、

1
2
3
app.get('/image/:text', (req, res) => {
// ...
})

というようにパラメーターで指定しておきます。
:text には req.params.text としてアクセスできます。

⑥ 画像合成・⑦⑧ 画像送信

HTML5 Canvas みたいな感じで合成出来たら手軽だと思ったので、
node-canvas というものを使いました。

使い勝手はほんとに HTML5 Canvas そっくりです。すごい。

はまりかけたところはまずフォントですね。

1
2
3
4
5
6
const { registerFont, createCanvas } = require('canvas')
const ctx = createCanvas(100, 100).getContext('2d')
// ...
registerFont('<フォントファイル>.ttf', { family: '<フォント名>' })
ctx.font = '17px <フォント名>'
// ...

このような感じで使えます。

あと、JPEG 画像として返すところですね。

1
2
3
4
5
6
const { createCanvas } = require('canvas')
const canvas = createCanvas(100, 100)
// ...
app.get('xxx', (req, res) => {
canvas.createJPEGStream({ quality: 100 }).pipe(res)
})

こんな感じですね。createJPEGStream で Stream を作ったのを
pipe して res に渡すだけでおkでした。

Express こんな方法にも対応しているのですね。さすがー

まとめ

本当に誰得かわかりませんが面白いものができました。

でもこういうものを通じて、今回は express、LINE bot の作り方、
Heroku、now、localtunnel、node-canvas など、様々なものについて学べました。

そして bot 作り自体はそこまで難しくなさそうですね。
これなら、身近な LINE ですし、プログラミングの入門としてもいいかもしれません。

今度部活のみんなでbot作ろう会をやってみよっかな。