Androidアプリから自然言語処理（DialogFlow）

## はじめに
以前、AndroidアプリからDialogFlowを利用して自然言語処理機能を実装しました。
DialogFlowを実装するためのSDKがAndroid用にはなく、結構嵌ったのでメモとして投稿しました。
少しでも参考になれば幸いです。

## 全体構成
AndroidアプリからDialogFlowを呼び出すのために、Cloud functionを利用しています。
Cloud functionを挟むことにより、Androidアプリ＋DialogFlowとの認証を簡単にしています。

![dialogflow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667320/797ef781-b303-6248-2ef0-9fa264023bbf.png)

## 事前準備
- AndroidアプリからCloud functions for Firebaseを利用可能にしておく
- DialogFlowを利用可能にしておく
- DialogFlowのサービスアカウントを発行する

## CloudFunctions
以下、紹介する実装のファイル構成です。

```
 ├── functions
     ├── index.js              // cloudFunctions実装（アプリから呼ぶ関数定義）
     ├── dialogflow-v2.js      // cloudFunctions実装（DialogFlow呼び出し）
     ├── serviceaccount.json　 // サービスアカウント
```

### CloudFunctions実装（index.js）
アプリから呼ぶ関数の定義です。

```javascript:index.js
const dialogflowv2Module = require('./dialogflow-v2');

exports.callDetectIntent = functions.https.onCall((data, context) => {
  let input = data.input;
  let result = dialogflowv2Module.detectIntentQueryText(input)
      .then(r => {
        return JSON.stringify(r);
      })
      .catch(err => {
        throw new functions.https.HttpsError('callDetectIntent',err);
      });
  return result;
});
```

### CloudFunctions実装（dialogflow-v2.js）
サービスアカウントを使って、DialogFlowのAPIの呼び出しています。

```javascript:dialogflow-v2.js
"use strict";

const dialogflow = require('dialogflow');
const serviceAccount = require('./serviceaccount.json');

exports.detectIntentQueryText = async function(query) {
    return await detectIntent(query);
}

async function detectIntent(query) {

    // Define config
    const languageCode = "ja";
    const sessionId = "00000000";

    // Instantiate a DialogFlow client.
    const sessionClient = new dialogflow.SessionsClient({
        credentials: {
            private_key: serviceAccount.private_key,
            client_email: serviceAccount.client_email
        }
    });

    // Define session path
    const sessionPath = sessionClient.sessionPath(serviceAccount.project_id, sessionId);

    // The text query request.
    const request = {
        session: sessionPath,
        queryInput: {
            text: {
                text: query,
                languageCode: languageCode,
            },
        },
    };

    // Send request and log result
    const result = await sessionClient
        .detectIntent(request)
        .then(responses => {
            return responses[0];
        })
        .catch(err => {
            console.log(err);
            throw new functions.https.HttpsError('detectIntentSync',err);
        });

    return result;
};
```

## Androidアプリ実装
Androidアプリ実装です。Cloud Functionを呼び出しています。

```kotlin:DialogFlow.kt
    private lateinit var functions: FirebaseFunctions

    private fun callDetectIntent(text: String): Task<String> {
        val data = hashMapOf(
            "input" to text
        )

        return functions
            .getHttpsCallable("callDetectIntent")
            .call(data)
            .continueWith { task ->
                val result = task.result?.data as String
                result
            }
    }
```


### 参考文献

https://github.com/firebase/quickstart-android/blob/8262596a009b50b6c99191001f7e5470391bcc4a/functions/app/src/main/java/com/google/samples/quickstart/functions/kotlin/MainActivity.kt#L78-L95