LoginSignup
4
2

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-01-27

はじめに

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

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

KotlinにはKtorというWebフレームワークがあります。
今回はフルKotlinでGoogleアシスタントのアクションを構築する方法を紹介します。

使う技術

次の表に、各言語で使う技術構成をまとめました。
GoogleアシスタントのバックエンドはNode.js + Cloud Functions For Firebaseの構成で作られることが多いです。
今回は、Kotlin + Ktor + Google App Engine(GAE)で作ります! :muscle:
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というディレクトリがあるのですが、詳細については↓を参考にしてみてください:bow:

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]
...
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2