前回の続きです。
前回は、Blazor ウェブサーバー(ウェブアプリケーション)にWeb Speech API を埋め込んで、日本語音声認識機能を実装しました。
今回は、認識結果のテキストを、連載第7回で示したCeVIO読み上げアプリケーションを用いて発声します。
そして、これをもって、私の目的である「美少女ボイスのリアルタイム音声合成システム」が完成します。
Blazor で JavaScript から C# の機能を呼び出す
今回も、前回作成したプロジェクトを編集して、各機能を実装していきます。
また、第7回で作成したCeVIO読み上げアプリケーション「TalkAgent.exe」も使用します。
前回示したとおり、C#からJavaScriptの関数を呼び出す場合、JSRuntimeを仲介して、目的の関数を呼び出していました。
逆に、JavaScriptからC#のメソッドを呼び出す場合も、これと同様に.NETオブジェクト参照を仲介して、目的のメソッドを呼び出すことになります。
まず、_Host.cshtmlファイルを編集します。
スクリプトに、上記のコードを追加します。
dotnetObjectに、.NETオブジェクト参照に必要な仲介役をするためのオブジェクトを持たせます。
このオブジェクトを介して、C#の各メソッドにアクセスすることになります。
このオブジェクトは、最初は何も入っていませんが、このあとに示す、C#側でページ初期化時に1度だけ呼び出されるメソッドの中で、setDotnetObject関数を通じて.NETオブジェクト参照を渡すことになります。
次に、Counter.razorを編集します。
@code内で、OnInitializedAsyncメソッドをoverrideします。
これは、ページを開いた際に1度だけ呼び出されるメソッドです。
DotNetObjectReference.Create(this)で、Counter.razorにくっついている.NETオブジェクトへの参照を作成します。
作成した参照は、前回示した方法で、上で定義したJavaScriptのsetDotnetObject関数を呼び出して、JavaScript側に渡してあげます。
加えて、JavaScript側で音声認識したテキストを、C#側に渡してあげるためのメソッドを定義します。
この時重要なのが、
[JSInvokable("関数名")]
です。
メソッド定義の直前の行にこれを書かないと、JavaScript側から.NETオブジェクト参照ごしに呼び出すことができません。
関数名は何でもいいですが、たいていC#側で呼び出すメソッド名と同じものにします。
再び、_Host.cshtmlファイルに戻ります。
渡された.NETオブジェクト参照を通じて、C#側のメソッドを呼び出すには、
dotnetObject.invokeMethodAsync('メソッド名', 引数)
とします。
これにより、上のコードの場合は、C#側のaddSpeakerTextと名付けされたメソッドを、resultText変数の値を引数として、実行することができます。
CeVIO読み上げアプリケーションを呼び出す
あとはどちらかというとC#のノリで書く領域なので、とくに特別なことはしませんが
usingで使用するアセンブリを指定するときは、@を先頭につけて記述します。
ここでは、Processクラスを使用するために、System.Diagnosticsを追加しています。
コードですが、CeVIO読み上げアプリケーションのパスは、直書きしています(´・ω・`)
適切なものに直して(´・ω・`)(´・ω・`)
読み上げ中も音声認識は継続したいため、アプリケーションはTask.Runで非同期呼び出しします。
また、読み上げ中に送られてくる音声認識結果が1つとは限らないため、複数あっても漏らさず次の実行時に読み上げできるように、テキストはキューに追加していく形をとりました。
ま、そんな難しいことはやっていないと思います。
JavaScript側で音声認識により出力されたテキストを、dotnetObjectごしにaddSpeakerText関数(AddSpeakerTextメソッド)を呼び出すことで、C#側に渡し、テキストをキューに追加します。
C#側では読み上げ用のスレッドが並列実行されています。キューにたまったテキストを1文につなげ、CeVIO読み上げアプリケーションに引数として渡す形で、美少女ボイスでの読み上げを実現します。
なお、あらかじめCeVIO Creative Studio を起動しておく必要があります。
起動していない状態で実行すると、読み上げは行われず、以下のダイアログが表示されます。
例によって、作成したプログラムを以下の公開リポジトリに置いています。
(都度更新するので、コードがここで提示したものと異なる場合があります。)
ちなみに、C#が動くならCeVIOのアセンブリもBlazorで呼び出せばいいじゃんと思うかもしれませんが、CeVIOのアセンブリは.NET Framework、Blazorは.NET Coreなので、基本的に直接呼び出せません。
互換性のあるバージョンどうしならかろうじてなんとかなるかもですが、あまりメリットはなさそうです。
システムを実行してみよう!
ここまでで、目的のシステムにあるべき一連の流れを実装することができました。
ということで、実行して、まずは自分のブログを読み上げてみました。
んー。というか、この文章を書いた私と、その文章を読み上げる私にも問題がある気がする(´・ω・`)
リテイクすりゃいいのに、しないから・・・(´・ω・`)
おわりに
やってみた感じですが、読み上げに天然さはあるものの、そこまで悪くもないんじゃないかなーといった印象です。私は、ね(´・ω・`)
良いかと言うと、そこまででもないんですが。
でもまぁ、声がかわいいから許す!
やはり完璧さを求めるには、至らない部分も多いですが、遊びでやる分にはかまわないのではないかと。
あと、読み手次第なところもあると思います。
先のエントリーでも書きましたが、文章としてつじつまの合うような音声認識を試みているように見えるので、人間側が1文1文を短くわかりやすく発話することで、ある程度の実用性も見えてくるのではないかと思います。
まぁ、人間側がシステムに配慮するというのは、本来なら逆だろうとも思いますが、音声認識システムに、たとえば「文章としての整合性は優先しなくてもいいので、文節レベルで低遅延で吐き出してくれればいい」みたいなパラメータが追加されれば、そういうのを使ってシステムのよさを向上していったらいいのかなと思います。
現時点では、Web Speech API そのものもドラフト版なので、今後どうなるかは分かりませんし、今後ここで提示した方法が使えなくなるかもわかりませんが、まずは1つの完成形としてみていいのではないでしょうか?
また、提案システムの中にテキスト翻訳機能を追加すれば、たとえば話者は日本語で、配信されるのは英語でといったような機能も実現できます。
どれだけ使い物になるかはわかりませんが、グローバル化が進む社会で、かつコロナ禍の中にある状況で、リモートによる機械的なやりとりが多くなっているわけですが、その中でこれを海外向けのリモートプレゼンテーションのための1つのツールとして、日本語しか話せなくても英語で発信できる、そんな夢のようなシステムの可能性も秘めているのではないかと思います。
今回は、特に例外処理などははぶいて実装していますが、提示のプログラムはあくまで最低限の実装のみの土台ですので、これをベースに各自でいろんな技術を取り込めば、テキストへの感嘆符等の自動挿入、カメラ画像による表情・感情の反映、より人間らしい音声合成と発話とかとか、いろんなテーマが思い浮かぶのではないかと思います。
私もここまでやったので、気になるものがあれば取り込んでみたいですが、まずは今の実力をはかるという観点で、次回、テキトーに配信してみます(´・ω・`)
全10回にわたり長々と文章を書いてしまいましたが、読んでいただいたみなさん、お付き合いいただきありがとうございました!
本題は以上です。次回はおまけ(´・ω・`)
あ、そうそう・・・
第6回でも書きましたが、今日('20/7/26)までならソースネクストeSHOPでCeVIOが4,500円で買えます(´・ω・`)
あと、もしよかったら、チャンネル登録もお願いします!
4連休無駄にせずに済みました!(`・ω・´)