9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

LINE WORKS トークBot をPythonで実装してみる 〜後編: チャットボット実装〜

Last updated at Posted at 2019-07-09

前回

LINE WORKSのAPIを使うために必要な各種設定とTokenの発行までを行いました。
前回: https://qiita.com/mmclsntr/items/1d0f520f1df5dffea24b

今回は、実際のチャットボットの実装を行います。

LINE WORKS トークBotの仕組み

ユーザーからのメッセージを受信し、それに応じた返答を返すという対話を行うために、LINE WORKSでは トーク Bot API が用意されています。
トークBot APIの概要: https://developers.worksmobile.com/jp/document/3005001?lang=ja

メッセージ送受信用Webアプリケーションを用意し、LINE WORKS Developer Console上でBotにコールバックURLとして紐付けを行うことで、LINE WORKS上にチャットボットを実装することができます。

今回は、PythonとAWS Lambdaを使って開発したいと思います。

検証環境

言語: Python 3.7
実行環境: AWS Lambda

今回は、AWS API Gateway + Lambdaの構成で作りました。

1. チャットボット開発

1.1. リクエスト検証

コールバックに設定したサーバーに送られて来たリクエストが正しいものであるか、その確認をする仕組みが用意されています。
https://developers.worksmobile.com/jp/document/1005009?lang=ja

以下、コードサンプル。

import os
from base64 import b64encode, b64decode
import hashlib
import hmac

API_ID = os.environ.get("API_ID")  # API ID

def validate_request(body, signature):
    """
    リクエスト検証
    """
    # API IDを秘密鍵に利用
    secretKey = API_ID.encode()
    payload = body.encode()

    # HMAC-SHA256 アルゴリズムでエンコード
    encoded_body = hmac.new(secretKey, payload, hashlib.sha256).digest()
    # BASE64 エンコード
    encoded_b64_body = b64encode(encoded_body).decode()

    # 比較
    return encoded_b64_body == signature

1.2. メッセージの受信

送られてくるメッセージのタイプは大きく分けて5つあります。

タイプ 説明
message 一般メッセージ。
join Bot を複数人トークルームに招待。
leave Bot が複数人トークルームから退室。
joined メンバーが Bot の属するトークルームに参加。
left メンバーが Bot の属するトークルームから退室。

特に、message には、下の4タイプあります。

メッセージタイプ 内容
text テキスト
location 位置情報
sticker スタンプ
image 画像

LINEと同じくスタンプメッセージにも対応してます。

メッセージ受信 - Callback 形式: https://developers.worksmobile.com/jp/document/1005009?lang=ja

1.3. 返答メッセージ返答

返答メッセージを送るために、メッセージ送信用のAPIを使います。

メッセージ送信: https://developers.worksmobile.com/jp/document/1005008?lang=ja

これは、リプライだけでなくプッシュ通知を行う際も使われます。
このAPIを利用する際に、前回発行したTokenを利用します。

送信できるメッセージのタイプは以下の通り。

メッセージタイプ 内容
text テキスト
image 画像
link リンク
buttonTemplate ボタンテンプレート
listTemplate リストテンプレート
sticker スタンプ

以下、コードサンプル。

import os
import json
import requests
import urllib

API_ID = os.environ.get("API_ID")  # API ID
SERVER_API_CONSUMER_KEY = os.environ.get("SERVER_API_CONSUMER_KEY")  # Server API Consumer Key
BOTNO = os.environ.get("BOTNO")  # Bot No

TOKEN = os.environ.get("LW_TOKEN")  # 発行したToken

def send_message(content, account_id):
    """
    送信
    """
    url = 'https://apis.worksmobile.com/' + API_ID + '/message/sendMessage/v2'
    headers = {
          'Content-Type' : 'application/json;charset=UTF-8',
          'consumerKey' : SERVER_API_CONSUMER_KEY,
          'Authorization' : "Bearer " + TOKEN
        }
    params = {
            "botNo" : int(BOTNO),
            "accountId" : account_id,
            "content" : content
        }

    form_data = json.dumps(params)

    r = requests.post(url=url, data=form_data, headers=headers)
    if r.status_code == 200:
        return True

    return False

※ 注意

