[Google Cloud Speech-to-Text API(V2)] Javaで認識精度を向上させるフレーズセットを作成・更新・削除する

Cloud Speech-to-Text API V2(Java)を使用して、
認識精度を向上させるフレーズセットを作成・更新・削除する方法についてご紹介します。

**フレーズセット(PhraseSet)とは**
フレーズセット(PhraseSet)はモデル適応機能を実現させるためのリソースの1つです。

モデル適応機能を使用すると提案される可能性がある他の候補よりも、
Speech-to-Textが特定の単語やフレーズをより高い頻度で認識するように設定できます。

フレーズセット(PhraseSet)リソースでは下記が設定できます。
|できること|概要|
|---|---|
|単語とフレーズの認識精度を向上させる|フレーズを指定することで、Speech-to-Text がその単語の並びを認識しやすくなります。<br>フレーズを提供することで、個々の単語を含むフレーズの一部を認識する確率も高まります。|
|[クラストークン](#クラストークン)を使用して認識精度を向上させる|通貨単位やカレンダー日付など、自然言語で発生する一般的なコンセプトを表します。<br>クラスにより、共通のコンセプトに対応する大規模な単語グループの音声文字変換の精度を向上できます。|

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Cloud Speech-to-Text API(V2)] JavaでSpeech-to-Text APIを使ってみる](https://qiita.com/doran/items/8e4ef896588229c4fed3)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[フレーズセットを作成](#1-フレーズセットを作成)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|
|2||[フレーズセットを更新](#2-フレーズセットを更新)|
||1|[スコープ](#21-スコープ)|
||2|[実行](#22-実行)|
||3|[レスポンスの内容](#23-レスポンスの内容)|
|3||[フレーズセットを削除](#3-フレーズセットを削除)|
||1|[スコープ](#31-スコープ)|
||2|[実行](#32-実行)|
||3|[レスポンスの内容](#33-レスポンスの内容)|

## 1. フレーズセットを作成
フレーズセットを作成します。

### 1.1. スコープ
OAuth2.0でこのAPIを実行するには、以下のスコープを指定してください。
サービスアカウントで実行する場合はスコープの指定は不要です。
```
https://www.googleapis.com/auth/cloud-platform
```

### 1.2. 実行
フレーズセットIDには、これから作成するフレーズセットのIDを設定します。
既に存在するIDを指定した場合はエラーになります。

```java
public static void main(String[] args) throws Exception{
    try(SpeechClient client = getSpeechClient()){
        Phrase.Builder phrase = Phrase.newBuilder();
        phrase.setValue("テスト");
        phrase.setBoost(20);
        
        PhraseSet.Builder phraseSet = PhraseSet.newBuilder();
        phraseSet.addPhrases(phrase.build());
        
        CreatePhraseSetRequest.Builder builder = CreatePhraseSetRequest.newBuilder();
        builder.setParent(String.format(
                "projects/%s/locations/%s", 
                "プロジェクトID","ロケーションID"));
        builder.setPhraseSetId("フレーズセットID");
        builder.setPhraseSet(phraseSet.build());
        builder.setValidateOnly(true);
        
        OperationFuture<PhraseSet,OperationMetadata> response = client.createPhraseSetAsync(builder.build());
        System.out.println(response.getName());

        PhraseSet set = response.get();
        System.out.println(set);
    }
}
```

#### 1.2.1. HTTPリクエスト
POST:　https:\//speech.googleapis.com/v2/projects/{プロジェクトID}/locations/{ロケーションID}/customClasses
が実行されます。

#### 1.2.2. クエリパラメータ
CreatePhraseSetRequest.Builderのsetメソッドにより、リクエストボディを追加できます。
build()メソッドでCreatePhraseSetRequestインスタンスを取得し、
createPhraseSetAsync()に渡します。

|メソッド|引数|説明|
|---|---|---|
|setParent|String|【必須】リソース名<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}"|
|setPhraseSetId|String|【必須】フレーズセットID|
|setPhraseSet|[PhraseSet](#phrasesetset)|【必須】フレーズセット|
|setValidateOnly|boolean|リクエストを検証してフレーズセットをプレビューするが実際には作成しないか|

#### 1.2.3. リクエストボディ
#### PhraseSet(Set)
|メソッド|引数|説明|
|---|---|---|
|addPhrasesList|[Phrase](#phraseset)|【必須】単語(フレーズ)または[クラストークン](#クラストークン)のリスト|
|setName|String|【更新時のみ必須】更新するフレーズセット名<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}/phraseSets/{フレーズセットID}"|
|setBoost|float|ヒントブースト(0〜20)<br>値が高いほど認識される確率が高くなる|
|setDisplayName|String|フレーズセットの名前(63文字まで)|

#### Phrase(Set)
|メソッド|引数|説明|
|---|---|---|
|setValue|String|【必須】単語(フレーズ)、[クラストークン](#クラストークン)|
|setBoost|float|【必須】ヒントブースト(0〜20)<br>値が高いほど認識される確率が高くなる|

#### State
|定義値|内容|
|---|---|
|STATE_UNSPECIFIED|未指定|
|ACTIVE|通常のアクティブな状態|
|DELETED|フレーズセットは削除された|

#### クラストークン
Speech-to-Text がサポートしているクラストークンです。
ここでは日本語のみ(ja-JP)の一覧を表示しています。

他の言語は[⧉サポートされるクラストークン(公式)](https://cloud.google.com/speech-to-text/docs/class-tokens?hl=ja)を参照ください。

|クラストークン|説明|音声のテキスト変換の例|
|---|---|---|
|$OOV_CLASS_AM_RADIO_FREQUENCY|AMラジオの周波数|「せんにひゃくにじゅー」 = 1220<br>「いちにーにーぜろ」 = 1220<br>「いちにーにーれー」 = 1220|
|$OOV_CLASS_DIGIT_SEQUENCE|数字の列(任意の長さ)|「に」 = 2<br>「いちにさん」 = 123<br>「にににににに」 = 222222|
|$OOV_CLASS_FM_RADIO_FREQUENCY|FMラジオの周波数|「きゅーじゅーてんご」 = 90.5<br>「ななじゅーななてんいち」 = 77.1<br>「ななじゅーしちてんいち」 = 77.1|
|$OOV_CLASS_TEMPERATURE|温度(度)|「いち」 = 1<br>「まいなすいち」 = -1<br>「ひくいち」 = -1|
|$ADDRESSNUM|住所の番地(対象の言語/地域で使用されるもの）|「いちのじゅーいちのにじゅーきゅー」 = 1-11-29<br>「にのじゅーごのにじゅーご」 = 2-15-25<br>「せんにひゃくはちじゅーごのさん」 = 1285-3|
|$FULLPHONENUM|電話番号(対象の言語/地域で使用されるもの)|「ぜろきゅーぜろいちにーさんよんごーろくななはち」 = 090-1234-5678<br>「ぜろいちにーさんいちにーさんよんごーろく」 = 0123-12-3456<br>「ぜろさんいちにーさんよんごーろくななはち」 = 03-1234-5678|
|$MONEY|金額(通貨単位名付き)|「きゅーせんえん」 = 9000円<br>「さんじゅーななどる」 = 37ドル<br>「いちまんはっせんはっぴゃくえん」 = 18800円|
|$OPERAND|数値(整数、分数、小数)|「れーてんいち」 = 0.1<br>「せんさんじゅーよんてんごーろくなな」 = 1034.567<br>「いちまん」= 1万|
|$PERCENT|パーセント値(パーセント記号付き)|「れーてんぜろぱーせんと」 = 0.0%<br>「れーてんれーぱーせんと」 = 0.0%<br>「さんじゅーよんてんごーろくぱーせんと」 = 34.56%|
|$POSTALCODE|郵便番号(対象の言語/地域で使用されるもの)|「にーさんぜろにーさんぜろぜろ」 = 230-2300<br>「きゅーぜろぜろのきゅーぜろぜろぜろ」 = 900-9000<br>「さんぜろぜろななぜろにーぜろ」 = 300-7020|
|$TIME|時刻または時間|「にじゅーじさんじっぷん」 = 20時30分<br>「ごじ」 = 5時<br>「さんじゅーにふんご」 = 32分後|

### 1.3. レスポンスの内容
#### OperationFuture\<PhraseSet,OperationMetadata\>
|メソッド|戻り値|説明|
|---|---|---|
|getName|String|サーバーによって割り当てられた名前<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}/phraseSets/{フレーズセットID}"|
|isDone|boolean|操作がまだ進行中であるか|
|getPollingFuture|RetryingFuture\<[OperationSnapshot](#operationsnapshot)\>|失敗またはキャンセルされた場合の操作のエラー結果|
|get|[PhraseSet](#phraseset)|フレーズセットデータ|
|getMetadata|ApiFuture\<[OperationMetadata](#operationmetadata)\>|API実行のメタデータ|

#### PhraseSet
|メソッド|戻り値|説明|
|---|---|---|
|getName|String|フレーズセットのリソース名<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}/phraseSets/{フレーズセットID}"|
|getUid|String|システムによって割り当てられたフレーズセットID|
|getPhrasesList|List\<[Phrase](#phrase)\>|単語とフレーズのリスト|
|getBoost|float|ヒントブースト(0〜20)|
|getDisplayName|String|フレーズセットの名前(63文字まで)
|getState|[State(enum)](#state)|フレーズセットのライフサイクル状態|
|getCreateTime|Timestamp|作成時間|
|getUpdateTime|Timestamp|このリソースが最後に変更された時刻|
|getDeleteTime|Timestamp|このリソースの削除が要求された時刻|
|getExpireTime|Timestamp|このリソースがパージされる時刻|
|getEtag|String|チェックサム値|
|getReconciling|boolean|フレーズセットが更新中か|
|getKmsKeyName|String|フレーズセットの暗号化に使用されるKMSキーの名前<br>形式："projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}"|
|getKmsKeyVersionName|String|フレーズセットの暗号化に使用されるKMSキーのバージョン名<br>形式："projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}/cryptoKeyVersions/{crypto_key_version}"|

#### Phrase
|メソッド|戻り値|説明|
|---|---|---|
|getValue|String|単語(フレーズ)、[クラストークン](#クラストークン)|
|getBoost|float|ヒントブースト(0〜20)<br>値が高いほど認識される確率が高くなる|

#### OperationMetadata
|メソッド|戻り値|説明|
|---|---|---|
|getCreateTime|Timestamp|オペレーションが作成された時刻|
|getUpdateTime|Timestamp|操作が最後に更新された時刻|
|getResource|String|操作のターゲットのリソースパス|
|getMethod|String|操作をトリガーしたメソッド|
|getCreatePhraseSetRequest|[CreatePhraseSetRequest](#createphrasesetrequest)|【生成の場合】オペレーションで生成したフレーズセット|
|updatePhraseSetRequest|[UpdatePhraseSetRequest](#updatephrasesetrequest)|【更新の場合】オペレーションで更新したフレーズセット|
|getDeletePhraseSetRequest|[DeletePhraseSetRequest](#deletephrasesetrequest)|【削除の場合】オペレーションで削除したフレーズセット|
|getProgressPercent|int|オペレーションの進捗率(0〜100)|

#### CreatePhraseSetRequest
|メソッド|戻り値|説明|
|---|---|---|
|getPhraseSet|[PhraseSet](#phraseset)|作成したフレーズセット|
|getValidateOnly|boolean|リクエストを検証してフレーズセットをプレビューするが実際には作成しないか|
|getPhraseSetId|String|フレーズセットID|
|getParent|String|フレーズセットが作成されるプロジェクトと場所<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}"|

#### OperationSnapshot
|メソッド|戻り値|説明|
|---|---|---|
|getErrorCode|StatusCode|エラーコード|
|getErrorMessage|String|開発者向けのエラーメッセージ|

## 2. フレーズセットを更新
指定したフレーズセットを更新します。

### 2.1. スコープ
OAuth2.0でこのAPIを実行するには、以下のスコープを指定してください。
サービスアカウントで実行する場合はスコープの指定は不要です。
```
https://www.googleapis.com/auth/cloud-platform
```

### 2.2. 実行

```java
public static void main(String[] args) throws Exception{
    try(SpeechClient client = getSpeechClient()){
        Phrase.Builder phrase = Phrase.newBuilder();
        phrase.setValue("テスト");
        phrase.setBoost(20);
        
        PhraseSet.Builder phraseSet = PhraseSet.newBuilder();
        phraseSet.setName(String.format(
                "projects/%s/locations/%s/phraseSets/%s", 
                "プロジェクトID","ロケーションID","フレーズセットID"));
        phraseSet.addPhrases(phrase.build());

        UpdatePhraseSetRequest.Builder builder = UpdatePhraseSetRequest.newBuilder();
        builder.setPhraseSet(phraseSet.build());
        
        OperationFuture<PhraseSet,OperationMetadata> response = client.updatePhraseSetAsync(builder.build());
        System.out.println(response.getName());
        
        PhraseSet set = response.get();
        System.out.println(set);
    }
}
```

#### 2.2.1. HTTPリクエスト
PATCH:　https:\//speech.googleapis.com/v2/projects/{プロジェクトID}/locations/{ロケーションID}/phraseSets/{フレーズセットID}
が実行されます。

#### 2.2.2. クエリパラメータ
クエリパラメータはありません。

#### 2.2.3. リクエストボディ
UpdatePhraseSetRequest.Builderのsetメソッドにより、リクエストボディを追加できます。
build()メソッドでUpdatePhraseSetRequestインスタンスを取得し、
updatePhraseSetAsync()に渡します。

|メソッド|引数|説明|
|---|---|---|
|setPhraseSet|[PhraseSet](#phrasesetset)|【必須】フレーズセット|
|setUpdateMask|FieldMask|更新するフィールド<br>未設定の場合は全てのフィールドが更新対象|
|setValidateOnly|boolean|リクエストを検証し、更新されたフレーズセットをプレビューするが実際には更新しないか|

### 2.3. レスポンスの内容
#### OperationFuture\<PhraseSet,OperationMetadata\>

[1.3. レスポンスの内容](#13-レスポンスの内容)と同じです。

#### UpdatePhraseSetRequest
|メソッド|戻り値|説明|
|---|---|---|
|getPhraseSet|[PhraseSet](#phraseset)|更新するフレーズセット|
|getUpdateMask|FieldMask|更新するフィールドのリスト|
|getValidateOnly|boolean|リクエストを検証し、更新されたPhraseSetをプレビューするが実際には更新しないか|

## 3. フレーズセットを削除
指定したフレーズセットを削除します。

### 3.1. スコープ
OAuth2.0でこのAPIを実行するには、以下のスコープを指定してください。
サービスアカウントで実行する場合はスコープの指定は不要です。
```
https://www.googleapis.com/auth/cloud-platform
```

### 3.2. 実行

```java
public static void main(String[] args) throws Exception{
    try(SpeechClient client = getSpeechClient()){
        DeletePhraseSetRequest.Builder builder = DeletePhraseSetRequest.newBuilder();
        builder.setName(String.format(
                "projects/%s/locations/%s/phraseSets/%s", 
                "プロジェクトID","ロケーションID","フレーズセットID"));
        
        OperationFuture<PhraseSet,OperationMetadata> response = client.deletePhraseSetAsync(builder.build());
        System.out.println(response.getName());

        PhraseSet set = response.get();
        System.out.println(set);
    }
}
```

#### 3.2.1. HTTPリクエスト
DELETE:　https:\//speech.googleapis.com/v2/projects/{プロジェクトID}/locations/{ロケーションID}/phraseSets/{フレーズセットD}
が実行されます。

#### 3.2.2. クエリパラメータ
DeletePhraseSetRequest.Builderのsetメソッドにより、クエリパラメータを追加できます。
build()メソッドでDeletePhraseSetRequestインスタンスを取得し、
deletePhraseSetAsync()に渡します。

|メソッド|引数|説明|
|---|---|---|
|setValidateOnly|boolean|リクエストを検証し、削除されたフレーズセットをプレビューするが実際には削除しないか|
|setAllowMissing|boolean|フレーズセットが見つからない場合、リクエストは成功し操作は行わないか|
|setEtag|String|チェックサム値|

#### 3.2.3. リクエストボディ
リクエストボディはありません。

### 3.3. レスポンスの内容
#### OperationFuture\<PhraseSet,OperationMetadata\>

[1.3. レスポンスの内容](#13-レスポンスの内容)と同じです。

#### DeletePhraseSetRequest
|メソッド|戻り値|説明|
|---|---|---|
|getName|String|削除するフレーズセットの名前<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}/phraseSets/{フレーズセットID}"|
|getValidateOnly|boolean|リクエストを検証して削除されたフレーズセットをプレビューするが実際には削除しないか|
|getAllowMissing|boolean|フレーズセットが見つからない場合、リクエストは成功しても操作は行わないか|
|getEtag|String|チェックサム値|

<br>
<br>
おしまい。。