develop line_bot with logicflow
TRANSCRIPT
Develop LINE BOTwith LogicFlow
2017/11/18
LogicFlow-ja 小尾智之(Ahf)
事前準備
• LINE アカウント
• LINE Developer アカウント
• Azure サブスクリプションまたはFlow アカウント(Microsoft アカウント)
https://goo.gl/pxwBH9からスキーマ定義を DL しておいてください
LINE DEVELOPER アカウント作成
https://developers.line.me/ja/
LINE アカウントでログイン
初ログイン時は端末上で本人確認あり(LINEアプリ必要)
作成済みの BOT 情報が表示される初回は何も表示されない
本名である必要はなくあとで修正も可能
Messaging API をクリック
BOT 用チャンネル情報を設定する
Developer Trial を選択
一通り設定したら確認をクリック規約への同意など求められるのでチェックをつけて作成をクリック
LINE DEVELOPER の設定はひとまずここまで
現状では上記のように送受信設定が行われていない状態でOKです
LogicApps/Flow で受け取る
1.LogicApps の追加をクリック2.名前を入力3.利用するサブスクリプションを選択4.リソースグループを選択または新規入力5.利用するリージョンを選択6.作成をクリック
LogicApps の新規作成
Blank Logic App をクリック
Flow の新規作成
1.マイフローをクリック2.一から作成をクリック3.多数のコネクタやトリガーを検索するをクリック
この状態になれば作成可能
Request(要求)トリガを選択する
LogicApps
Flow
Flow の場合はトリガとアクションがなければ保存できないので、仮のアクションを選択し保存を行う必要があります
保存するとURL が生成されます
この URL をLINE 側に設定します
LINE Developer 上で Webhook を有効にします
利用するを選択して更新をクリックします
「自動応答メッセージ」「友達追加あいさつ」は「利用しない」に設定します
LINE Developer 上で Webhook URL を設定します
URL に LogicFlow で生成された URL を貼り付け更新をクリックします(HTTPS:// は不要な点に注意!)
Webhook URL を設定後に接続確認をクリック
正しく設定すれば LogicFlow が呼び出されます
LINE DEVELOPER 側ではエラー表示となるが現時点では問題なし
テキストメッセージのやりとり
全体の流れ
(1) LINE より呼び出し
(2) LINE へテキストメッセージを送信
Webhook オブジェクトのスキーマを設定します
補足資料のスキーマ定義を貼り付けでOKです
HTTP アクションの設定(1)
POST https://api.line.me/v2/bot/message/reply
HTTP アクションの設定(2)
Content-Type:application/json
Authorization:Bearer {long life token}
Bearer の後に半角スペース、その後にトークンを張り付けます
HTTP アクションの設定(3)
ReplyToken を指定すると自動で ForEach が設定される
HTTP アクションの設定(4)
items('Apply_to_each')?['message']?['text']
設定時は function 表示されていますが保存後に再表示を行うとこのように変わります
現在のダイアログでは孫要素(A.B.C・・・のC以降)を扱えないための挙動です
このようにオウム返しできていれば成功です
実行確認
それ以外のやりとり
その他に送信できる種類
• スタンプ(独自スタンプは不可)• 画像(jpg)• 動画(mp4 プレビューイメージは jpg)• 音声(m4a形式)• 位置情報• イメージマップ• テンプレート(ボタン/確認/カルーセル)
全体の流れ
単体のやり取りは同じ流れになります
HTTP アクションで戻す内容が異なります
スタンプ
https://developers.line.me/media/messaging-api/sticker_list.pdf
利用可能なスタンプ一覧
{
"type": "sticker",
"packageId": "2",
"stickerId": "145"
}
画像
{
"type": "image",
"originalContentUrl": "",
"previewImageUrl": ""
}
originalContentUrl HTTPS で指定
JPEG最大画像サイズ:1024×1024
最大ファイルサイズ:1MB
previewImageUrl HTTPS で指定
JPEG最大画像サイズ:240×240
最大ファイルサイズ:1MB
originalContentUrl
previewImageUrl
画像サイズを指定できるのでサムネイル作らなくとも対応は可能です
Cognitive Services で提供されているComputeVision API でサムネイル作成も可能です
動画 {
"type": "video",
"originalContentUrl": "",
"previewImageUrl": ""
}
指定した動画 URL が誤っていた場合このように再生できないのですがTL上ではわからない状態になります
音声 {
"type": "audio",
"originalContentUrl": "",
"duration": 10000
}
位置情報 {
"type": "location",
"title": "",
"address": "",
"latitude": 0,
"longitude": 0
}
PC 版の場合はクリックするとブラウザで GoogleMap で表示スマホ版は内部ビューワーで GoogleMap を表示します
イメージマップ{
"type": "imagemap",
"baseUrl": "","altText": "クラウディアさんとななみ",
"baseSize": {
"height": 1040,
"width": 1040
},
"actions": [
{
"type": "message","text": "クラウディアさんお疲れ様でした!",
"area": {
"x": 183,
"y": 5,
"width": 220,
"height": 540
}
}
]
} スマホ版のみで利用できます
"actions": [
{
"type": "message","text": "クラウディアさんお疲れ様でした!",
"area": {
"x": 183,
"y": 5,
"width": 220,
"height": 540
}
}
]
画像の指定した領域をクリックするとActions で定義した動作を実行します
イメージマップのアクション
{
"type":"uri",
"linkUri":"https://example.com/",
"area":{
"x":0,
"y":0,
"width":520,
"height":1040
}
}
{
"type":"message",
"text":"hello",
"area":{
"x":520,
"y":0,
"width":520,
"height":1040
}
}
Uri アクションは指定したアドレスにリダイレクトします
Message アクションはメッセージを代理で入力したかのように動作します(タップするとすぐにWebhookで呼び出される)
イメージマップの画像サイズ{
"type": "imagemap",
"baseUrl": "","altText": "クラウディアさんとななみ",
"baseSize": {
"height": 520,
"width": 1040
},
画像は
[ baseUrl ] / [ デバイスから要求する画像サイズ ]でアクセスする仕様なので、サイズにあった画像をあらかじめ同一ディレクトリに用意しておくのがよいです
利用される画像サイズ 240px / 300px / 460px / 700px / 1040px
テンプレート(確認){
"type": "template","altText": "確認なのです!",
"template": {
"type": "confirm","text": "出撃しますか?",
"actions": [
{
"type": "message","label": "電の本気を見るのです!",
"text": "第一艦隊、第一水雷戦隊。出撃です!"
},
{
"type": "message","label": "艦隊がお戻りみたいです。",
"text": "ちょっと直してくるのです。"
}
]
}
}
"type": "message","label": "電の本気を見るのです!",
"text": "第一艦隊、第一水雷戦隊。出撃です!"
"type": "message","label": "艦隊がお戻りみたいです。",
"text": "ちょっと直してくるのです。"
スマホの画面サイズによりlabel の文字は欠けることが多いので注意が必要です
テンプレート(ボタン){
"type": "template",“altText”: “テンプレートのサンプル",
"template": {
"type": "buttons",
"thumbnailImageUrl": "
https://lfjabot.blob.core.windows.net/images
/logicflowja_logo.png",
"title": "Menu","text": "LogicFlow といえば",
"actions": [
{"type": "postback",
"label": "LogicApps",
"data": "action=buy&itemid=123" },
{"type": "postback",
"label": "MS Flow",
"data": "action=add&itemid=123" },
{"type": "uri",
"label": "WF",
"uri": "http://blogahf.blogspot.jp/" }
]
}
}
Type:button で postback した場合はTL にメッセージが表示されないままWebhook が呼び出されます
Postback.data で指定した値が連携されます
テンプレート(カルーセル){"type": "template","altText": "カルーセルのサンプルです",
"template": {"type": "carousel",
"columns": [
{"thumbnailImageUrl":
"https://lfjabot.blob.core.windows.net/images/rabbit.jpg","title": "メニュー1",
"text": "はむはむむしゃむしゃ",
"actions": [
{"type": "postback","label": "飼う",
"data": "action=keep&itemid=1" },
{"type": "postback","label": "野に放つ",
"data": "action=remove&itemid=1" }
]
},{ (別カラムの設定)}
]
}
}
{"thumbnailImageUrl":
"https://lfjabot.blob.core.windows.net/images/rabbit.J
PG","title": "メニュー1",
"text": “description",
"actions": [
{"type": "postback","label": "飼う",
"data": "action=keep&itemid=1" },
{"type": "postback","label": "野に放つ",
"data": "action=remove&itemid=1" }
]
},
カルーセルのカラムは 10 個までカラムのアクションは 3 個まで(すべてのカラムでアクション個数は統一)
テンプレート(画像カルーセル){
"type": "template","altText": "画像カルーセルのサンプル",
"template": {
"type": "image_carousel",
"columns": [
{ "imageUrl": "https://lfjabot.blob.core.windows.net/images/fox.jpg",
"action": { "type": "postback","label": "こんこん",
"data": "action=sings" }
},
{ "imageUrl":
"https://lfjabot.blob.core.windows.net/images/raccoon.jpg",
"action": { "type": "postback","label": "ぽんぽこぽん",
"data": "action=drum" }
}
]
}
}
{ "imageUrl":
"https://lfjabot.blob.core.windows.net/images
/fox.jpg",
"action": { "type": "postback","label": "こんこん",
"data": "action=sings" }
},
{ "imageUrl":
"https://lfjabot.blob.core.windows.net/images
/raccoon.jpg",
"action": { "type": "postback","label": "ぽんぽこぽん",
"data": "action=drum" }
}
選択肢がないだけでカルーセルとほぼ同じになります
コンテンツの取得
https://api.line.me/v2/bot/message/{messageId}/content
concat('https://api.line.me/v2/bot/message/’,
items('For_each')?['message']?['id’],
'/content')
取得用の URI 作成
シナリオのある BOT 対応
必要な対応
1. メッセージ種類による処理分岐2. やりとりの状態管理
(誰からか、何が送られたか等)
最低限として上記への対応が必要になります。
今回のハンズオンでは「メッセージ種類による処理分岐」への対応を行い「やりとりの状態管理」は簡易な方法を採用します。
今回作ろうとしているもの
質問1
質問2-A
質問3-A 質問3-B
質問2-B
質問3-C 質問3-D
YesNo クイズ
シナリオのサンプル
ID メッセージ 選択肢1 移動先1 選択肢2 移動先2
1最新の技術を使うのが好き はい 2 いいえ 3
2プログラムを書いてなんぼという気持ちがある はい 10 いいえ 11
3専門職じゃなくても開発したい はい 12 いいえ 13
10C# がいいんでないかな
11LogicFlow でつなげる開発たーのしー
12VBA・・おっと誰か来たようだ
13独立すればいいんでね?
設問は2問と非常に簡単な形です
実行結果のサンプル
正しく状態に沿った動きをしているように見えます
実際には選択肢に含ませた情報で次に出す内容を特定しています
言い換えると状態を持っているのをLINE の TL 側とすることでLogicFlow の処理を軽減させます
メッセージ種類による処理分岐
イベント種類
message
follow
unfollow
join
leave
beacon
postback
メッセージ種類
text
image
video
audio
file
location
sticker
メッセージだけでも 7 種類について考慮が必要です
まともにやると条件判断を繰り返し行うので非常に読みにくい LogicFlow となってしまいます
今回はプログラム的な発想で対処します
本来は LogicFlow ではなく外部処理で行うのが適している箇所です
indexof('messagefollowunfollowjoinleavebeaconpostback’,
items('For_each')?['type'])
indexof(
'messagefollowunfollowjoinleavebeaconpostback’,
items('For_each')?['type'])
ある文字列の中から指定した文字列が何桁目から始まっているかを取得する関数
LINE から渡されるイベント種別を結合した文字列
実際に LINE から渡されるイベント種別
Indexof による取得結果
イベント種類
message
follow
unfollow
join
leave
beacon
postback
この結果をもとに「スイッチ」で横に分岐します
0
7
13
21
25
30
36
今回のハンズオンでは message と postback のみ利用しますので他イベントに対応できる必要はありません
Indexof による取得結果(2)
メッセージ種類
text
image
video
audio
file
location
sticker
メッセージ種類も同様の方法で対応可能です
0
4
9
14
19
23
31
今回のハンズオンでは text のみ利用しますので他メッセージに対応できる必要はありません
LogicFlow 完成イメージ
非常に横に長い LogicFlow となります
Bearer トークンを変数に設定
利用する機会が多いので変数が便利です
indexof('messagepostback’,
items('For_each')?['type'])
items(‘For_each')?['message']?[‘type']
何かテキストを送信した場合に占いを開始します
replace(
string(items('For_each')?['postback']?['data’]),
‘itemid=‘,
'')
一つにまとめても大丈夫です
Itemid の値で処理を分けてください
シナリオでのID値
まとめ
ハンズオンまとめ
• LogicFlow だけでも簡単な BOT は作成可能です
•ただし複雑な処理には向いていませんその場合は処理を外出し、LogicFlow から呼ぶのがアーキテクチャ的に素直です
• LogicFlow は流れの制御を行うのが得意ですおおまかな流れを LogicFlow で、細かい処理を Function App や API Apps で行うのがよいです
•すべてを LogicFlow で処理するのは自己満足にしかなりません
Happy LogicFlow Develop!
補足
{"type": "object", "properties": { "events": { "type": "array",
"items": { "type": "object",
"properties": { "replyToken": { "type": "string" },
"type": { "type": "string" },
"timestamp": { "type": "number" },
"source": { "type": "object",
"properties": { "type": { "type": "string" },
"userId": { "type": "string" },
"groupId": { "type": "string" }
}
}
},
"message": {"type": "object",
"properties": { "id": { "type": "string" },
"type": { "type": "string" },
"text": { "type": "string" },
"fileName": { "type": "string" },
"fileSize": { "type": "number" },
"title": { "type": "string" },
"address": { "type": "string" },
"latitude": { "type": "number" },
"longitude": { "type": "number" },
"packageId": { "type": "string" },
"stickerId": { "type": "string" }
}
},
"postback": {"type": "object",
"properties": { "data": { "type": "string" } }
}
}
} }
}
Webhook オブジェクトスキーマ定義(Beacon未定義)
https://goo.gl/pxwBH9
プラン APIリクエスト回数の制限 メッセージ受信者数の制限
Developer Trial 1,000/分 20,000/分
その他のプラン 10,000/分 200,000/分
ステータスコード 説明
200 OK リクエストが成功しました。
400 Bad Request リクエストに問題があります。
401 Unauthorized 有効なチャネルアクセストークンが指定されていません。
403 Forbidden APIを使用する権限がありません。ご契約中のプランやアカウントに付与されている権限を確認してください。
429 Too Many Requests APIコールのレート制限を超過しました。
500 Internal Server Error 内部サーバーのエラーです。
メッセージ 説明
The request body has X error(s) リクエストボディのJSONデータにエラーがありました。Xの部分にエラーの数が表示されます。詳細はdetails[].messageおよびdetails[].propertyフィールドに含まれます。
Invalid reply token 応答メッセージで使用された応答トークンが無効です。
The property, XXX, in the request body is
invalid (line: XXX, column: XXX)
リクエストボディに無効なプロパティが指定されていました。XXX
の部分に具体的な行と列が表示されます。
The request body could not be parsed
as JSON (line: XXX, column: XXX)
リクエストボディのJSONデータを解析できませんでした。XXXの部分に具体的な行と列が表示されます。
The content type, XXX, is not supported APIでサポートされていないコンテンツタイプがリクエストされました。
Authentication failed due to the
following reason: XXX
APIが呼び出されたときに認証に失敗しました。XXXの部分に理由が表示されます。
Access to this API is not available for
your account
実行権限がないAPIを呼び出しました。
Failed to send messages メッセージの送信に失敗しました。指定したユーザーIDが存在しない場合などにこのエラーが発生します。