先日(2020/03/28(土))YouTubeのライブ配信にて、Power Apps でMicrosoft Translator を利用して朗読アプリを作成する配信を行いました!
下記にアーカイブがありますので、よろしければ見て頂けると嬉しです!
今回はこちらの配信で行ったことのまとめと、MicrosoftTranslator.TextToSpeech() を利用したときに発生したトラブルの原因とその対処方法(動画1:00:00あたり~)を記載したいと思います。
Microsoft Translator の使い方
公式の文書はこちらになります。Power Apps から Microsoft Translator に接続する
こちらの文書にかかれているように、文章の読み上げには、
MicrosoftTranslator.SpeechLanguages()
と
MicrosoftTranslator.TextToSpeech([テキスト], [ロケールID])
を利用すればいいですね。
これらを利用して朗読アプリを作成していきましょう!
朗読アプリを作成してみよう!
今回、読み上げ元となるデータはOneDriveのExcelに格納したいと思います。
Excel内にテーブルを作成し、例えば以下のように作成します。
"PowerAppsId"はPower Apps 側で自動で生成されるものなので、特にこちらで作成する必要はありません。
続いてPower Apps でこちらのExcelファイルを読み込めるようにしましょう。
コネクタで、"OneDrive for business"を選択し、対象のExcelファイルのテーブルを選択します。
これだけで、Power Apps からExcelのテーブルを読み込めるようになります。
Power Apps からExcelのテーブルを参照するときは、[テーブル名].[見出し]で参照できます。
読み上げる童話を選択できるように「入力」より「ドロップ ダウン」を追加します。
"Items"にはExcelのテーブル名、例えば私の場合ですと、"Books"と入力します。
また、表示される項目には"Title"が表示されてほしいので、"Value"には"Title"を選択します。
続いて表示する言語を選択できるようにします。
「入力」より「ドロップ ダウン」を追加し、"Items"に以下のように記載します。
MicrosoftTranslator.SpeechLanguages()
こちらも、選択肢が分かりやすいように"Value"には"Name"を選択しておきましょう。
続いて、テキストを表示させましょう。
ここで、テキストは、改行区切りをいつのまとまりとして、表示させたいと思います。
なので、現在何個目のテキストを表示しているか?を判断するための変数を宣言しておきます。
Screen.OnVisible
UpdateContext({_count:1});
続いてラベルを追加し、以下のように記載しましょう。
Label.Text
MicrosoftTranslator.Translate( Last( FirstN( Split( LookUp( Books, Title = TitleDropdown.Selected.Title, Text ), Char(10) ), _count ) ).Result, Dropdown4.Selected.Code )
こちらで、選択した物語が、選択した言語で、"_count"番目の改行区切りの文章が表示されます。
こちらの式、なにをおこなっているか簡単に説明しますと、
LookUp( Books, Title = TitleDropdown.Selected.Title, Text )
まずこちらでは、選択した物語をフィルタしています。
Split( LookUp( Books, Title = TitleDropdown.Selected.Title, Text ), Char(10) )
"Char(10)"は改行を表しています。
Split()関数については、こちらの公式文書をご確認ください。Power Apps での関数の分割
簡単に説明すると、ここでテキストを改行区切りにしています。
Last( FirstN( Split( LookUp( Books, Title = TitleDropdown.Selected.Title, Text ), Char(10) ), _count ) ).Result
こちらでは、改行区切りで取得されたテーブルに対して、"FirstN([table], count)"で最初からcountまでのデータを取得し、さらにLast([table]).Resultにて、最後のデータを取得しています。
つまり、_count番目のデータを取得しているわけですね。
MicrosoftTranslator.Translate()
最後に、取得された文章を選択された言語で翻訳しているわけですね。
続いて_countを変化させることにより、文章を変化させましょう!
「アイコン」より、次へと戻るを意味するようなアイコンを選択します。
そしてそれぞれの"OnSelect"にそれぞれ以下のように記載します。
NextIcon.OnSelect
UpdateContext({_count:_count + 1});
BackIcon.OnSelect
UpdateContext({_count:_count - 1});
これで物語が読めるようになりましたね!
あとはテキストをよみあげさせるようにしましょう。
「メディア」より、「オーディオ」を追加します。
オーディオのメディアには以下のように記載します。
Audio.Media
MicrosoftTranslator.TextToSpeech(MicrosoftTranslator.Translate( Last( FirstN( Split( LookUp( Books, Title = TitleDropdown.Selected.Title, Text ), Char(10) ), _count ) ).Result, Dropdown4.Selected.Code ), Dropdown4.Selected.Code)
ラベルのテキストを参照していないのは、ラベルにテキストが反映される待ち時間をなくすために、ラベルに指定しているテキストを直で指定しています。
続いて、次へや戻るが押されたときに、テキストが読み上げられるようにしたいため、以下のように記載します。
Screen.OnVisible
UpdateContext({_audioStart:false});
NextIcon.OnSelect
UpdateContext({_audioStart:true});
BackIcon.OnSelect
UpdateContext({_audioStart:true});
Audio.Start
_audioStart
これで、ボタンが押されたときにオーディオが再生されるようになりました。
ただこのままでは、一度オーディオが再生されると次にボタンを押してもオーディオが再生されません。
これは"_audioStart"が"true"のままなので、オーディオが再生されないのが原因です。
なので以下のように記載します。
Audio.OnEnd
UpdateContext({_audioStart:false});
これで、オーディオが終了したら、"_audioStart"が"false"になるように設定できました。
この手法は、タイマーを利用する際にもよく使う手法なので、是非覚えておいてください!
以上で朗読アプリの作成は完了です!
でも...
前のテキストが一瞬読み上げられてしまう!
この設定のままでは表示されているテキストではなく、
1つ前に表示されていたテキストが一瞬読み上げられ、その後、今表示されているテキストが読み上げられる。
という事象が発生してしまっているかもしれません。
ライブ配信中はこの原因をすぐに究明することができませんでしたが、原因及び解決方法がわかりましたので、ここに記載します。
まず、単刀直入に原因を説明すると、オーディオが参照しているデータがまだ反映されていないのに読み上げを行おうとしていたからです。
では、オーディオはどこにあるメディアデータを参照しているのか?というと、オーディオのメディアに設定してあるデータをラベルなどで表示させればわかります。
表示させてみると、以下のようなテキストが得られるかと思います。
appres://blobmanager/...
こちらをみてぴんときたかたもいるかと思いますが、AzureのBlobを参照していますね。
つまり読み上げが上手くいかなかったのは、AzureのBlobに保存が完了していないのに、データを読み上げてたからですね。
なので、データが更新されたら読み上げ(オーディオの再生)を行うようにします。
オーディオのメディアには上記確認で用いたラベルを参照するようにします。
Audio.Media
MediaLbl.Text
続いて、前のデータを格納するための仕組みを作成します。
Screen.OnVisible
UpdateContext({_prev:""})
Audio.OnEnd
UpdateContext({_audioStart:false}); UpdateContext({_prev:MediaLbl.Text})
こちらの前のデータと現在のデータに差異があったときにオーディオを再生するようにします。
Audio.Start
(_prev <> MediaLbl.Text) || _audioStart
これで、前のデータが読み上げられることがなくなりました!