LINE BOT（オウム返し）を作る

#LINEBOTで単純なオウム返しを、Heroku、Flask、line-bot-sdkで作成した。丸２日かかり詰まった点も多いのでメモも含めて共有。

・Mac
・Python

#（１）環境整備、ディレクトリ構成
デスクトップに、ディレクトリtest_linebotを作成。
ディレクトリ内に仮想環境を構築して起動。

```
python3 -m venv .
source bin/activate
```

最終的なディレクトリ構成は以下の通り

```
test_linebot
├main.py
├runtime.txt
├Procfile
└requirements.txt
```

#（２）必要なフレームワークをインストール

```
pip install flask
pip install gunicorn
pip install line-bot-sdk
```

#（３）main.pyを作成

```.py:main.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

app = Flask(__name__)

#herokuの環境変数に設定された、LINE DevelopersのアクセストークンとChannelSecretを
#取得するコード
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)

#herokuへのデプロイが成功したかどうかを確認するためのコード
@app.route("/")
def hello_world():
    return "hello world!"


#LINE DevelopersのWebhookにURLを指定してWebhookからURLにイベントが送られるようにする
@app.route("/callback", methods=['POST'])
def callback():
    # リクエストヘッダーから署名検証のための値を取得
    signature = request.headers['X-Line-Signature']

    # リクエストボディを取得
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # 署名を検証し、問題なければhandleに定義されている関数を呼ぶ
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)
    return 'OK'


#以下でWebhookから送られてきたイベントをどのように処理するかを記述する
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text))

# ポート番号の設定
if __name__ == "__main__":
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)
```

##※上記コードの補足説明
####try:〜
Webhookに関する記述。Webhookとはイベント（メッセージ送信、友達追加など）が起きた時にイベントを処理するサーバーへイベントを送る処理をするもの（サーバーへ送るためにはLINE DevelopersのWebhookにURLを指定が必要）。


###@handler.add(MessageEvent, message=TextMessage)
1つ目の引数にはイベントの種類を入れる（今回はメッセージが送られてきた時に返信したいので、MessageEventとした）、２つ目の引数にはメッセージの種類を入れる（今回はテキストを返したいので、message=TextMessageとした）。

###def handle_message(event):
イベント処理する関数handle_messageが呼び出され、reply_messageの第2引数の値がLINEの返信として返される。lineメッセージとして返すためにはlineb_bot_apiのreply_message関数を使う。reply_messageである第一引数のevent.reply_tokenはreply_tokenが入る。これはwebhookオブジェクトから取得できるもので、どのイベントに対して返信するのか識別するもの。イベントの応答トークンを意味する。第二引数にはlinebot.modelsに定義されている返信用のTextSendMessageという関数を入れ、この関数は引数に返すメッセージを入れる。
また、event.message.textはLINEから送られてきたメッセージが格納されている。例えば”おはよう”と送られてきたら、event.message.text="おはよう"が格納されている。仮に、TextSendMessage(text='おはよう'))とすれば、返信は全て"おはよう"と返す。
ちなみに、eventの中身は以下のようになっている。

```
{
  "message": {
    "id": "***************",
    "text": "おはよう",
    "type": "text"
  },
  "replyToken": "***********************",
  "source": {
    "type": "user",
    "userId": "************************"
  },
  "timestamp": *********************,
  "type": "message"
}
```

### port = int(os.getenv("PORT", 5000))
Herokuは動的にポート番号を割り当てているようなので、os.getenvを使用して，以下のようにする。os.getenv("PORT", 5000)は，環境変数'PORT'を取得を試みて、取得できた場合はその取得した値が返され、取得できない場合：5000が返される。5000はローカル環境で作業する場合を想定としたもの。

```
# ポート番号の設定
if __name__ == "__main__":
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)
```

#（４）LINE Developersに登録
[LINE Developers](https://developers.line.biz/ja/)へアクセスして、登録後、サービス提供者を表す「プロバイダー」を作成。プロバイダー内で新規チャネルを作成。チャネルの種類はMessage APIを選択。

#（５）Herokuの環境変数を設定
Herokuにログインして、アプリを作成する。今回は、testlinebot0319という名前とした。

```
heroku login
```

```
heroku create testlinebot0319
```

初期化して、

```
git init
```

herokuのアプリとgitを紐つけて、

```
heroku git:remote -a testlinebot0319
```

herokuの環境変数に、Line developersの「アクセストークンの文字列」と「チャンネルシークレットの文字列」を設定する。
例えば、heroku config:set YOUR_CHANNEL_ACCESS_TOKEN="チャネルアクセストークンの文字列" -a （アプリ名）とする。

```
heroku config:set YOUR_CHANNEL_ACCESS_TOKEN="チャネルアクセストークンの文字列" -a testlinebot0319
heroku config:set YOUR_CHANNEL_SECRET="チャネルシークレットの文字列" -a testlinebot0319
```

heroku上に環境変数がちゃんとセットされたか確認。

```
heroku config
```

#（６）その他、必要なファイルを揃える
Procfile、runtime.txt、requirements.txtを作成する。

runtime.txtは、自身のpythonのバージョンを確認の上作成する。

```.txt:runtime.txt

python-3.8.0
```

Procfileは以下を記述。

```:Prockfile
web: python main.py
```

requirements.txtは以下をターミナルで入力して記述。

```
pip freeze > requirements.txt
```

#（７）Herokuへデプロイ
gitを再度初期化、紐つけて、addして、the-firstという名前でcommitする。
最後にHerokuにプッシュ。

```
git init
heroku git:remote -a testlinebot0319
git add .
git commit -m'the-first'
git push heroku master
```

heroku openして、

```
heroku open
```

ブラウザに以下が出れば成功。

<img width="173" alt="スクリーンショット 2020-03-19 22.32.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29856/85dc8af5-f6a8-0c0d-ea08-78598a7acfbd.png">

#（８）LINE DevelopersのWebhook設定
以下のように、自分のHeroku上のアプリ名をLINE DevelopersのWebhook欄に設定する。Heroku上のアプリ名＝testlinebot0319
<img width="678" alt="スクリーンショット 2020-03-19 22.34.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29856/86c58922-c45b-150c-4e72-b8079d4062be.png">


この時、Webhookの利用をオンにしておく。
これで、LINE Developersの上記にあるQRコードを読み込み友達登録すればオウム返しのアプリの完成。
うまく、オウム返ししてくれないなどLINEBOTが機能しない場合は、Webhookの利用を、オン、オフを繰り返すとる場合がある（私の場合はそれでうまくいった）。

#参考にしたサイト
[1時間でWikipedia検索できるLINE BOTをサクッと作ってみよう！](https://qiita.com/Keisuke_Tsuji/items/7cac27db7d1bd030205a#comments)
[Python + Flask + HerokuでLINE BOT](https://qiita.com/mark-town/items/024ff4c24f0c769f025e)
[【Python初心者! -LINE Botでオウム返し編-】](https://www.wantedly.com/companies/casley/post_articles/139107)