JavaアプリケーションにDialogflowを組み込む話

#はじめに
Dialogflowを組み込んだJavaアプリケーションを作成したので、
その手順を備忘録も兼ねて簡単にまとめました。
実際に使用する場合は、ここに記載したもの＋Swing等を書くことになると思います。


##参考資料
* Dialogflow
 * [Dialogflow 公式ドキュメント](https://cloud.google.com/dialogflow/docs "https://cloud.google.com/dialogflow/docs")

* Maven
 * [Dialogflow 公式ドキュメント](https://cloud.google.com/dialogflow/docs "https://cloud.google.com/dialogflow/docs")
 * [【超初心者向け】Maven超入門](https://qiita.com/tarosa0001/items/e5667cfa857529900216 'https://qiita.com/tarosa0001/items/e5667cfa857529900216')
 * [Mavenで実行可能jarをビルドする方法](https://qiita.com/tarosa0001/items/e019ec4daaaf54684c53 'https://qiita.com/tarosa0001/items/e019ec4daaaf54684c53')
 * [MavenプロジェクトのgroupIdとartifactId](https://code-macchiato.com/tips/maven-groupid-artifactid 'https://code-macchiato.com/tips/maven-groupid-artifactid')

##開発環境
* Windows 10 Home
* Java 1.8
* Maven 3.6.2
* Eclipse IDE (2020-03)  
(Mavenプラグイン導入済み、プライベートJRE設定済み)

##必要な物
* Google アカウント

#Dialogflowとは
>Dialogflow は、会話型のユーザー インターフェースの設計と、モバイルアプリ、ウェブ アプリケーション、デバイス、ボット、対話型の音声応答システムなどへの統合を容易にする自然言語理解プラットフォームです。
引用元：[公式ドキュメント](https://cloud.google.com/dialogflow/docs "https://cloud.google.com/dialogflow/docs")

Google Homeの自然言語解析を行う際に使われているもので、AWSの[Amazon Lex](https://aws.amazon.com/jp/lex/ 'https://aws.amazon.com/jp/lex/')などが類似システムとして挙げられます。

---

#1. GCPプロジェクト・Dialogflow対話モデルの作成

##1.1. Google Cloud Platform(GCP)プロジェクトの作成
Dialogflowを接続するGCPプロジェクトを作成します。

* [Google Cloud Platform](https://console.cloud.google.com/ 'https://console.cloud.google.com/')を開く。  
（必要に応じて利用規約に同意する。GCPの無料トライアルは不要。）
* `プロジェクトの選択`->`新しいプロジェクト`の順にクリックする。
* `プロジェクト名`を入力し、`作成`をクリックする。
![CreateProject.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605888/a9ec3440-1ea6-6b7b-3293-cc43f6110679.gif)


##1.2. Dialogflow対話モデルの作成
* [Dialogflow Console](https://dialogflow.cloud.google.com/ 'https://dialogflow.cloud.google.com/')を開く。（必要に応じて初期設定をする）
* `Create Agent`をクリックする。
* `DEFAULT LANGUAGE`に`Japanese - ja`を、`GOOGLE PROJECT`に`作成したプロジェクト`を選択し、`CREATE`を押す。
![CreateAgent.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605888/fe286ef2-e504-b825-5920-90035ab6622e.gif)


ここで、Dialogflowの対話モデルを作成します。
対話モデルの作成に関する情報は、[公式ドキュメント](https://cloud.google.com/dialogflow/docs/quick/build-agent 'https://cloud.google.com/dialogflow/docs/quick/build-agent')を始めとする
多くの情報がネット上にあるので省略します。

今回は「テスト」という発話に対して「Hello Dialogflow!」とレスポンスを返す
テスト用の対話モデルを作成しました。

* 画面右部分で対話が行えることを確認する。
![CheckAgent.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605888/bba29418-a647-e07f-9ffc-d41ba683e14f.gif)


##1.3. 認証用jsonファイルのダウンロード

* 再び、[Google Cloud Platform](https://console.cloud.google.com/ 'https://console.cloud.google.com/')を開く。
* 画面上部より`Dialogflow対話モデルが接続されているプロジェクト`を選択し、`IAMと管理`から`サービスアカウント`を開く。
* `サービスアカウントを作成`をクリックし、`サービスアカウント名`を入力する。
* `ロールを選択`より、`Dialogflow`->`Dialogflow API クライアント`を選択、続行する。
* `キーを作成`をクリックし、`JSON`を選択して`作成`をクリックする。
* 認証キーがかかれたJSONファイルを、デスクトップなどの分かりやすいところにダウンロードする。
![CreateKey.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605888/5fd9ae4b-df34-5fe4-ead1-80c68b7b4e09.gif)


---

#2. JavaアプリケーションにDialogflowを組み込む
##2.1. mavenプロジェクトを作成
* Eclipseで`ファイル`->`新規`->`Mavenプロジェクト`の順にクリックし、mavenプロジェクトを作成する。
* `シンプルなプロジェクトの作成`にチェックを付け、次へ進む。
* 成果物の`グループId`と`アーティファクトId`を入力し、完了を押す。
 * グループIdは、ドメインをひっくり返せば良い。Javaのパッケージ名のような感じ。
 * アーティファクトIdは、完成時のアプリ名を入れる。

##2.2. パッケージ・クラスファイルの作成
作成したMavenプロジェクト内に、パッケージとクラスファイルを作成します。

* `src/main/java`を右クリックし、`新規`->`パッケージ`の順に選択する。
* `名前`にパッケージ名を入力し、`完了`をクリックする。
* ↑ここで`作成したパッケージ`を右クリックし、`新規`->`クラス`の順に選択する。
* `名前`にクラス名を入力し、`public static void main(String[] args)`にチェックを入れ、`完了`をクリックする。

これで、Mavenプロジェクト内にパッケージと、メインメソッド入りのクラスが作成されました。

##2.3. pom.xmlの編集
作成したMavenプロジェクト内のpom.xmlというファイルを、次のように書き換えます。

```xml:pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">

  <!--groupIdとartifactIdの...は、Mavenプロジェクト作成時に入力したものと置き換えてください。-->
  <modelVersion>4.0.0</modelVersion>
  <groupId>...</groupId>
  <artifactId>...</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.2</version>
        <configuration>
          <source>${java.version}</source>
          <target>${java.version}</target>
        </configuration>
      </plugin>
      
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.0.0</version>
        <configuration>
          <finalName>...</finalName>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <!--mainClassの...は、パッケージ名.クラス名です。-->
              <mainClass>...</mainClass>
            </manifest>
          </archive>
        </configuration>
        <executions>
          <execution>
            <id>mark-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.google.cloud</groupId>
        <artifactId>libraries-bom</artifactId>
        <version>5.1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  
  <dependencies>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-dialogflow</artifactId>
    </dependency>
  </dependencies>
</project>
```

入力が終わったら保存し、pom.xmlを適用します。

* `pom.xml`を右クリックし、`Maven`->`プロジェクトの更新`の順に選択する。
* 使用可能なMavenコードベースから`作成したMavenプロジェクト`を選択し、`OK`で続行する。

![UpdateMavenProject.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605888/aa38f4a3-7a29-1666-5276-650e4ba6b333.gif)


##2.4. Javaファイルの編集
先に作成したメインメソッド入りのクラスファイルを、次のように書き換えます。

```java:Main.java
//package名は、適宜おき換えてください。
package tokyo.penguin_syan.dialogflowTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import com.google.api.client.util.Maps;
import com.google.cloud.dialogflow.v2.DetectIntentResponse;
import com.google.cloud.dialogflow.v2.QueryInput;
import com.google.cloud.dialogflow.v2.QueryResult;
import com.google.cloud.dialogflow.v2.SessionName;
import com.google.cloud.dialogflow.v2.SessionsClient;
import com.google.cloud.dialogflow.v2.TextInput;
import com.google.cloud.dialogflow.v2.TextInput.Builder;

public class Main {

  public static void main(String[] args) {
    Scanner userInput = new Scanner(System.in);
    List<String> text = new ArrayList<String>();
    String input;
    Map<String, QueryResult> ret;
    //sessionIdはテスト用の適当な数値です。
    int sessionId = 123456789;

    do {
      System.out.print("\nYou  : ");
      input = userInput.next();
      if(input.equals("exit"))
        System.exit(0);

      text.add(input);
      ret = new HashMap<>();

      try {
        //引数内の---は、ダウンロードしたjsonファイルに記載されたproject_idに置き換えてください。
        ret.putAll(detectIntentTexts(---,
            text, String.valueOf(sessionId++), "ja"));
        System.out.format("Agent: %s\n", ret.get(input).getFulfillmentText());
      } catch (Exception e) {
        e.printStackTrace();
      }

    }while(true);
  }

  public static Map<String, QueryResult> detectIntentTexts(
    String projectId,
    List<String> texts,
    String sessionId,
    String languageCode) throws Exception {
      Map<String, QueryResult> queryResults = Maps.newHashMap();
      try (SessionsClient sessionsClient = SessionsClient.create()) {
        SessionName session = SessionName.of(projectId, sessionId);
        for (String text : texts) {
          Builder textInput = TextInput.newBuilder().setText(text).setLanguageCode(languageCode);
          QueryInput queryInput = QueryInput.newBuilder().setText(textInput).build();
          DetectIntentResponse response = sessionsClient.detectIntent(session, queryInput);
          QueryResult queryResult = response.getQueryResult();
          queryResults.put(text, queryResult);
        }
      }
    return queryResults;
  }

}
```

##2.5. コンパイル
* パッケージ・エクスプローラー内の`Mavenプロジェクト`を右クリックする。
* `実行`->`Maven install`の順に選択する。
* コンソールに`BUILD SUCCESS`と表示されるまで待つ。

---

#3. 実行
##3.1. 実行用batファイルの作成
実行用のbatファイルを作成します。

```dialogflowTest_java.bat
@echo off

rem ---にはダウンロードした認証用jsonファイル名前を入れます。
set GOOGLE_APPLICATION_CREDENTIALS=---.json
java -jar test-jar-with-dependencies.jar
```

実行用にディレクトリ構造を整理します。

* `test-jar-with-dependencies.jar`、`ダウンロードしたjsonファイル`、`作成したbatファイル`をすべて同じフォルダ内に配置する。  
（test-jar-with-dependencies.jarは，Mavenプロジェクト内のtargetフォルダ内にあります）

```:ディレクトリ構造
.
├ test-jar-with-dependencies.jar
├ ---.json
└ dialogflowTest_java.bat
```

##3.2. 実行
実行するためには、作成したbatファイルを起動します。
<img width="734" alt="run.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605888/42f55d18-0c9c-520d-1184-dd0b5976bd7c.gif">

無事実行できました。
٩(๑•ㅂ•)۶うぇーい