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


前回

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/