Cloud Functions (Python3)入門用に LINE BOTを作ってみる

#はじめに
今回の目的はLINE BOTの下地をCloud Functions(GCF)を使って作ること。
言語としては、最近サポートされはじめたPython3を使用する。
LINEで公開しているサンプルコードにあるオウム返しするアプリを、Cloud Functionsでうごかしてみる。

#今回つかってみるもの
- LINE Messaging API
- Google Cloud Functions
- Python3

#準備
##　LINE BOT
###　LINE Developersへ登録
以下のURLからLINE Developersへサインアップ
https://developers.line.biz/ja/

###プロバイダーとチャネルの作成
プロバイダーとチャネルという概念があるが、

####プロバイダーを作成
<img width="1287" alt="プロバイダー作成" src="https://qiita-image-store.s3.amazonaws.com/0/32691/9c0f517e-bece-f62b-2201-7e2dc0b4aa74.png">
####チャネル作成を選び、MessageAPIを選択
<img width="1284" alt="チャネル作成を選んでMessageAPIを選択" src="https://qiita-image-store.s3.amazonaws.com/0/32691/4c7bafd4-5c17-df33-0191-fa4a75c8aeb8.png">
####チャネル作成完了
<img width="1289" alt="チャネル完成" src="https://qiita-image-store.s3.amazonaws.com/0/32691/c9b7684c-664f-4c09-0b9e-a792795afbde.png">
####　チャネルの基本設定の確認
以下は後ほどアプリケーション内で使う。
#####Channel Secretの確認
基本設定　>　基本情報　>　Channel Secret
#####AccessTokenを作成し、確認
基本設定 > メッセージ送受信設定　> AccessToken

<img width="1287" alt="チャネル詳細" src="https://qiita-image-store.s3.amazonaws.com/0/32691/66c000f0-f3ee-7e14-d9ba-9a66e075af79.png">


##Cloud Functions
###Google Cloud
以下から登録
https://cloud.google.com/

迷うことはないと思いますが、わからなくてもググればいい記事が出てくるはずなので割愛。

###Cloud Functionsの作成
 - Cloud Functions API を有効化
<img width="730" alt="スクリーンショット 2018-12-25 0.29.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/32691/4839e1f4-1ea6-5f42-2ed0-8f626b930efd.png">
 - 作成ボタンを押す
<img width="728" alt="スクリーンショット 2018-12-25 0.30.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/32691/34ba8e7f-8ea7-7376-976c-54c45687597a.png">
 - 各種項目を設定する

ひとまず以下のようにうめる

| 項目 | 値 | 
|:-----------|:------------|
| 名前 | （任意） |
| 割り当てられるメモリ | 256MB |
| トリガー | HTTP |
| URL | (自動) |
| ソースコード | インラインエディタ |
| ランタイム | Python3.7 |
| 実行する関数| (任意。main.pyの中にある関数を指定) |
<img width="717" alt="スクリーンショット 2018-12-25 0.30.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/32691/770ac83b-8a34-5ef9-458f-233f289846a3.png">
 - 項目を埋めたら作成
<img width="720" alt="スクリーンショット 2018-12-25 0.33.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/32691/e952e08e-a054-c48e-bfa7-3c4fdcd186f4.png">

#実装
コードはローカルで実装し、git管理して、gcloudコマンドでデプロイしてもいいし、今回くらいの規模なら、直接インラインエディタで書いてもいいかもしれない。

##ディレクトリ構造

```
　project/
　　　　├　main.py
　　　　└　requirements.txt
```

##Python3での実装
実行される関数をかく

```python:main.py
import os
import base64, hashlib, hmac
import logging

from flask import abort, jsonify

from linebot import (
    LineBotApi, WebhookParser
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage
)
    
def main(request):
    channel_secret = os.environ.get('LINE_CHANNEL_SECRET')
    channel_access_token = os.environ.get('LINE_CHANNEL_ACCESS_TOKEN')

    line_bot_api = LineBotApi(channel_access_token)
    parser = WebhookParser(channel_secret)

    body = request.get_data(as_text=True)
    hash = hmac.new(channel_secret.encode('utf-8'),
        body.encode('utf-8'), hashlib.sha256).digest()
    signature = base64.b64encode(hash).decode()

    if signature != request.headers['X_LINE_SIGNATURE']:
        return abort(405)

    try:
        events = parser.parse(body, signature)
    except InvalidSignatureError:
        return abort(405)


    for event in events:
        if not isinstance(event, MessageEvent):
            continue
        if not isinstance(event.message, TextMessage):
            continue

        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text=event.message.text)
        )
    return jsonify({ 'message': 'ok'})
```

pip install しないといけないものをここに記載する

```text:requirements.txt
# Function dependencies, for example:
# package>=version
line-bot-sdk
```

##Cloud Functionsのローカルエミュレータについて
残念ながら、Python3は対応していないので割愛

##Cloud Functions へデプロイ
```
gcloud functions deploy hogehoge --trigger-http
```
##　Cloud Functions の環境変数の設定
上述したように、チャネル設定を確認し、
Channel Secretを`LINE_CHANNEL_SECRET`として
AccessTokenを`LINE_CHANNEL_ACCESS_TOKEN`として設定する。


### Cloudコンソールから
<img width="５" alt="スクリーンショット 2018-12-25 0.42.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/32691/635c8e84-4bc3-25f5-7362-ed74da67c7da.png">

###コマンドから
```
gcloud functions deploy hogehoge --trigger-http --set-env-vars LINE_CHANNEL_SECRET=123456789qwert123456789qwert,LINE_CHANNEL_ACCESS_TOKEN=123456789qwert
```

#挙動
##LINE BOT
###友だち追加
チャネル基本設定に「LINEアプリへのQRコード」という項目があるので、
<img width="960" alt="スクリーンショット 2018-12-26 8.24.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/32691/a3325d56-4a29-a291-8311-38a18ee08846.png">

それを読み取ると作ったBOTを友だちに追加できる。
<img width="200" alt="IMG_2049.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/32691/cb124245-6bfc-a5ae-c31f-e4c644cb2718.png">

###チャット
追加すると、チャットをはじめられる。
<img width="200" alt="IMG_2050.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/32691/6c462dae-54c2-bf96-3a5a-e2701b9fbd38.png">

今回はオウム返しするサンプルコードを使ったのでこんな感じ。
とりあえずこれで最低限の挙動は確認できた。
<img width="200" alt="IMG_2052.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/32691/eb89ecab-241b-49b0-3afe-ff127f4e546b.png">

#まとめ
以下の簡単な使い方だけまとめました。
　-　LINE Messaging API
　-　Google Cloud Functions
　-　Python3

やったこととしては、LINEで公開されているサンプルコードにあるオウム返しするアプリを、
Cloud Functions(Python)でうごかしてみた。
基本的にLINEとGoogleの公式ドキュメントが丁寧なので、それを見ていれば問題なさそう。
(特にLINEのドキュメントにはPythonのコードが多いので、Pythonで実装していると楽かもしれない)

#参考
 - https://developers.line.biz/ja/reference/messaging-api/
 - https://cloud.google.com/functions/docs/concepts/python-runtime

#展望
今回つくったものを基に、他APIと連携などしてちゃんとしたアプリケーションを作っていく。
Python3は現時点でベータ版なので、今後仕様がいろいろかわるかもしれないが・・・。
(ローカルエミュレータはやく対応してくれ)