ども!AWS認定SAアソシエイトのまとんです。
LINE botに話しかけると、生命保険の金額を教えてくれる仕組みをで作ったので紹介します!
使ったもの:AWSを使ってサーバーレス実装しました。
- LINE関連:Messaging API, line-bot-sdk-python 1.14.0
- AWS関連:Amazon API Gateway, AWS Lambda
- 為替レート取得:OANDA API
- 開発環境:Python 3.7, Windows 10, Windows Subsystem for Linux (Ubuntu)
経緯
先日、ドル建て生命保険の解約返戻金をLINEに通知してくれる仕組みを作りました。
SORACOMのボタンを押すと、LINEのトークルームに金額を通知してくれるという仕組みです。
このボタンをダイニングテーブルの上に置いておきました。
嫁には「好きな時にボタンを押していいよ!」と言っておいたのですが・・・
嫁いわく、「ボタンを押すのがめんどくさい。LINEで反応させてくれ」とのこと。
ボタンを押すことさえ、手間。LINE上で完結させないとダメのようです。
となると、実装がガラリと変わるので、大変なのですが。。。
しかし、顧客(嫁)が本当に求めているものを、何としてでも作って提供するのがエンジニア冥利というものです。
というわけで、LINE Botで返事をする仕組みを作りました。
作りたいもの
今回の要求仕様は以下の通りです。
完成形のイメージ:
実装
アーキテクチャ
LINEはMessaging APIなるサービスで、独自のbotを作る仕組みを提供しています。
Messaging APIで作った自分専用のbotを、僕と嫁のトークルームに参加させます。
トークルームで話しかけると、botのMessaging APIが反応し、webhookで別システムのAPIを叩くことができます。
別システムとして、AWSを使用します。
AWSではAPI Gatewayを使って、自分のAPI(アドレス)を簡単にインターネット公開することができます。
Messaging APIのwebhookでAPI Gatewayのアドレスを叩くように設定することで、LINEとAWSを連結させることができます。
API Gatewayは、後段のLambdaを起動して、POSTメッセージを捌く処理を実装します。
POSTの応答で、botに生命保険金額を発言するように返せばOKです。
生命保険金額の複利計算と、ドル円為替レートの取得については、前回の記事で詳細に説明したので、この記事では省略します。
Messaging API
LINE botを作っていきます。以下の記事を参考にさせていただきました。
LambdaではじめてのLINE Botを作る | DevelopersIO
LINE Developersに登録して、bot用チャネルを作成
まず、LINE Developersコンソールに、自分のLINEアカウントでログインします。
新規プロバイダーを作成します。プロバイダーとは、開発者(企業・個人)の名前です。
プロバイダー名「メタラーまとん」で作成しました。
次に、Messaging APIのチャネルを作成します。チャネルは、botことだと理解しています。
チャネル名「メタラーまとん」で作成しました。
チャネルの設定
メタラーまとんチャネルの「チャネル基本設定」カラムで、色々と設定します。
・Channel Secretの文字列をコピー
・アクセストークン(ロングターム)を発行→文字列をコピー
「グループ・複数人チャットへの参加を許可する」にチェック。自分と嫁のグループチャットを使うため。
・LINE@機能の利用→自動応答メッセージ→設定はこちら
「応答メッセージ」をオフ。デフォルト(オン)では、話しかけたときに毎回返信をするようになっている。今回は不要なのでオフにする。
AWS
必要なライブラリをzipで固めてLambdaにアップロードする
今回の実装では、LambdaのPython3.7ランタイムを使います。
Lambdaでサードパーティのライブラリを使いたいときは、直接pip installすることができず、一旦ローカルでpipをして、zipで固めてアップロードする必要があります。
今回必要なライブラリは、line-bot-sdk、oandapyV20、requestsです。これらをzipで固めていきます。
僕は開発環境でWindows 10を使っていて、pipするのが難しいです。
そこで、Windows Subsystem for Linux (WSL)でUbuntuを走らせて、この上でpipしていきます。WSLへのPythonインストール手順は割愛します。
作業用ディレクトリ作成、移動
$ mkdir HighsoButton
$ cd HighsoButton
ライブラリを作業用ディレクトリにインストール
$ sudo pip3 install oandapyV20 -t ./
$ sudo pip3 install requests -t ./
$ sudo pip3 install line-bot-sdk -t ./
不要ファイルを削除
$ rm *.dist-info -r
フォルダごとzipに固める
$ sudo zip -r HighsoLineBot.zip ./*
「HighsoLineBot.zip」ができればOKです。
WSLを使っている人は、下記コマンドでzipをWindows環境にコピーしましょう。
$ cp HighsoLineBot.zip /mnt/c/Users/<ユーザー名>/Desktop/
次に、AWS Lambdaで、新しいLambda関数を作成します。
関数名:HighsoLineBot
リージョン:オレゴン
ランタイム:Python 3.7
コードエントリタイプ→「.zipファイルをアップロード」で、先ほど作成したzipをアップロードし、画面右上の「保存」ボタンを押します。
./HighsoLineBot/ 以下に、各種ライブラリのフォルダが出現すればOKです。
./HighsoLineBot/に、新しいPython「lambda_function.py」を作成して、保存します。
AWS LambdaでPOST処理を書く
lambda_function.pyに、POSTを捌く処理を書いていきます。
line-sdk-botの使い方について、以下の記事を参考にさせていただきました。
Lambdaでline-bot-sdk-pythonを使用してオウム返しBOTを作成する - Qiita
Lambdaでやることは以下の通りです。太字以外の部分は、前回の記事で実装済みです。
- OANDA APIでドル円為替レートを取得
- 生命保険金の複利運用額を計算し、ドル円換金額を計算
- LINE-botハンドラーを作成。
- botからイベントを受け取り、X-Line-Signatureで認証
- メッセージ内に「円」「いくら」等特定の文字列があったら、2で計算したドル円換金額を答えるよう、botに指示
- POSTのステータスコードをjsonで返す
具体的には、以下のコードをlambda_function.pyに書きました。(太字が今回実装した部分)
import json
import sys
import urllib.parse
import urllib.request
import datetime
import os
from oandapyV20 import API
import oandapyV20.endpoints.instruments as instruments
from datetime import datetime as dt
from datetime import timedelta
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
from linebot.exceptions import (
LineBotApiError, InvalidSignatureError
)# LINE Messaging API
LINE_CHANNEL_SECRET = os.getenv('LINE_CHANNEL_SECRET', None)
LINE_CHANNEL_ACCESS_TOKEN = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', None)
if LINE_CHANNEL_SECRET is None:
print('Specify LINE_CHANNEL_SECRET as environment variable.')
sys.exit(1)
if LINE_CHANNEL_ACCESS_TOKEN is None:
print('Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.')
sys.exit(1)
line_bot_api = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(LINE_CHANNEL_SECRET)#OANDA API
OANDA_ACCESS_TOKEN = os.environ.get('OANDA_ACCESS_TOKEN')
api = API(access_token=OANDA_ACCESS_TOKEN)
def get_USDJPY():
params = {
'count': 1,
'granularity': 'D'
}
r = instruments.InstrumentsCandles(instrument="USD_JPY", params=params)
api.request(r)
data = []
for raw in r.response['candles']:
data.append({
'time': raw['time'],
'volume': raw['volume'],
'o': raw['mid']['o'], #始値
'h': raw['mid']['h'], #高値
'l': raw['mid']['l'], #安値
'c': raw['mid']['c'], #終値
})
print(data)
#前日の終値
date = dt.strptime(data[0]['time'][:19], '%Y-%m-%dT%H:%M:%S')
date = date + timedelta(hours = 9)
#print(date)
exchange_rate = float(data[0]['c']) #USD-JPYレート
msg1 = str(date.year) + '年' + str(date.month) + '月' + str(date.day) + '日'
msg2 = 'USD-JPY終値: ' + str(exchange_rate) + '円'
print(msg1)
print(msg2)
#日ごとの複利計算
start_date = dt(year=2019, month=8, day=20) #保険開始日
elapsed_time = date - start_date
elapsed_day = elapsed_time.days
msg3 = '経過日数: ' + str(elapsed_day) + '日'
print(msg3)
## Y = a*b^X
## 解約返戻金(USD) = a*b^(経過日数)
a = 8457.28972
b = 1.00007929
refund_USD = a * b ** elapsed_day
#refund_USD = refund/5
exchange_fee = 0.5 #USDからJPYへの為替手数料(円)
refund_JPY = refund_USD * (exchange_rate - exchange_fee)
msg4 = '複利運用額: ' + str(round(refund_USD, 1)) +'ドル'
msg5 = '解約返戻金: ' + str(round(refund_JPY, 1)) + '円'
msgs = '\n'.join([msg1, msg2, msg3, msg4, msg5])
print(msgs)
return msgs
def send_line_bot(signature, body, msg_refund):
ok_json = {"isBase64Encoded": False,
"statusCode": 200,
"headers": {},
"body": ""}
error_json = {"isBase64Encoded": False,
"statusCode": 403,
"headers": {},
"body": "Error"}@handler.add(MessageEvent, message=TextMessage)
def message(line_event):
text = line_event.message.text
if '円' in text or 'いくら' in text:
rep = msg_refund
line_bot_api.reply_message(line_event.reply_token, TextSendMessage(text=rep))
elif 'まとん' in text:
rep = 'いじめないで・・・'
line_bot_api.reply_message(line_event.reply_token, TextSendMessage(text=rep))
try:
handler.handle(body, signature)
except LineBotApiError as e:
print("Got exception from LINE Messaging API: %s\n" % e.message)
for m in e.error.details:
print(" %s: %s" % (m.property, m.message))
return error_json
except InvalidSignatureError:
return error_jsonreturn ok_json
def lambda_handler(event, context):
msg_refund = get_USDJPY()
signature = event["headers"]["X-Line-Signature"]
body = event["body"]
res = send_line_bot(signature, body, msg_refund)
print(res)
return res
アクセストークンなどのクレデンシャルをコードにハード埋め込みしないよう、Lambdaの環境変数に、以下を登録します。
・Messaging APIのChannel Secret
・Messaging APIのアクセストークン(ロングターム)
以上の設定が終わったら、Lambdaを保存します。
Amazon API GatewayでMessaging APIのwebhookをLambdaに投げる
プロトコル:REST
新しいAPI
API名:HighsoInvestment
エンドポイントタイプ:リージョン
リソース→アクション→メソッドの作成→POSTを選択
統合タイプ:Lambda関数
Lambdaプロキシ統合の使用:チェック
Lambdaリージョン:us-west-2 (オレゴン)
Lambda関数:HighsoLineBot
メソッドリクエストを設定
・HTTPリクエストヘッダーに名前「X-Line-Signature」を追加
POSTが以下のようになっていればOK
アクション→APIのデプロイ
新しいステージを選択。
ステージ名「beta」でデプロイ
デプロイが完了すると、URLが表示されるのでコピーする。
API GatewayとLambdaの連携に成功すると、Lambdaの画面で以下のようにAPI Gatewayトリガーが追加されたことが分かる。
最後に、Messaging APIの設定画面に戻り、以下の設定をすれば完了。
・Webhook送信:利用する
・Webhook URL:先ほどデプロイしたAPI Gatewayのアドレス
botを友達登録して、トークルームにbotを招待
Messaging APIの「LINEアプリへのQRコード」を、LINEの友達追加で読み取り、bot「メタラーまとん」を友達登録。
僕と嫁が参加しているトークルームに、メタラーまとんを招待。botなので一瞬で承認して入ってきます。
上のLambda関数だと、「円」「いくら」を含む発言をすると、解約返戻金を教えてくれて、「まとん」を含む発言をすると「いじめないで・・・」と返事をします!
デモ動画
生命保険の解約返戻金を通知してくれるLINE botを作りました。「円」に反応して、ドル建て生命保険の運用額を円に換算して教えてくれます。 Messaging API, AWS Lambda, OANDA API pic.twitter.com/10GOyKz3vi
— メタラーまとん@はてなブログ (@Highso_ciety) September 22, 2019
感想
LINE Botを作るのはめちゃくちゃ簡単でした!
親切な解説記事があったおかげとはいえ、わずか2.5時間でLINE botを作れました。
botを作ると、さっそく嫁が色々と遊んでくれたので、満足です。
みなさんもLINE Botを作って遊んでみてください。
以上、メタラーまとんでした。
ではでは。
ファイナンシャル × IoT記事まとめ
1. ドル円為替レートをLINEに通知するハイソ投資ボタンを作った! Lambda, LINE Notify, OANDA, SORACOM
2. ドル建て生命保険の解約返戻金を計算してLINEに通知する仕組みを作った!
3. LINE Botに生命保険の解約返戻金を教えてもらえるようにした!Messaging API, Amazon API Gateway, Lambda