Speech Serviceの発音評価をPower Appsで試す

# はじめに

`Azure AI Service`の[Speech Service](https://learn.microsoft.com/ja-jp/azure/ai-services/speech-service/)において、[発音評価](https://learn.microsoft.com/ja-jp/azure/ai-services/speech-service/how-to-pronunciation-assessment?pivots=programming-language-csharp)が存在します。

https://learn.microsoft.com/ja-jp/azure/ai-services/speech-service/

https://learn.microsoft.com/ja-jp/azure/ai-services/speech-service/how-to-pronunciation-assessment?pivots=programming-language-csharp

外国語学習もしやすい環境になりましたね。

[Azure AIのSpeech Studio](https://speech.microsoft.com/portal)でどのようなものか試すことができます。
こちらをクリックして内容を覗いてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/523ee91c-52a1-4376-bba4-54b5cac6fb61.png)

https://speech.microsoft.com/portal

発音評価を試すことができるようですね。
スクロールしていくと`Power Platform コネクタ`の文字が👀✨

![スクリーンショット 2024-06-19 172701.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/b19807b4-f810-3b5a-e1ff-0cc3b93f5a40.png)

`Power Platform`で使えるのであれば、試すしかないですね！
使ってみましょう！

# [Azure 音声発音評価 (プレビュー)](https://learn.microsoft.com/ja-jp/connectors/azurespeechpronuncia/)

Power Platformのコネクタで[Azure 音声発音評価 (プレビュー)](https://learn.microsoft.com/ja-jp/connectors/azurespeechpronuncia/)が存在します。

https://learn.microsoft.com/ja-jp/connectors/azurespeechpronuncia/

`Azure`のリソースがあればサクっと試すことができるようですね。

接続方法は
 - `Azure AD`統合
 - `API キー`
 
`API キー`接続が既定ですが`非推奨`のようです。

しかしながら`リージョン`と`API キー`のみでサクっとコネクタが使えてしまうため、今回は`API キー`でコネクタの接続します。

![スクリーンショット 2024-06-19 004151.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/2da97368-1139-4ff3-fcc3-ce8898527b18.png)

:::note info
記事は2024年6月19日時点の情報です。
Azureのリソースのリージョンは`japaneast`。
:::


# [発音評価](https://learn.microsoft.com/ja-jp/connectors/azurespeechpronuncia/#%E7%99%BA%E9%9F%B3%E8%A9%95%E4%BE%A1%E3%81%AE%E4%BD%9C%E6%88%90-(v1))
`Power Automate`経由で`Audio`データを渡すことにより、`発音評価`が実行できます。
アプローチは、以前記事で取り上げた[Whisperの文字起こし](https://qiita.com/DEmodoriGatsuO/items/109b151f3004f1cf2f28)の手法と同様に、マイク コントロールから音声を録音し、`Power Automate`経由で評価できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/5d9561d6-a8fd-0eea-0b87-e530abbd041c.png)

サクっと画面を並べて、`マイク コントロール`の`OnStop`に下記を仕込みます。
その前に、`Power Automate`の準備をしましょう。

# Power Automate
1. Power Appsから`録音データ`と`発音評価の参照テキスト`を受け取る
1. `Azure Speech Pronunciation Assessment`コネクタに値を渡す
1. 応答で評価を取得

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/3b6ece16-7dee-4fed-82bd-fddb5ebdc355.png)

上記の三ステップで済む超お手軽仕様。

(1) Power Appsから`録音データ`と`発音評価の参照テキスト`を受け取る

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/b27fb198-2244-7b29-eacf-a70f63e9e903.png)

今回は`English`練習専用で作成。
ほかの言語も使う場合は、`Power Apps`から操作できると良いと思います。

(2) `Azure Speech Pronunciation Assessment`コネクタに値を渡す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/41ce3e5d-7482-766e-fbd8-7dddd6bea71f.png)

 - `AudioContent` - `triggerBody()?['file']?['contentBytes']`
 - `ReferenceText` - `triggerBody()?['text']}
 - `Language` - en-US

上記を指定します。

(3) 応答で評価を取得

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/fb8441e4-47fd-a1e5-ef84-ef02bc112e5b.png)

サジェストで`body`が出てきませんが、評価の値は`body`に含まれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/b0409e22-0cc2-e636-f97d-057a55436231.png)

関数で`body('Create_Pronunciation_assessment(V1)')`と直接指定しましょう。

```plaintext:Body
@{body('Create_Pronunciation_assessment(V1)')}
```

応答の`JSON Schema`はコチラ

```json:Response Body JSON Schema
{
    "type": "object",
    "properties": {
        "RecognitionStatus": {
            "type": "string"
        },
        "Offset": {
            "type": "integer"
        },
        "Duration": {
            "type": "integer"
        },
        "NBest": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "Confidence": {
                        "type": "number"
                    },
                    "Lexical": {
                        "type": "string"
                    },
                    "ITN": {
                        "type": "string"
                    },
                    "MaskedITN": {
                        "type": "string"
                    },
                    "Display": {
                        "type": "string"
                    },
                    "AccuracyScore": {
                        "type": "integer"
                    },
                    "Words": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "Word": {
                                    "type": "string"
                                },
                                "Offset": {
                                    "type": "integer"
                                },
                                "Duration": {
                                    "type": "integer"
                                },
                                "Confidence": {
                                    "type": "integer"
                                },
                                "AccuracyScore": {
                                    "type": "integer"
                                },
                                "Syllables": {
                                    "type": "array",
                                    "items": {
                                        "type": "object",
                                        "properties": {
                                            "Syllable": {
                                                "type": "string"
                                            },
                                            "Grapheme": {
                                                "type": "string"
                                            },
                                            "Offset": {
                                                "type": "integer"
                                            },
                                            "Duration": {
                                                "type": "integer"
                                            },
                                            "AccuracyScore": {
                                                "type": "integer"
                                            }
                                        },
                                        "required": [
                                            "Syllable",
                                            "Grapheme",
                                            "Offset",
                                            "Duration",
                                            "AccuracyScore"
                                        ]
                                    }
                                },
                                "Phonemes": {
                                    "type": "array",
                                    "items": {
                                        "type": "object",
                                        "properties": {
                                            "Phoneme": {
                                                "type": "string"
                                            },
                                            "Offset": {
                                                "type": "integer"
                                            },
                                            "Duration": {
                                                "type": "integer"
                                            },
                                            "AccuracyScore": {
                                                "type": "integer"
                                            }
                                        },
                                        "required": [
                                            "Phoneme",
                                            "Offset",
                                            "Duration",
                                            "AccuracyScore"
                                        ]
                                    }
                                }
                            },
                            "required": [
                                "Word",
                                "Offset",
                                "Duration",
                                "Confidence",
                                "AccuracyScore",
                                "Syllables",
                                "Phonemes"
                            ]
                        }
                    }
                },
                "required": [
                    "Confidence",
                    "Lexical",
                    "ITN",
                    "MaskedITN",
                    "Display",
                    "AccuracyScore",
                    "Words"
                ]
            }
        },
        "DisplayText": {
            "type": "string"
        }
    }
}
```

長いですね。しかしここで設定しておくことで、`Power Apps`で使いやすくなります。

# 改めてPower Apps
`マイク コントロール`の`OnStop`に下記を仕込みます。

```javascript:OnStop
UpdateContext(
    {
        Response: PronunciationAssessment.Run(
            {
                name: "audio.webm",
                contentBytes: Self.Audio
            },
            TextCanvasScript.Text
        )
    }
)
```

こちらで`録音データ`と`発音評価の参照テキスト`を`Power Automate`に渡します。
`レコード`形式で`発音評価`は取得されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/15219b25-e37e-c8a2-68f1-e5d5bb2aee9e.png)

評価が出ましたね。細かく単語別にスコアが細分化されます。
私の英語能力の低さはおいておいて、コネクタでサクっと試せるのは楽しいものです。

今回はビューにこだわりませんでしたので、このアプリケーションを次回レベルアップしていきたいと思います。