アンドロイドスマホに搭載のGoogleAssistantもしくはGoogleHome系のアプリを作りました。
##実際の図
GoogleAssistantで"アイで"と発話すると"hello"と返し、Line側には"アイで"がPUSH通知されます。
##そもそも
GoogleAssistant→DialogFlow→LineはIntegrationsで設定すればすぐできますが、
テキストを返すことはできません。
またIntegrationsの方法は自分のLINEへはPUSH通知できますが、特定の人へPUSH通知はできません。
基本、google homeで子供の宿題管理をするの実装手順にてできました。うまくいかなかった箇所を本記事に加えてます。
##フロー図
google homeで子供の宿題管理をするからお借りして一部付け加えてます。
##DialogFlow
テストでIntentのパラメータを$anyにしてます。
これで”アイで”と発話すればこのIntentが起動します。
##Lambda
なぜLambdaを経由しているのかというと、GASでデプロイしたエンドポイントは、302リダイレクトをしてしまい、DialogflowのWebhookとして使えなかったからです。
#一番のハマりポイント
google homeで子供の宿題管理をする通り実行するとLambda関数にて下記エラーが出ます。
該当箇所↓
body = json.dumps(json.loads(event["body"])).encode("utf-8")
ん?event["body"]ってなに?
jsonデータ見ても”request”なんだけど…
色々調べてみると下記に書いてありました。
・API Gatewayの「Lambda プロキシ統合の使用」オプションより
結論から言うと、API Gatewayにてプロキシ統合の使用をチェックすればOKです。
試しにPOSTしてみたところ、Lambdaのeventには以下の値が設定されていました。
{
resource: '/mook',
path: '/mook',
httpMethod: 'POST',
headers: { Accept: ' application/json' },
queryStringParameters: { param1: 'value1' },
pathParameters: null,
stageVariables: null,
requestContext: {
accountId: 'xxxxxxxxxxxx',
resourceId: 'xxxxxx',
stage: 'test-invoke-stage',
requestId: 'test-invoke-request',
identity: {
cognitoIdentityPoolId: null,
accountId: 'xxxxxxxxxxxx',
cognitoIdentityId: null,
caller: 'xxxxxxxxxxxx',
apiKey: 'test-invoke-api-key',
sourceIp: 'test-invoke-source-ip',
cognitoAuthenticationType: null,
cognitoAuthenticationProvider: null,
userArn: 'arn:aws:iam::xxxxxxxxxxxx:root',
userAgent: 'Apache-HttpClient/4.5.x (Java/1.8.0_102)',
user: 'xxxxxxxxxxxx'
},
resourcePath: '/mook',
httpMethod: 'POST',
apiId: 'xxxxxxxxxx'
},
body: '{"Message": "Hello World"}'
}
API Gatewayがこれまで丸めていたHTTPヘッダーの情報をかなりきちんと得ることができます。
##Spreadsheet with GAS
下記GASのコードです
// プロパティ取得
const PROPERTIES = PropertiesService.getScriptProperties();
const LINE_CHANNEL_ACCESS_TOKEN = PROPERTIES.getProperty('LINE_CHANNEL_ACCESS_TOKEN');//GLG_test_bot
const USER_ID = PROPERTIES.getProperty('your_USER_ID');
function doPost(e) {
try {
let request = JSON.parse(e.postData.getDataAsString());
let any = request.queryResult.parameters.any
switch (any) {
case 'アイ':
let result = { "fulfillmentText": "hello" };//fulfillmentTextが大事!
pushMessage(any)
return returnAsJSON(result);
default:
return returnAsJSON({ "fulfillmentText": "ごめんね。よくわからなかったよ" });
}
} catch (ex) {
Logger.log("Error at doPost : %s", ex)
doc.getBody().appendParagraph(Logger.getLog())
return returnAsJSON({ "fulfillmentText": "エラーが発生しました。ログで確認できます" });
}
}
function returnAsJSON(obj) {
return ContentService.createTextOutput(JSON.stringify(obj)).setMimeType(ContentService.MimeType.JSON);
}
function pushMessage(message) {
let postData = {
"to": USER_ID,
"messages": [{
"type": "text",
"text": message,
}]
};
let url = "https://api.line.me/v2/bot/message/push";
let headers = {
"Content-Type": "application/json",
'Authorization': 'Bearer ' + LINE_CHANNEL_ACCESS_TOKEN,
};
let options = {
"method": "post",
"headers": headers,
"payload": JSON.stringify(postData)
};
let response = UrlFetchApp.fetch(url, options);
}
GASはウェブ公開にてデプロイし、そのあと出てくるURLをLambda側にコピペすればOK
※Lineについて別途設定が必要ですが、特別なことはやっていないので設定等は割愛。
LineBotでググればいくらで出てきます。
あとはDialogFlow側でテストし、AWSのcloudwatchのログなどを見ながら実装する。
##今後の展望
GASが使えるのでスプレッドシートと連携して色々できます。
##参考:
google homeで子供の宿題管理をする
初めてのサーバーレスアプリケーション開発 ~API GatewayからLambdaを呼び出す~ | Developers.IO