イマーシブリーダー (Immersive Reader) を使ってみよう！

## イマーシブリーダー (Immersive Reader) とは
一言でいうと「テキストを読んで理解できるようユーザーを支援する AI サービス」です。「読んで理解する」というのは奥が深そうですね。
例えば、専門用語が含まれる難しい文章を読むとき、外国語の文章を読むときなど、ゆっくりまたは繰り返し読んだり、言葉を調べながら読むことはないでしょうか。また、文字のフォントや大きさや色などによっては読みづらいといったこともあると思います。
イマーシブリーダーはこのような様々なシーンでアクセシビリティを向上し、すべての人の「読んで理解する」ことを支援するサービスです。
Microsoft Teams や OneNote、Word などの Office 製品にも組み込まれています。

[Immersive Reader](https://azure.microsoft.com/ja-jp/services/cognitive-services/immersive-reader/)

## 「読んで理解する」ということをどうやって支援するか
先ほどの説明だと実際に何をしてくれるサービスなのかイメージがわかないかもしれません。
デモサイトを作成したのでこれを元に機能の説明します。

イマーシブリーダーのデモサイト (運用コスト削減の都合上、最初にページが表示されるまで時間がかかりますがご容赦を)
https://immersivereaderdemo.azurewebsites.net/

上記のイマーシブリーダーのデモサイトを開きます。その後、好きな文を入力し、言語を選択して "Immersive Reader" のボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/bb7556b0-c52c-08a1-2f7c-e7c60ec6fe53.png)

ボタンをクリックして数秒待つと、先ほど入力した文章が大きな文字で表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/bdff8068-ef1f-d8fe-c0be-ec9dac165c6a.png)


### 1. 文字サイズや背景色などの変更
画面右側の AA のボタンをクリックすると文字の大きさ (Text Size) やフォント (Font)、背景色 (Themes) などを変更することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/44bebd5b-73ee-4dba-da86-9694534bb893.png)



### 2. 単語を絵で説明
例えば、英語学習では英語→日本語のように頭の中で変換するよりも、英語そのものを理解できる英語脳を身に着けることが良いと言われています。このように単語の説明に絵が用いられると覚えやすいですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/afba323c-3f70-8be8-c325-368abd4a9732.png)

### 3. 品詞と音節の表示
品詞は n (nouns=名詞)、v (verbs=動詞)、adj (adjectives=形容詞)、adv (adverbs=副詞) という文字と色で表示されます。また、音節 (Syllables) をオンにすると landforms が land-forms のように 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/53011c0d-6ca5-6d41-1031-190af18891ae.png)

### 4. 音声で読み上げ
以下は GIF なので音声は出ていませんが、再生マークを押すとテキストを音声で読み上げます。また、それとあわせて読んでいる単語にフォーカスが当たります。
![reading.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/b6864fea-3651-6ef2-fc9f-b52153b2ab78.gif)


音声の再生スピードや女声男声を変更することもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/d144a84e-e09d-606a-a1c6-b9ec809f560c.png)

### 5. 翻訳
単語と文章の両方とも翻訳ができます。英語学習に役立ちそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/0b0002b7-f761-a2c1-b66a-a4549d56e652.png)

単語
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/204f7e5b-b764-1300-a361-db577110fafb.png)

文章
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/ade19a19-19f9-8b1e-0e8c-04757bc2c422.png)

