Flaskで簡易ダジャレLINE botを作った話

# はじめに
こんにちは、本日2022/04/10でございます。
つい昨日、急にbot作ってみたいなと思い、すぐに始められそうなFlaskの勉強を始めました。

環境構築に苦戦しましたが、何とか勉強を始めてから1日かけずにLINEbotを作ることができました。基礎的な部分はこれから参考書を買ってマスターしていきたいと思います。


オウム返しのコードを参考にし、適宜変更し、**単語を送ると、それに応じてダジャレを返すbot**を作成しました。その際、[こちらのブログ](https://programming-holic.com/2021/12/23/python-flask-linebot/) を参考にしました。
非常に参考になりました。

# FlaskでLINEbotを作る手順
やることは大きく分けて3つあります。

- LINE developerに登録
- コードを書く
- herokuに置く

## LINE developerの登録

ブラウザで「LINE developer」と検索し、それらしきサイトに飛ぶと以下のような画面が出ると思います。
![スクリーンショット (426).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2573459/26c8b940-0c71-01ab-8666-d8103d8bd981.png)

この画面が出てきたら、右上の**ログイン**を押し、ログインします(プライベートのLINEアカウントを使いました。)


ログインを済ますと以下のような画面が出ると思います。右下らへんで表記を日本語にすることもできます。


![スクリーンショット (427).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2573459/23bf4254-822d-3a65-e4bc-74a2acdddf4f.png)

ここで、何も作成したことがなければ、何も表示されないので、プロバイターの**作成**を押します。すると、以下のような画面が出るので、**Messaging API**を選択します。

その後、いろいろと入力するとbotの設定が完了します。
しかし、何もしていないので、この時点でbotが自分の思い通りに動くことはありません。


## コードの準備
はじめに、必要なファイルについて説明します。
必要なファイルは全部で5つありまして、

- joke_app.py
- Procfile
- runtime.txt
- requirements.txt
- .gitignore

です。1つずつ解説していきます。

### joke_app.py

これがメインのファイルです。
とりあえず全部載せます。見られてはいけないところもあるので、そこは隠します。また細かく見ていくときに言います。

```python:joke_app.py
from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)
import os

#token取得---------------------------------------------------
line_bot_api = LineBotApi('チャネルアクセストークン')
handler = WebhookHandler('チャネルシークレット')
#---------------------------------------------------------------


#確認------------------------------
app = Flask(__name__)
app.debug = False

@app.route("/")
def say_hello():
    return "Hello!!!!!"
#----------------------------------


#LINEbotを呼び出す---------------------------------
@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)

    return 'OK'
#----------------------------------------------------------


#ダジャレ開始--------------------------------------------------------
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):

    df_list=[['ふとん', 'ふとんがふっとんだ'],
            ['みかん', 'アルミ缶のうえにあるみかん'],
            ['ねこ', 'ねこが寝ころんだ'],
            ['いす', 'いすに居座る'],
            ['委員会', '委員会に入っていいんかい'],
            ['いくら', 'このいくら、いくらですか？'],
            ['飲酒', '飲酒していいんしゅか？'],
            ['お金', 'お金はおっかねえ'],
            ['カンニング', 'カンニングはいかんにんぐ']]

    for i in range(len(df_list)):
        joke=None
        if event.message.text==df_list[i][0]:
            joke=df_list[i][1]
            line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text=joke))
        else:continue

    if joke==None:
        line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text='すまん、思いつかんかった!!'))

#------------------------------------------------------------------------
if __name__ == "__main__":
    port = int(os.getenv("PORT"))
    app.run(host="0.0.0.0", port=port)

```

自分自身理解していないブロックが何個かありますので、わかる部分だけ説明します。

まず、最初はライブラリの取得です。
もし、インポートできなかったら、コマンドで
```cmd
pip install flask
pip install line-bot-sdk
pip install gunicorn
```
として、インストールしましょう。
今更ですが、Flaskはvenvで環境構築しました。

tokenの取得から見ていきます。

```python
#token取得---------------------------------------------------
line_bot_api = LineBotApi('チャネルアクセストークン')
handler = WebhookHandler('チャネルシークレット')
#---------------------------------------------------------------
```
ここでは、先ほど作成したLINEbotのアクセス権とパスワードみたいなものを取ってきているんだと思います。
トークンとシークレットは、それぞれ**Messaging API設定**と、**チャネル基本設定**の下の方にあります。スクロールすれば見つかると思います。



**#確認**の部分は、正常にアプリが作られたか確認するためのところなので飛ばします。
（正常に作られれば、作成時にWebサイトが開かれ、''Hello!!!''と表示されます。)