メンバー数によってクォータ(最大送信数の制限)が設定されています。
メンバー数が 100 人以下 : 最大 20,000 回 / 日
メンバー数が 100 人超過 : 最大 20,000 回 + (超過するメンバー数)*100 回 / 日
クォータは 0 時(GMT +9)にリセットされます。
クォータの 80%、90%、100% に到達すると、管理者に通知メールを送信します。

1.4. コード全体

サンプルとして、「こんにちは」と送られたら「こんにちは!」と返す超シンプルなボットを作れるコードを貼ります。

handler.py
import os
import json
import requests
import urllib

from base64 import b64encode, b64decode
import hashlib
import hmac

from requests.structures import CaseInsensitiveDict

API_ID = os.environ.get("API_ID")  # API ID
SERVER_API_CONSUMER_KEY = os.environ.get("SERVER_API_CONSUMER_KEY")  # Server API Consumer Key
BOTNO = os.environ.get("BOTNO")  # Bot No

TOKEN = os.environ.get("LW_TOKEN")  # 発行したToken


def validate_request(body, signature):
    """
    リクエスト検証
    """
    # API IDを秘密鍵に利用
    secretKey = API_ID.encode()
    payload = body.encode()

    # HMAC-SHA256 アルゴリズムでエンコード
    encoded_body = hmac.new(secretKey, payload, hashlib.sha256).digest()
    # BASE64 エンコード
    encoded_b64_body = b64encode(encoded_body).decode()

    # 比較
    return encoded_b64_body == signature


def send_message(content, account_id):
    """
    送信
    """
    url = 'https://apis.worksmobile.com/' + API_ID + '/message/sendMessage/v2'
    headers = {
          'Content-Type' : 'application/json;charset=UTF-8',
          'consumerKey' : SERVER_API_CONSUMER_KEY,
          'Authorization' : "Bearer " + TOKEN
        }
    params = {
            "botNo" : int(BOTNO),
            "accountId" : account_id,
            "content" : content
        }

    form_data = json.dumps(params)

    r = requests.post(url=url, data=form_data, headers=headers)
    if r.status_code == 200:
        return True

    return False


def handler(event, context):
    """
    チャットボット処理
    """
    event = CaseInsensitiveDict(event)
    headers = event["headers"]
    body = event["body"]

    # リクエスト検証
    if not validate_request(body, headers.get("x-works-signature")):
        # 不正なリクエスト
        return

    # Jsonへパース
    request = json.loads(body)

    # 送信ユーザー取得
    account_id = request["source"]["accountId"]

    res_content = {
        "type" : "text",
        "text" : "テキストのみ対応"
    }

    # 受信したメッセージの中身を確認
    request_type = request["type"]
    ## Message
    if request_type == "message":
        content = request["content"]
        content_type = content["type"]
        ## Text
        if content_type == "text":
            text = content["text"]
            if text in "こんにちは":
                res_content = {
                    "type" : "text",
                    "text" : "こんにちは!"
                }
            else:
                res_content = {
                    "type" : "text",
                    "text" : "・・・"
                }

    # 送信
    rst = send_message(res_content, account_id)

    res_body = {
        "code": 200,
        "message": "OK"
    }
    response = {
        "statusCode": 200,
        "headers": {
            "Content-Type": "application/json"
        },
        "body": json.dumps(res_body)
    }

    return response

2. デプロイ

AWS Lambdaへデプロイ (ランタイム: Python 3.7)
トリガーとしてAPI Gatewayを置く。

3. Botの登録

最後に、Botをテナントへ登録する。

  1. LINE WORKS Developer Consoleで、Botの設定の「Callback URL」に、今回作成したAPI Gatewayのエンドポイントを設定する。
  2. LINE WORKS 管理画面で、「サービス>Bot」から上記Botを追加する。

最後に

これで、LINE WORKS トークBotをPythonで実装することができました。
LINE WORKSには他にもいろいろAPIがあるので、社内システムとの連携も含め、多彩なチャットボットが実現できると思います。
今の所、SDKがないので自前でURL叩く必要があります。。SDK欲しいですねー

参考

https://qiita.com/comefigo/items/ce573e4ff5d86519eb16
https://qiita.com/tokotan/items/976d35ca56132e0bb5c1
https://utano.jp/entry/2018/01/hmac-sha-256-python/

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?