Edited at

Kotlin + Googleアシスタントでアクションのバックエンドを作ってみる


はじめに

2019/01/16にActions on Google(AoG)Client LibraryのJava/Kotlin版が発表されました

公式では、Kotlin + Google App Engine上のJavaサーブレットで構築する方法が紹介されています。

KotlinにはKtorというWebフレームワークがあります。

今回はフルKotlinでGoogleアシスタントのアクションを構築する方法を紹介します。


使う技術

次の表に、各言語で使う技術構成をまとめました。

GoogleアシスタントのバックエンドはNode.js + Cloud Functions For Firebaseの構成で作られることが多いです。

今回は、Kotlin + Ktor + Google App Engine(GAE)で作ります!



Ktor, GAEは環境構築の一番最初の部分から解説していきます。

言語
フレームワーク
実行環境

Kotlin
Ktor
PaaS: Google App Engine

Node.js
(Express)
FaaS: Cloud Functions For Firebase


Ktorについて

Ktor とは、Kotlinの軽量で簡単に使えるWebフレームワークです。

おなじみJetBrains社が開発をしており、安心感があります。

去年(2018)の11月にv1.0がリリースされており、Kotlinサーバサイドでの利用が期待が高まっています。

- Ktor 1.0 Released: A Connected Applications Framework by JetBrains | Kotlin Blog


構築手順


Actions on GoogleプロジェクトとDialogflowエージェントの作成

こちらは従来どおりの作り方と変わりありません。


開発環境の準備(テンプレートを利用)

↑のGihtubリポジトリにテンプレートを作成しておきました。環境構築の際にはぜひお使いください!

ダウンロード後、Intellij IDEで開いてください。


AoG Java/Kotlinクライアントライブラリの使い方

次に本題のAoG Java/Kotlinクライアントライブラリの使い方を解説していきます。

AoG Java/Kotlinクライアントライブラリは、

build.gradle に↓を指定することでダウンロードしています。

compile "com.google.actions:actions-on-google:1.0.0"


IntentHandler作成

Dialogflowからのリクエストを受け取り処理するためのIntentHandlerを作成します。

新規にConversationComponentsApp.ktを作成してください。

IntentHandlerの作成ポイントは



  1. DialogflowAppを継承させる。


  2. ForIntentアノテーションを使ってDialogflowで定義したIntent名と処理を紐付ける。


  3. ResponseBuilderを使ってレスポンスを組み立てる。

コードはこんな感じです。


class ConversationComponentsApp : DialogflowApp() {

@ForIntent("Default Welcome Intent")
fun welcome(request: ActionRequest): ActionResponse {
val responseBuilder = getResponseBuilder(request)
responseBuilder
.add(SimpleResponse()
.setDisplayText("純情Action!")
.setTextToSpeech("純情Action!Action!"))
return responseBuilder.build()
}

@ForIntent("Good Bye")
fun goodBye(request: ActionRequest): ActionResponse {
val responseBuilder = getResponseBuilder(request)
responseBuilder
.add("会話を終了します。さようなら")
.endConversation() // 会話を終了させる。 Node.js版でのconv.close
return responseBuilder.build()
}
}

例ではSimpleResponseを使っていますが、他にBasicCardCarouselTableなどのサンプルを公式がGithubあげてくれています。

気になる方は、こちら↓も見てみるといいでしょう!


POSTリクエストのエンドポイント用意

続いて、作ったIntentHandlerにDialogflowからのデータを渡せるようにしましょう。

DialogflowからはPOSTリクエストでJSONが送られてくるので、次のコードの通りに / をルートパスとしてJSONを受け取ります。

call.receiveText()でJSONデータを受け取り、

先程作ったした ConversationComponentsApp#handleRequestにヘッダー情報と一緒に渡します。

これによりIntent名に対応してレスポンスが返されます。

最後に、call.respond を使ってDialogflow側に返却してあげます。

fun Application.module(testing: Boolean = false) {

val actionsApp= ConversationComponentsApp()
routing {
post("/"){
// body取得
val jsonBody: String = call.receiveText()
// header取得
val headerMap = getHeaderMap(call.request)
// IntentHandlerにbody,header情報を渡す
val jsonResponse = actionsApp.handleRequest(jsonBody, headerMap).get()
call.respond(jsonResponse)
}
}
}

// ヘッダー情報をHashMapにKey-Valueでつっこんであげる。
fun getHeaderMap(request: ApplicationRequest): Map<String, String>{
val headers= request.headers
val headerMap = HashMap<String, String>()
headers.forEach{ k, v -> headerMap[k] = v.toString() }
return headerMap
}


GAEへのデプロイ準備


ターミナル編

Google Cloud SDKをMacにインストールし、初期化まで完了させます。

初期化中にGoogle Cloud Platformプロジェクトを選択する必要があります。Actions on GoogleプロジェクトIDと同じものを選びましょう。

設定できたら、現在の設定に間違いないか確認しておくといいでしょう。

$ gcloud config list

[app]
promote_by_default = true
[core]
account = <AoGプロジェクト作成時と同じGoogleアカウントのメールアドレス>
disable_usage_reporting = False
project = <Actions on GoogleのプロジェクトID(GCP Project id)>

GAEのJavaプラグインをインストールします。

$ gcloud components install app-engine-java

$ gcloud components update


Intellij IDE編

GAE関連の設定を解説します。

build.gradleに↓を記入しておくことで、GAE用のGradleタスクが活用できるようになります。

buildscript {

...
dependencies {
...
classpath "com.google.cloud.tools:appengine-gradle-plugin:1.3.4"
}
}

...
apply plugin: 'war'
...

dependencies {
...
providedCompile "com.google.appengine:appengine:1.9.60"
}

appengine {
// ご自身の環境に合わせて変更してください。
tools.cloudSdkHome="<google-cloud-sdkディレクトリへのパス>"
}

テンプレートコードのディレクトリ構成を整理しておきます。

ディレクトリツリー構造はこんな感じになっています。

...

.
└── main
├── kotlin
│   ├── Application.kt
│   └── ConversationComponentsApp.kt
├── resources
│   ├── application.conf
│   └── logback.xml
└── webapp
└── WEB-INF
├── appengine-web.xml
├── logging.properties
└── web.xml

kotlinファイルは、src/main/kotlinに、プロジェクトルートに存在するktorの設定ファイルがsrc/main/resourcesにあります。

src/main/webappというディレクトリがあるのですが、詳細については↓を参考にしてみてください


GAEへデプロイ! と動作確認!

ここまでの設定が完了したら、

./gradlew appengineDeployかIDEのGradleタスクからappengineDeployを実行してください。

成功すると、https://<gcp-project-id>.appspot.comのURLがコンソールに表示されるので、

こちらをメモっておき、DialogflowのFullfillmentに設定すれば完了です!

...

Deployed service [default] to [https://<gcp-project-id>.appspot.com]
...