次に、LINEbotを呼び出す部分を見ます。
```python
#LINEbotを呼び出す---------------------------------
@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)

    return 'OK'
#----------------------------------------------------------
```
詳細は知りませんが、LINEbotを呼び出しています。
オウム返しbotでもなんでもここは共通で大丈夫です。


次に本丸の**ダジャレ**を見ていきましょう。
```python

#ダジャレ開始--------------------------------------------------------
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):

    df_list=[['ふとん', 'ふとんがふっとんだ'],
            ['みかん', 'アルミ缶のうえにあるみかん'],
            ['ねこ', 'ねこが寝ころんだ'],
            ['いす', 'いすに居座る'],
            ['委員会', '委員会に入っていいんかい'],
            ['いくら', 'このいくら、いくらですか？'],
            ['飲酒', '飲酒していいんしゅか？'],
            ['お金', 'お金はおっかねえ'],
            ['カンニング', 'カンニングはいかんにんぐ']]

    for i in range(len(df_list)):
        joke=None
        if event.message.text==df_list[i][0]:
            joke=df_list[i][1]
            line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text=joke))
        else:continue

    if joke==None:
        line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text='すまん、思いつかんかった!!'))

#------------------------------------------------------------------------
if __name__ == "__main__":
    port = int(os.getenv("PORT"))
    app.run(host="0.0.0.0", port=port)
```

ここでは、どんなメッセージが来たら、どんなメッセージを返すかといった関数を作っています。
まず、言葉とダジャレのリストを作っています。これをfor文で回すことで、リストにある単語と一致したときにそれに応じたダジャレを返すようにしています。
forとifだけなので特別なことは無いかと思います。

最後の関数の外のif文では、appを実行するときの詳細を書いているのだと思います。

### Procfile
これはそういうファイルなので拡張子はいりません。
```:Procfile
web: gunicorn joke_app:app --log-file -
```
joke_appのところにさっきのpyファイルの名前を入れればokです。

### runtime.txt
こちらは、Pythonのバージョンを記述します。自分はPython3.9.5でした。
```txt:runtime.txt
python-3.9.5
```
ここで要注意なのですが、pythonの''p''は**小文字**です。
大文字にしていたらエラーが出てすごく時間を無駄にしました。
皆さんにはそのような時間を過ごしてほしくはありません。注意しましょう。

### requirements.txt
こちらには、使用するライブラリとそのバージョンを記述します。コマンドで
```:コマンドプロンプト
pip freeze > requirements.txt
```
とすれば一気に書けます。
もし、ここに記述した内容でエラーが出たら、使っていないライブラリの記述は消したり、バージョンを変えてみたりしましょう。

### .gitignore
役割と意味を理解できていませんが、とりあえず必要らしい(?)もしかしたら必要ないかも。
でもこれがあったも実行できたのであって損はないのでは？？と考えています。
```:.gitignore
__pycache__
```

長かったですが、すべてのファイルの準備ができました。

次に、herokuについて説明します。


## herokuへの登録と実行
herokuとは、アプリを動かすために必要なファイルを代わりに保管し、そこで実行してくれるクラウドサービスといったところでしょうか。
Gitと連携することでそれが可能になっているので、少しだけGitのコマンドも使います。

まずは「heroku」と検索し、ユーザー登録をします。
また、インストールもしましょう。

インストールが完了したら、コマンドに
```cmd:コマンド
heroku login
```
と入れます。上手くいけば、herokuのログイン画面が立ち上がるので、ログインしましょう。ログインしたらコマンドに戻ります。

次にコマンドでGitを初期化、ステージング、コミット、プッシュをします。
```git:コマンド
git init
git add .
git commit -m "commit message"
heroku create 'botの名前'
git push heroku master
```
ちなみに、Gitのインストール時に、Gitコマンドをコマンドプロンプトで使えるように設定していないとできないです。

ここまできたら、ほぼ完成です。最後にコマンドにて
```cmd:コマンド
heroku ps:scale web=1
heroku open
```
として、Web上に　**Heloo!!!**　と表示されれば成功です。

この後ですが、LINE developerの設定に戻り、**Messaging API設定**から、**Webhook設定**を編集しましょう。URLには[https://さっきのappの名前.herokuapp.com/callback]と入力します。

また、その近くにある**応答メッセージ**を編集しようとすると別のページに飛びます。

そこで、WebhookをONにしましょう。これで完成です。

あとはプログラム関係ないので、ノリで自分好みに編集しました。

## おわりに

まずはこんな長い記事を読んでいただきありがとうございました。
エラーが起きたりして、何度かやめようとしましたが完成すると嬉しいですね。

ダジャレのリストを作成するところはデータベースを勉強してから改良していきたいと思います。

また、質問や指摘、新しいダジャレなどあればコメントお願いします。

なんでこの記事を書いたかというと、

**LINEbotについてのQiitaを書きーたかった。**

はい、ありがとうございました。