WatsonのSpeech To TextをXamarin.Formsで試してみたよ('◇')ゞ
音声認識の実装に関して興味があったのでWatsonのSpeech To Textを使用してXamarin.Fromsで音声認識を行ってみました。
なぜWatsonにしたか
GooleのCloud Speech APIが50回の回数制限があったから。
です。
Xamarin.Formsで音声入力を文字化する実装を考えたときにAndroidの方はSpeechRecognizerを使用すればできるんですが
iOSの方がなかなか難しいんです。
最初はGoogle Cloud Speech APIを使って音声認識を試してみようかと思ったのですが使用回数が50/dayだったりでほんとにちょっとしたテストしかできませんでした。
ということで別の方法を探してました。
この記事を読んでいたら
Watsonは有料となっていたのですがサイトを見てみたら最初の1000分までは無料とのことだったので試すにはちょうど良いと思いWatsonを試してみました。
CMとかもやってますしねぇ。Watson。
登録とか
Bluemixのアカウントを作成します。
最初の30日は無料ですべてのサービスにアクセスできるみたいです。
Bluemixのアカウントを作成すると組織とスペースを決めます。
組織は日本語で大丈夫でしたがスペースは日本語だめかもしれません。
最初に日本語を入れてみたのですが、登録は成功するけど反映されないみたいなおかしな状態になったので英語にしたほうが良いかと思います。
ホーム画面からWatsonを選択します。
右上の「+」ボタンをクリックします。
Speech To Textを選択します。
特に考えずに作成を行います。
資格情報の作成を行います。
usernameとpasswordは認証情報として使用します。
APIについて
APIReferenceはちゃんと用意されています。
主にHTTPを使用したセッションありとセッションなしのAPI、WebSocketを使用したAPIがあります。
HTTPを使用したセッションは保存済みのデータをテキストに変換するのに適していてWebSocketはリアルタイムに変換する事に向いていると考えてよいかと思います。
Java用とnode.js用のライブラリは用意されています。
またUnity用のC#ライブラリもありますので、お手軽にっていうのであればそちらを利用するのも手です。
今回はAPIの理解を得たい面もあったのでそれらは使用せずに実装します。
リアルタイム変換を行いたいのでWebSocketのAPIをします。
実装
とりあえずソースコードを
Observer/Observableパターンで実装してます。
使用しているライブラリは
WebSocket-Sharp
Json.NET
認証
まずWebSocketで接続を行います。
接続URLはwss://stream.watsonplatform.net/speech-to-text/api/v1/recognize
クエリストリングにてmodelを指定できます。
modelは言語に使用する言語に対応した物を指定します。
今回は日本語ですのでja-JP_BroadbandModel
を使います。
資格情報としてSpeechToTextの資格情報を設定します。
_client.SetCredentials(user, password, true);
そして接続を行います。
接続に成功した場合、クライアントからスタート情報をjsonで送信することで変換ストリーミングを開始できます。
var startjson = JsonConvert.SerializeObject( new Connection { Action = "start", content_Type = $"audio/l16;rate={SampleRate};channels={Channel}", InterimResults = InterimResults, Continuous = Continuous, InactivityTimeout = -1, MaxAlternatives = 1, Timestamps = false, WordConfidence = false }, Formatting.Indented); Debug.WriteLine(startjson); _client.Send(startjson); _isSending = true;
今回はPCM音声データを使用しますのでcontent-typeにはl16を指定しrateとchannelsを追加で指定します。
Interim_resultsは変換が確定しない時点でもストリーミング的に途中結果を受け取ることができます。
continuousを有効にすることで断続した変換を行うことができます。
スタート要求を送信するとstate : "listening"というjsonを返答してくれます。
スタートを送信したらあとは、PCMデータをWebSocketのBinaryFrameにて送信することで結果を返答してくれます。
if (!_isConnected) return; if (value.IsStop == false) { if (!_isSending) { StartRecognize(); } _client.Send(value.PcmStream); } else { _client.Send("{\"Action\": \"stop\"}"); _isSending = false; Debug.WriteLine("Stop"); }
結果に関しては Speech to Text Service Documentation | Watson Developer Cloudを読んでください。
受信処理は
var result = JsonConvert.DeserializeObject<SpeechResult>(args.Data); Debug.WriteLine(args.Data); result.Results.ForEach(res => { if (res.Alternatives.Any()) { var speechtext = new SpeechText { IsFainel = res.Final, Text = res.Alternatives.First().Transcript }; _speechTextSubject.OnNext(speechtext); } });
こんな感じで書くことができます。
今回はXamarin.Forms側のプログラムは説明しませんがソースコードは
こちらで確認することができます。
精度的には他と比較していないので何ともです。
おそらく多と比較検討してくれる記事などを書いてくれる人が出てくると思うので期待です。
このように実装することでオンライン限定ですがクロスプラットフォームでの音声認識を実装できます。
このケースでは音声認識部分はAndroidとiOSでコード共有率100パーセントです。
Xamarin素晴らしい。
以上です。
ToReactiveProperty拡張メソッド
特に書くことがないのでReactiveProperty使うときに追加している拡張メソッドを紹介します。
ToReactivePropertyAsOneWaySync
ModelからReadOnlyReactivePropertyを作成するときに使います。
むっちゃ使います。
INotifyPropertyChangedクラスからViewModelのプロパティ作成するときはまずこれです。
基本はViewModelのプロパティは基本がReadOnlyReactivePropertyでありReadOnlyObservvableCollectionでありReadOnlyReactiveCollectionです。
編集が必要な時のみReactivePropertyを使ってます。
ToReactivePropertyAsOneTime
たまに使います。
ReactiveProperty.FromObjectを使いたい時によくなんだっけ?って忘れるのでToって書けばインテリジェンスで候補が表示されれば幸せになれると思います。
IDisposableとusing
今更なんですけどC#初心者な感じの話です。
最近ReactiveExtentionsを勉強しててDisposableによく触れるのですが自分でDisposableを実装するってやった事なかったなぁと思ってちょこっと作ってみました。
よくあるtry catchパターンの代替としてusingを使用する例です。
DisposableにてCommitするかRollBackするかを制御しています。
もっと色々なパターンでIDisposableって活用できそうですよね。
IObservable/IObserverもそうなんですけど,.NET Frameworkで用意されているInterfaceって色々と意味があるんだなぁと再認識させられます。
NSpeex.Reactiveをリリースしてみました
この度
NSpeex.Reactiveというライブラリをリリースしました。
現在のバージョンは0.0.1です。
このライブラリはNSpeex
と、NSpeexをObserver/Observableな感じで使用するための余計なライブラリが含まれています。
NSpeex単体で使いたい場合は本家を使用してください。
NSpeex単体でnugetパッケージを作らなかったのはワザとです(^◇^)
このライブラリは.NET4、Xamarin.Android、Xamarin.iOSで利用することができます。
にて管理を行っています。
どんなライブラリ?
こんなライブラリです。
NSpeex - Speex for .Net and Silverlight - Home
プラスしてRxのサブジェクトっぽくNSpeexを使えるようにしてあるだけです。
強いていえば、XamarinでNSpeexが使えるよ(^◇^)っていうのが特徴です?
サンプルは?
すいません。間に合っていません。そのうちサンプルアプリを作ろうと思います。
コードのイメージはこんな感じです。
どっかで見た気がします。
ObservableVoiceCaptureでキャプチャしたPCMをNSpeex.Reactiveでエンコード・デコードした後にDelayを1000msecかけて再生している例です。
どんなことに使えるの?
PCMデータをSpeexでエンコードしてネットワーク経由で送信して受信してデコードして再生するとVoIPになったりします。
現在の新しいVoIPなコーデックといえばOpusなのですが、Speexだってレイテンシも悪くないしイケてると思います。
たぶんそのうちOpusのライブラリ作ると思いますけど(^◇^)
おまけ
NSpeex/src/NSpeex.TypeScript at master · yuka1984/NSpeex · GitHub
以前のエントリー Netjsを使ってC#からTypeScriptへの変換をしてみた。 - 眠いしお腹すいたし(´・ω・`) で紹介したNSpeexのデコードの一部(NarrowBandにのみ対応)をTypeScriptで使用できるようにしたライブラリはこちらに管理を移動しました。
一応ブラウザで動かす例をちゃっかり載せときます。
サンプルはWebSocket経由でSpeexエンコードされた音声データを受け取ってJSにてデコードしてWebAudioAPIを使用して再生している感じです。
ObservableVoiceCaptureをリリースしてみました。
この度
ObservableVoiceCaptureというライブラリをnugetにリリースしました。
現在のバージョンは0.0.2です。まだ破壊的な変更をするかと思います。
このライブラリは.NET4.5以上、Xamarin.Android、Xamarin.iOSで利用することができます。
にて管理を行っています。
どんなライブラリ?
音声をキャプチャしたり再生したりできます。
.NET45版ではNAudio
を使用して音声データの入出力を行っています。
Xamarin.Android版ではNativeのAudioRecoed/AudioTrackを使っています。
Xamarin.iOS版ではInputAudioQueue/OutputAudioQueueを使っています。
PCMデータをbyteの形で取り扱う非常に低レベルなライブラリです。
特徴は?
インターフェースが全プラットフォームで共通になっています。
サウンドキャプチャはIObservable<byte>でサウンド再生はIObserver<byte[]>になっていて非常にシンプルです。
現時点ではXamairn Pluginの形で提供されていないのですが、近日中にXamarin Pluginに対応しようと思っています。
要するにXamarin Formsで低レベルなオーディオインターフェースをPCL上にて扱えるということになる予定です。
サンプルは?
すいません。間に合っていません。そのうちサンプルアプリを作ろうと思います。
コードのイメージはこんな感じです。
キャプチャしたPCMデータを1000msecディレイさせてそのまま再生させる例です。
実際に動かすとむっちゃハウリングします(^◇^)
割と簡単にPCMデータのやり取りを行えるようにしているつもりです。
どんなことに使えるの?
これ単体ではあんまり使い道がないかもしれません。
このライブラリは私が今作ろうとしている物の一部をライブラリ化したものです。
PCMデータをエンコードしてネットワーク経由で送信して受信してデコードして再生するとVoIPになったりします。
要するに単体では使えん(^◇^)
ということです。
以上、すごく無駄なエントリーでした(^^)/
Netjsを使ってC#からTypeScriptへの変換をしてみた。
アイコンがイケメンです。素晴らしいライブラリです。間違いないです。
ではなくてC#をTypeScript/JavaScriptに変換してくれるライブラリです。
仕組み的にはC#で作成したクラスライブラリファイル(.dll)を読み込んで.ts/.jsファイルを作成するイメージになります。
使い方
GitHubからプロジェクトをクローンしてビルドします。
引数に変換したいdllを指定してexeをコマンドラインから実行します。
そのフォルダにファイルが作成されます。
mscorlib.tsを作成されたtsファイルと同じ階層に置きます。
.NetFrameworkはどこまでカバーされているのか?
基本的にほとんど変換されません。
using Systemの範囲内は少しカバーされています。
具体的には
Netjs/mscorlib.ts at master · praeclarum/Netjs · GitHub
この範囲です。
ようするにNetjsは純粋にC#プログラムをTypeScriptに変換してくれます。
だから既存のC#資産をTypeScirptに。。。ぐへへぇ。みたいな事は出来ません。
私の使い方
既存のC#資産をTypeScriptに変換して使いました。
さっきと言っていることが違うのですが、C#で書いていても.NetFrameworkをあまり使っていない資産というものもあるということです。
NSpeex - Speex for .Net and Silverlight - Source Code
こういう類の資産です。
現在、私の知る限り
- C/C++ -> JavaScript
- C# -> TypeScript/JavaScript
emscriptenでC変換されたjsは結構見かけます。
duocodeeが現時点で継続しているプロダクトとしては最新の環境になると思いますが
連載:「○○してみた」日記:C#→JavaScriptコード変換ってどうよ? DuoCodeを試してみた - @IT
出力されるコードを見て(´・ω・`)となってしまったため試しませんでした。
Netjsでは
SimpleVoiceDeliver/NSpeex.Decoder.ts at master · yuka1984/SimpleVoiceDeliver · GitHub
こんな感じのコードが出力されます。
これなら手を入れようかって気になるかなぁと思います。
使ってみて
元コードがかなり.NETを使っていないコードだったので、すんなり変換できましたが、.NETを使っている部分で足りない部分はmscorlib.tsに書き足しました。
たしかArray.CopyとRandomだったと思います。
ようするに足りなかったら自分で書けば良いんです。
にソースコードは載ってます。
変換精度ですが、一部(´・ω・`)な部分がありました。
IL詳しくないのでわかんないのですが、配列の値セットが
array[index] = value;
みたいに変換されたいのですがarray.set_item(index, value);
という風に変換されることがあって、その部分は手で修正しました。
後は
byte[] short[]
がnumber[]
に変換されるのでUint8Array、Int16Arrayに書き直した。C#の2次元配列[,]に対応していないため、元コードをジャグ配列に直してからビルドした。
ぐらいです。
大体1日もかからず目的のtsファイルを作れたのですごく助かりました。
生かせる部分は限定的ですがアイディア次第では楽することができるかもしれません。
Xamarin.FormsでOnSleepとOnResumeの呼ばれるタイミングをAndroidとiOSで似た感じにしたい
Xamarin.FromsのPCLプロジェクトのApplicationクラスにはOnSleep/OnResumeという仮想関数が用意されています。
Working with the App Lifecycle - Xamarin
OnSleep - Called each time the application goes to the background.
OnResume - Called when the application is resumed, after being sent to the background.
となっているわけですが、AndroidとiOSで呼ばれるタイミングが全然違ったりします。
Androidでは画面上部から設定画面をプルダウンしたりしてもOnSleepは呼ばれませんが、iOSでは画面上部、画面下部から設定画面を引っ張ったりするだけでOnSleepが呼ばれたりします。
なのでタイミングが違いすぎてあまり役に立たなかったりします。
iOSをAndroidに合わせたい場合には以下のようにすると一応合わせることができます。
一応と書いてあるのはAppDelegate.csのOnResignActivationの基底をコールしないことによる副作用が見えないためです。
現時点で副作用らしい副作用は出ていませんが不安である場合には各プラットフォームのMainActivity/AppDelegateにて動作を実装してOnSleep/OnResumeを使用しないほうが良いかもしれません。