LINE Bot を Python Flask を使って  Now.sh (Zeit.co) 上で無料で簡単に動かす方法

LINE で自動で返信してくれる Bot が、今ナウい [Now.sh (Zeit.co)](https://zeit.co/now) 上に Python Flask を使って無料で簡単に作れます！

**Now.sh とは？**

- PaaS：ソースコードをデプロイ（利用可能にすること）するだけで自前サーバーなしでプログラムが動かせる！
- 小規模なら無料！クレジットカード不要
- HTML/CSS/JavaScript を使った静的 Web ページ、Node.js、Go、PHP、**Python**(今回使う)、Rust、Bash、Markdown などに対応
- https 対応（LINE Bot を作るには必須）
- [Heroku](https://www.heroku.com) のようにスリープ後の復帰に時間がかからない（1秒以内）

**Now.sh の無料での制限**

- 帯域幅 100 GB/月
- **ビルドとリクエスト 1000回/日**
- 最長実行時間 10秒
- ログ 1000回/日
- ストレージ 100GB
- ファイルサイズ 100MB/ファイル
- ビルド 32回/時、100回/日

個人/少人数利用ならまったく問題ないですね。

（https://zeit.co/pricing, https://zeit.co/docs/v2/deployments/builds#limits）

# 完成イメージ
<img width="375" alt="LINE Screenshot" src="https://qiita-image-store.s3.amazonaws.com/0/155587/d6fd69a0-c122-be72-d3fa-15029cd295e9.jpeg">

# 流れ
<img width="630" src="https://qiita-image-store.s3.amazonaws.com/0/155587/ca9bcab1-e4bb-f829-8be8-525accc809cc.png">
LINE で Bot にメッセージが送られると LINE Messaging API から Now.sh 上のサーバーに POST リクエストが飛ぶので、サーバー上で処理をして、メッセージを LINE Messaging API にまた POST で返します。

1. LINE Developers の登録
2. Now.sh (Zeit.co) の登録
3. ファイルの作成と Now.sh へのデプロイ

という順番でやっていきます。

# 1. LINE Developers の登録

1. https://developers.line.biz/console/ にアクセスしてログイン
2. プロパイダー作成
3. チャネル作成：`Messaging API` を選択。プランは `Developer Trial` がおすすめ

この `Developer Trial` には特に有効期限はありませんが、友だちが50人までという制限があります。

登録方法について詳しくはこちらへ：https://developers.line.biz/ja/docs/messaging-api/getting-started/

登録が終わったら設定をします。

**[チャネル基本設定]**

**メッセージ送受信設定**
アクセストークン（ロングターム）：「**再発行**」をクリック → **0時間**に設定（＝失効しない）
Webhook送信：**利用する**

**LINE@機能の利用**
自動応答メッセージ：**利用しない**
友達追加時あいさつ: **利用しない**

設定が終わったらこのページは後でまた使うのでそのままにしておいてください。

# 2. Now.sh (Zeit.co) の登録

:information_source: ここではコマンドラインを使用しますが、GUI アプリもあります：https://zeit.co/download

まず `brew` または `npm` を使って `now` をインストールします。

[Homebrew](https://brew.sh/index_ja)（Mac） を使用：

```sh
$ brew cask install now
```

`npm` を使用（[インストール方法](https://www.google.co.jp/search?q=node.js+インストール)）：

```sh
$ npm install -g now
```

インストールが終われば `now` を実行します。
メールアドレスの入力を求められるので入力すると、
<img width="955" alt="Verify email" src="https://qiita-image-store.s3.amazonaws.com/0/155587/fb6bbcf7-9d9c-210e-da6a-6fb93a907747.png">
というメールが届くので **VERIFY** をクリックすると登録完了です。

# 3. Now.sh へのデプロイと設定

## ファイルの作成

まずディレクトリを作ります。

```sh
$ mkdir line-bot
$ cd line-bot
```

必要なファイルは `app.py` `now.json` `requirements.txt` の3個です。
`now.json` の `エイリアス` の部分は `username-line-bot` など自由に置き換えてください。

```app.py
import os
from flask import Flask, request, abort, redirect
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError, LineBotApiError
from linebot.models import MessageEvent, TextMessage, TextSendMessage

app = Flask(__name__)
line_bot_api = LineBotApi(os.environ['ACCESS_TOKEN'])
handler = WebhookHandler(os.environ['CHANNEL_SECRET'])


@app.route('/', methods=['POST'])
def callback():
    try:
        signature = request.headers['X-Line-Signature']
    except KeyError:  # POSTリクエストのヘッダーに署名がないとき
        print('No signature in header:' + request.remote_addr)
        abort(400)

    body = request.get_data(as_text=True)
    print('Request body: ' + body)

    try:
        handler.handle(body, signature)
    except LineBotApiError as e:  # 何らかのエラー
        print("LINE Messaging API Error: %s\n" % e.message)
        for m in e.error.details:
            print("  %s: %s" % (m.property, m.message))
        print("\n")
    except InvalidSignatureError:  # POST リクエストの署名が無効のとき（LINE API からでないとき）
        print('Signature was in header, but invalid:' + request.remote_addr)
        abort(400)

    return 'OK'


@handler.add(MessageEvent, message=TextMessage)  # テキストメッセージを受け取ったときの処理
def handle_message(event):

    received = event.message.text
    send_message = received + '！'

    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=send_message)
    )
```

```now.json
{
  "version": 2,
  "builds": [
    { "src": "app.py", "use": "@sisp/python-wsgi", "config": { "maxLambdaSize": "15mb" } }
  ],
  "env": {
    "ACCESS_TOKEN": "@access-token",
    "CHANNEL_SECRET": "@channel-secret"
  },
  "routes": [
    { "src": "/.*", "dest": "/"}
  ],
  "regions": ["hnd1"],
  "alias": ["エイリアス.now.sh"]
}

```
```requirements.txt
flask
line-bot-sdk
```


## 環境変数の設定

続いて、環境変数を設定します。
先ほど開いた https://developers.line.biz/console/channel/ にアクセスします。

以下の2つの情報を使います。

**基本情報**
Channel Secret

**メッセージ送受信設定**
アクセストークン（ロングターム）

そして以下のコマンドを実行します。`YOUR_CHANNEL_SECRET_HERE`, `YOUR_ACCESS_TOKEN_HERE` は上の Channel Secret とアクセストークンに置き換えてください。

```sh
$ now secret add channel-secret YOUR_CHANNEL_SECRET_HERE
$ now secret add access-token YOUR_ACCESS_TOKEN_HERE
```

そして、同じく **メッセージ送受信設定** から

Webhook URL：先程 `now.json` で指定した **`エイリアス.now.sh`** を入力

「接続確認」を押すとエラーになりますが、認証が通っていないだけなので問題ありません。

## デプロイ

準備が終わりました。ファイルを Now.sh にアップロードしてデプロイ（利用可能にすること）します。

```sh
$ now
```

と3文字打つだけです！簡単！

**完成です！** :tada::tada::tada:
実際に Bot にメッセージを送ってみてください。

---

更新したいときはまた

```sh
$ now
```
と打つだけで更新されます。（1分ほど時間がかかります）

# おまけ：ローカルでの開発

ファイルに変更を加えた後いちいち Now.sh にデプロイするのは時間がかかるので開発用にローカルサーバーを作ります。

今度はこうなります。
<img width="1022" src="https://qiita-image-store.s3.amazonaws.com/0/155587/43fe96d5-52ae-b66b-6437-adfdcf57dfc7.png">

ngrok というのは、ローカルサーバーにインターネットからアクセスできるように URL を与えてくれるものです。ポート開放などの手間がなくなります。コマンド1発で数秒で URL が生成されます。

## Python, Flask のインストール
```sh
$ brew install python
```
最初から `python` が入っている場合はコマンド名 `python`,`pip` がそれぞれ `python3` や `pip3` になります。
面倒なのでエイリアス設定してしまいます。

```sh:~/.bashrcなど
alias py='python3'
alias pip='pip3'
```

そして `flask` のインストール。

```sh
$ pip3 install flask
```

## ngrok のインストール

```sh
$ brew cask install ngrok
```

## ローカルサーバー起動

```sh
$ flask run --reload
```
この `--reload` オプションはファイルが変更されるごとに自動でリロードしてくれるオプションです。

```
* Running on http://127.0.0.1:5000/
```
などと表示されるので `:` 以降のポート番号の部分を覚えておきます。

ターミナルで新しいタブまたはウインドウを開いて以下の `5000` の部分を先程のポート番号に変更します（デフォルトでは `5000` なので変えなくて良い）。

```sh
$ ngrok http 5000
```
http://localhost:4040 にアクセスすると POST の内容とかが見れます。便利！
<img width="1241" src="https://qiita-image-store.s3.amazonaws.com/0/155587/1ba59a66-868f-7429-b4a3-8dac999f6a07.png">

# あとがき
マルコフ連鎖と組み合わせると自動生成したメッセージを返せるので面白いですね。
https://qiita.com/shge/items/fbfce6b54d2e0cc1b382

# 参考
https://qiita.com/nkjm/items/38808bbc97d6927837cd
https://qiita.com/vimyum/items/2226daa74444575811b5
https://qiita.com/tetrapod117/items/a7079b9cc2d2c9ac4f14