[イマーシブ リーダーを使用して読みのアクセシビリティを向上させる](https://docs.microsoft.com/ja-jp/azure/cognitive-services/immersive-reader/overview#use-immersive-reader-to-improve-reading-accessibility)

## イマーシブリーダーを使った開発
Azure イマーシブリーダーを用いることで、例えば Web サイトのアクセシビリティ向上、独自の言語学習コンテンツの作成などに役立てることができると思います。
今回のデモサイトは GitHub にある ASP.NET Core のサンプルを元に開発し、Azure Web Apps という PaaS のサービスで公開しています。

### 1. Azure リソースの作成と Azure AD アプリの登録
基本的には以下の記事に記載の流れで操作を行います。

[イマーシブ リーダー リソースを作成して Azure Active Directory 認証を構成する](https://docs.microsoft.com/ja-jp/azure/cognitive-services/immersive-reader/how-to-create-immersive-reader)

上記のドキュメントを開いて「使ってみる」をクリックすると、そのページ内で Azure Cloud Shell が起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/7de4c1bd-fcc7-f089-cf63-1fadc5deac5b.png)

まずは以下のコードスニペットを貼り付けて実行します。
公式ドキュメントでは $AADAppDisplayName="ImmersiveReaderAAD" のように Azure AD アプリの名前が自動的に入るのですが、わかりにくいので任意で入力するように変更してます。

```PowerShell
function Create-ImmersiveReaderResource(
    [Parameter(Mandatory=$true, Position=0)] [String] $SubscriptionName,
    [Parameter(Mandatory=$true)] [String] $ResourceName,
    [Parameter(Mandatory=$true)] [String] $ResourceSubdomain,
    [Parameter(Mandatory=$true)] [String] $ResourceSKU,
    [Parameter(Mandatory=$true)] [String] $ResourceLocation,
    [Parameter(Mandatory=$true)] [String] $ResourceGroupName,
    [Parameter(Mandatory=$true)] [String] $ResourceGroupLocation,
    [Parameter(Mandatory=$true)] [String] $AADAppDisplayName,
    [Parameter(Mandatory=$true)] [String] $AADAppIdentifierUri,
    [Parameter(Mandatory=$true)] [String] $AADAppClientSecret,
    [Parameter(Mandatory=$true)] [String] $AADAppClientSecretExpiration
)
{
    $unused = ''
    if (-not [System.Uri]::TryCreate($AADAppIdentifierUri, [System.UriKind]::Absolute, [ref] $unused)) {
        throw "Error: AADAppIdentifierUri must be a valid URI"
    }

    Write-Host "Setting the active subscription to '$SubscriptionName'"
    $subscriptionExists = Get-AzSubscription -SubscriptionName $SubscriptionName
    if (-not $subscriptionExists) {
        throw "Error: Subscription does not exist"
    }
    az account set --subscription $SubscriptionName

    $resourceGroupExists = az group exists --name $ResourceGroupName
    if ($resourceGroupExists -eq "false") {
        Write-Host "Resource group does not exist. Creating resource group"
        $groupResult = az group create --name $ResourceGroupName --location $ResourceGroupLocation
        if (-not $groupResult) {
            throw "Error: Failed to create resource group"
        }
        Write-Host "Resource group created successfully"
    }

    # Create an Immersive Reader resource if it doesn't already exist
    $resourceId = az cognitiveservices account show --resource-group $ResourceGroupName --name $ResourceName --query "id" -o tsv
    if (-not $resourceId) {
        Write-Host "Creating the new Immersive Reader resource '$ResourceName' (SKU '$ResourceSKU') in '$ResourceLocation' with subdomain '$ResourceSubdomain'"
        $resourceId = az cognitiveservices account create `
                        --name $ResourceName `
                        --resource-group $ResourceGroupName `
                        --kind ImmersiveReader `
                        --sku $ResourceSKU `
                        --location $ResourceLocation `
                        --custom-domain $ResourceSubdomain `
                        --query "id" `
                        -o tsv

        if (-not $resourceId) {
            throw "Error: Failed to create Immersive Reader resource"
        }
        Write-Host "Immersive Reader resource created successfully"
    }

    # Create an Azure Active Directory app if it doesn't already exist
    $clientId = az ad app show --id $AADAppIdentifierUri --query "appId" -o tsv
    if (-not $clientId) {
        Write-Host "Creating new Azure Active Directory app"
        $clientId = az ad app create --password $AADAppClientSecret --end-date "$AADAppClientSecretExpiration" --display-name $AADAppDisplayName --identifier-uris $AADAppIdentifierUri --query "appId" -o tsv

        if (-not $clientId) {
            throw "Error: Failed to create Azure Active Directory app"
        }
        Write-Host "Azure Active Directory app created successfully."
        Write-Host "NOTE: To manage your Active Directory app client secrets after this Immersive Reader Resource has been created please visit https://portal.azure.com and go to Home -> Azure Active Directory -> App Registrations -> $AADAppDisplayName -> Certificates and Secrets blade -> Client Secrets section" -ForegroundColor Yellow
    }

    # Create a service principal if it doesn't already exist
    $principalId = az ad sp show --id $AADAppIdentifierUri --query "objectId" -o tsv
    if (-not $principalId) {
        Write-Host "Creating new service principal"
        az ad sp create --id $clientId | Out-Null
        $principalId = az ad sp show --id $AADAppIdentifierUri --query "objectId" -o tsv

        if (-not $principalId) {
            throw "Error: Failed to create new service principal"
        }
        Write-Host "New service principal created successfully"
    }

    # Sleep for 5 seconds to allow the new service principal to propagate
    Write-Host "Sleeping for 5 seconds"
    Start-Sleep -Seconds 5

    Write-Host "Granting service principal access to the newly created Immersive Reader resource"
    $accessResult = az role assignment create --assignee $principalId --scope $resourceId --role "Cognitive Services User"
    if (-not $accessResult) {
        throw "Error: Failed to grant service principal access"
    }
    Write-Host "Service principal access granted successfully"

    # Grab the tenant ID, which is needed when obtaining an Azure AD token
    $tenantId = az account show --query "tenantId" -o tsv

    # Collect the information needed to obtain an Azure AD token into one object
    $result = @{}
    $result.TenantId = $tenantId
    $result.ClientId = $clientId
    $result.ClientSecret = $AADAppClientSecret
    $result.Subdomain = $ResourceSubdomain

    Write-Host "Success! " -ForegroundColor Green -NoNewline
    Write-Host "Save the following JSON object to a text file for future reference:"
    Write-Output (ConvertTo-Json $result)
}

```

次に以下をコピーして自身の Azure のサブスクリプション名や任意の名前に置き換えた後、先ほどと同様の Azure Cloud Shell に貼り付けて実行します。

```PowerShell
Create-ImmersiveReaderResource `
  -SubscriptionName '<サブスクリプション名(ID)>' `
  -ResourceName '<任意のリソース名>' `
  -ResourceSubdomain '<任意のサブドメイン名>' `
  -ResourceSKU 'S1' `
  -ResourceLocation 'japaneast' `
  -ResourceGroupName '<任意のリソースグループ名>' `
  -ResourceGroupLocation 'japaneast' `
  -AADAppDisplayName '<任意の Azure AD アプリの表示名>' `
  -AADAppIdentifierUri '<任意の Web サイトの URL (適当に入力しても http://localhost で動作します)>' `
  -AADAppClientSecret '<記号と大文字小文字を含む16桁の英数字>' `
  -AADAppClientSecretExpiration '<任意クライアントシークレットの有効期限。例えば、2030-12-31>'
```


最後に以下のメッセージや開発に必要な ClientSecret などの情報が表示されれば成功です。
ここで表示される json は後で使うのでコピーします。

```
Granting service principal access to the newly created Immersive Reader resource
Service principal access granted successfully
Success! Save the following JSON object to a text file for future reference:
{
  "ClientSecret": "xxxxxxxxxxxx",
  "TenantId": "xxxxxxxxxxxxx",
  "Subdomain": "xxxxxxxxxxx",
  "ClientId": "xxxxxxxxxxxx"
}
```

### 2. GitHub にあるサンプルを元に開発
以下のリポジトリをクローンまたは zip ダウンロードします。


https://github.com/microsoft/immersive-reader-sdk

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/71cf3ed9-674f-4358-4e2e-e70e32c65e5d.png)

サンプルは /js/samples 配下にあるので、好きな言語のサンプルを使います。
ここでは advanced-csharp という ASP.NET Core (C#) のサンプルを使います。
.sln という拡張子のファイルを Visual Studio で開き、ソリューションエクスプローラーでプロジェクト名を右クリックすると "ユーザー シークレットの管理" という項目があります。
これをクリックすると secrets.json というファイルが開きますので、そこに先ほど Azure Cloud Shell のコマンドを実行して表示された ClientSecret などの json を貼り付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/d93b1e36-f46e-c294-dc1d-2a031ee54089.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/b7639dd0-618a-2d8c-f679-fbca1ba5a6ff.png)

ただ、私の環境ではこれで正常に動作しなかったため、Controllers 配下の HomeController.cs に TenantId = "xxxxx" のように書き換えています。（管理上よくはないですが）

あとは実行しましょう。このようなページが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/d4e5fb0c-9a79-6bf6-5091-8018961a84b7.png)

Immersive Reader のボタンをクリックして以下のような画面が表示されたら、イマーシブリーダーの呼び出しも成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/c114a288-fe01-f4b4-f4f6-91784b296b9e.png)



ASP.NET Core のアプリは イマーシブリーダーを呼び出すために必要となる Azure AD の token 取得や JavaScript SDK を用いた HTML ページの応答を行います。

[Immersive Reader JavaScript SDK リファレンス (v1.1)](https://docs.microsoft.com/ja-jp/azure/cognitive-services/immersive-reader/reference)


イマーシブリーダーのご紹介でした。