めあとるーむ日記帳

なんか書く

PlantUMLで書いた図をCircleCIを使って自動で画像に変換する

同日

いろいろ試したり問題が起きたりしたから追記した


PlantUMLを使ってUML図を書くときはAtomにせよVSCodeにせよそれなりにビューアーがあるのでリアルタイムで見る分には基本問題ない

ただしドキュメントに挟むときとかあるいはメモがてら残したものをGitで管理して見たいときにちょいっと見るとなるといろいろめんどいしWebから見れない(ChromeのExtensionはあるけど)のでいっそ書いたら勝手に画像を残してくれる環境がほしいと思った。

plantuml.com

CIにもよるが、今回はGitHubと連携が楽で無料の範囲でも結構いろいろ使えるCircleCIを使うことにした

circleci.com

さて同じようなことを考えている人がいるのではないかと思ったが、GitHub Pagesで公開する用途に使うケースが散見されるが単に画像だけ作って欲しいみたいなものは見当たらなかった(ちなみにその場合gh-pagesあたりが使えるらしい)

加えてだいたいCircleCI用の設定ファイルがCircleCI1.0のもので、2.0にするにはなんかいろいろと手間取ってしまった


設定ファイルそのものをさっくりまとめると

  1. plantUMLを入れる
  2. 日本語フォントを入れる
  3. 変換する
  4. コミットしてプッシュ

簡単にこれだけ。ただし前提条件を上げておくと

  • 画像を用いるためgit-lfsを導入しておく(好みでもある)
  • CIのプッシュをCI自身がスルーするためにコミットメッセージに[ci skip]を入れる

前提条件は後半に書いて先に必要だったところから


PlantUMLを入れる

apt-getで持ってこれるのでそんな難しい話ではない

sudo apt-get install plantuml

plantumlのjarファイルを直接持ってきてjava -jar plantuml.jarで実行してもいい。その場合はgit-lfsの使用を推奨するがなくてもまあなんとかならなくもないと思う(最初それでやってたし)

日本語フォントを入れる

文字コードUTF-8にする必要がある(と思われる。厳密には調べてない。ごめん)

ちなみに標準だと日本語フォントがないらしく豆腐現象が起きるので英語のみなら当然必要ない

sudo apt-get install [任意のフォントパッケージ]

当然だがパッケージがなければ別の方法でインストールすることになるので各々頑張ってね

ちなみに入れただけではそれを使ってくれるわけじゃないので設定する必要もある

コマンドラインから設定する方法もあると思われるが見つけられなかったのでUML図を書いているファイルに書き込む形をとる

@startuml "hogehoge"
!include settingfile
~~~(略)~~~

そして設定ファイルを別に書く。ここでは!include settingfileのとおりsettingfileの名前で以下を書き込む

skinparam{
    defaultFontName [任意のフォント名]
}

ちなみにフォント名がわからないときとかはplantuml -printfontsででてくるから一旦そのコマンドを走らせてもいいかも

変換する

plantuml filename.wsd

終わり。オプションを付けないとPNGで出力する。git-lfsとか使わないで全部テキストベースで管理したいなら-ttxtとか-tutxtオプションをつけるといいよ

ファイル名は *.wsd でやってしまっていいと思う。厳密に管理できるならそれに越したことはないが

コミットとプッシュ

コミット時には [ci skip] のメッセージを入れておくこと(じゃないとpush時に自分のpushでCIが走ってまたpushして……と無限ループになる)

SSH鍵を渡していればプッシュは通常のコマンドと同様にやってくれるが、場合によっては画像ファイルの扱いでコンフリクトとかするのでオートコミット用のブランチを作って -f でプッシュしたりする必要がある(この辺改善できそう)


以上を踏まえ設定ファイルはこんな感じで

version: 2
jobs:
  document:
    docker:
      - image: circleci/openjdk:9.0.4
    steps:
      # 専用のブランチ作成・移動
      - run: git checkout -b auto-commit
      - run: sudo apt-get install plantuml
      - run: sudo apt-get install fonts-ipafont-gothic
      - run: plantuml doc/*.wsd
      - run: git add -A
      - run: git commit -am "[ci skip] auto commit"
      - run: git push -f origin auto-document

ここではフォントはIPAフォントを使っている(のと、git回りの設定やworking_directory関係の設定を省略しちゃってる)

コミットする内容がなかった場合はそのまま終了するように CircleCIの設定でProject Setting→Build Settings→Advanced Settings→Auto-cancel redundant buildsを有効にしてあげる必要がある(と思う、厳密にこれでうまくいくのか試しきれてない)

公式のドキュメントはこれ

circleci.com

ちなみにこれだと多分失敗時の処理とか全部スキップされるからwhen: on_failあたりを入れたりしないといけないはず

……とりあえずブランチを分けてフィルターを当てたほうが問題は起きにくい……かも

追記:

これでもこけた。一応「なにもしてない」ということになるので別に失敗でもいいのだが、失敗は失敗で放置しておくと本来の失敗で拾いそこねる可能性もあるのでどうにかしたい


余談だけど、curlwgetが使えるなら(というかCircleCIは使える)PlantUML Text Encodingでエンコードして公式に変換してもらう方が楽だと思った

plantuml.com

公式のオンラインエディタでも使ってるやつなので心配はないしDockerで自前で作ることもできる

エンコーディングの実装が必要になるほか、日本語フォントがあればの話になってしまうができるならそっちの方がいいかも


ここからは前提条件。本題のついでぐらいに

SSH鍵(いらないかも)

ssh-keygen してあげて pub をGitHub側に、秘密鍵をCircleCIの設定に。調べればわかるので問題ないと思う

Windowsだと面倒な気もするが、Bashコマンドですぐに作れる環境に行ける+そのままコマンド実行できるので覚えておくといいよ

書き込み権限が必要だと思ってたけどどうも用意した鍵の使用履歴がなかったのでいらないのかも

Git-LFSを入れる

まず作業環境に入れておく。入れておいてgit lfs trackコマンドで管理ファイルに*.pngを追加しておく

そんでCircleCI側も入るようにする

steps キーの下に以下を入れる。基本はDebian環境への導入と一緒

- run: curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
- run: sudo apt-get install git-lfs

すごいざっくりしてるしもっとうまくやれるところもあるかも知れないがとりあえずこんな感じ

やってる事自体は普通(手作業でも問題ないというか多分はやいぐらい)なのでこだわるところではないかも知れないが、後々ドキュメントの自動作成とかもできるようにしたいのでちょっとこだわった

自動でコミットした部分は別のブランチにしてあとからマージしてあげるのをイメージしている

できればブランチを分けてfilterかけてあげるとか、まだ変換してないところ&変更したものだけ変換とかもしたいが、とりあえずここまでできれば困ることはないので今後の改善点とCircleCIの勉強にもなると思いここまでとする。

なんかもっと楽にできるところとか問題が起きたときの回避策とか知ってる方いたら教えてください

Flutterをちょこちょこ触りつつのファーストインプレッション的な感想

Flutter - Beautiful native apps in record time

Flutter はクロスプラットフォームアプリケーション開発環境の一つ。Googleが開発(だったはず)、現在β版。

クロスプラットフォームと銘打ちつつ対応はほぼAndroid/iOSで、一応言語的にDart言語なのでその部分をうまく使い回せばWebも行けそう(あまり詳しく調べてない)

なんとなくTwitterで見かけたのでちょいちょい触りつつ、思ったことをつらつら


良かったところ

  • 言われてるけどUIが豊富
    • UIもDartでラップされてるけどだいたいやりたいことはできると思う
    • サンプル・例・実装までの資料も豊富。お前ほんとにβか
    • 英語しかないけどまあがんば
  • 環境構築が比較的楽
    • 強いて言うならパス通すとかわからない人には無理。まあそういう人はリリースまで待てばいいんじゃないかな
    • VSCodeとかIntelliJに忌避感なければという前提もあるが(それ以外でもDart環境作れれば苦労はしないと思う
  • レポジトリにサンプルがついてきてそれをローカルでビルドすると手元で動きが見える
    • UIの具体的な動作や実装例がセットで見れるのでかなり助かる
    • こういうのないかな?と思った物が見つかる
    • とりあえず環境作ったら一通り見ておくといいかも知れない
  • ホットリロード早いし便利
    • UIのプレビューがないけどかわりに書いてホッとリロードぐらいで問題ない感じ

現状つまったところ

  • 再描画処理でListView更新しようとしたらうまく行かなかった
    • なんで ListView.children : List で要素追加したとき更新されないのに ListView.children : List.toList() だったら要素追加して更新されるんだ
  • Dartでコード書くときのいい感じのアーキテクチャとかパターン知らねぇ
    • DroidKaigi のアプリがFlutter使ってるんで参考にさせてもらってる

その他

知ってる人いたら教えて

  • WebとかサーバサイドのコードもDartで書けるらしいけどどこまで共有とかきくのか
    • というかDartでWebフロントってどこまでできるんだろ
    • 調べてもDart VM使ってた古い記事ばっかりなんだよね。JSコンパイルしないとダメ?
  • ベータ版だけど今後の展開どうなってんの(英語ばっかでたどれない
  • Dartの初心者~中級者向けの資料ってなんかないかな
  • ホットリロード便利だけどUIを静的解析からリアルタイムで見る方法ってない?

ざっとちょいちょい触っての感想はこんな感じ

現状は各種UIの実装を試しつつなれてきたらなんか作ってみようかなって思ってる

ほんとUIが豊富で実装が結構楽(な印象)なのでいろいろ試して楽しいというところはある。DartTwitterライブラリもあるからTwitterクライアントとか作ってもいいかも知れない(StreamingAPIは死ぬが

Xenoblade2をクリアした

少年と少女は出会い、子供は信じた道を進み、大人はそれを手伝った。

変化したものたちは未来を紡ぎ、変化できなかったものたちは滅びを迎えた。

そんな感じのゲームだった。


まあ詩的な表現はそこまでにして、ゲームのレビュー的な

  • よかったところ
    • ストーリー全般。山あり谷あり見所あり。王道に邪道なしという感じのボーイミーツガールのお手本のような形
    • 戦略性が大きいバトルシステム
    • 設定上強い存在がちゃんと強いところ(主に主人公
  • ちょっと気になったところ
    • セーブデータもう1つ作れない?
    • カメラワーク。小さなオブジェクトでもキャラクターとの間に入ると一気に動くケースが多い。天井とかも透過して欲しかった
    • UI回りと画面遷移。フィールド歩いてるときに開くメニューが3種類あるのとかちょっとややこしいし、キャンセルボタンが直前の画面に戻るとも限らない
  • 判断が難しいところ
    • バトルシステムがやや複雑。覚えれば問題ないが、管理するゲージが多い、コンボの選択肢が確認しづらい、役割の選択肢が多いなど、覚えることややりたいことに到達するまでが難しい
    • エストが長いものが多い。「AをこなすためにBをこなしてCに届ける必要がある」と言った感じでお使いがお使いを呼ぶ感じ
    • フィールドが広すぎる。悪いわけじゃないが、後半のダンジョンとかフィールドスキルが必要な場面でブレイドの入れ替えとか面倒だった

判断が難しいところは達成感につながると考えれば一概に悪いとも言えない、でも面倒だったり複雑なのはそうなんだよな……という感想

でも減点法でも80点を下回ることはなく、加点法であれば90点を上回る、総合的にはそんな評価。概してプラス方向の評価だと思う。少なくともやりきった感想はプラスの評価にしたい

特に戦闘は、判断が難しいと言ったが複雑さはやり遂げた際の達成度に大きくつながっている。チェインアタックが完璧に決まれば100万ダメージ以上を一気に叩き込むことも可能であり、強敵との戦闘ではそれらに加えて複数のテクニックを応用することで打ち勝つ達成感はひとしおである

バランスとしては細かい部分も使いこなしてようやくクリアできる感じだが、レベル上げでゴリ押しもできるだろうし、後半は主人公が滅茶苦茶強くなるのでそこまで苦労しないだろう

シナリオも見事であり、序盤こそ心情が理解できない可能性があるが後半に至れば「このキャラクターはこの思考だ」と自信を持って考えられるようになる。欠点といえば欠点だが、そのためキズナトーク(指定場所で特定キャラ同士が会話をするイベント)では時折出てくる選択肢でものすごく迷うor全く迷わないというケースも出てくる。ちなみにキズナトークは1度消化すると他の会話を見ることができなくなるので筋金入りのプレイヤーはイベントを実行する前にセーブをするぐらいだという

ボーイミーツガールのお手本であり、終わり方も綺麗である

全体的に欠点らしい欠点はなく、かつてのXenoシリーズのような設定資料を見ないとわからない設定は少ない(まったくないとはいいにくい)。ある程度は創作におけるファンタジーやSFの経験があったほうが理解はしやすいかもしれない(まあRPGをプレイする人はそこを十分みたいしていると思うが)

ちなみにプレイ時間はだいたい50時間ぐらいだった。たまにのレベル上げは行ったがほぼストレートにプレイしてこのくらいの時間である。昨今のアクションゲームの流れからすると1週が長いが、RPGで見れば順当(あるいは大作では順当)だろうと思う

なお追加DLCは未購入。ただし追加シナリオや時間の余裕があれば購入するかも

Xenoblade2 (ゼノブレイド2)  - Switch

Xenoblade2 (ゼノブレイド2) - Switch


で、以下ネタバレあり。感想というより、最終的な終着点と前作との関係について

重ねて言うけどネタバレあり

考察に近い戯言だけどXenoblade2のテーマの中に「信頼」と「変化」があったと思う

信頼は、多分普通にプレイすれば見えるものだと思う。というかそういう話だったはず。絆という言葉が多用される作品(もといシリーズ)だし

もう1つの変化は、マルベーニがまさに変われなかったものだし、メツも最後まで変われなかった(変わるべきであるのは気づいていたと思う)

逆に、シンやヨシツネ、ベンケイ、サタヒコは変われたんだと思う。だからこそ、死んでしまったが最後に救われた(と思う)

もっと早くに変わることに気づいたニアは、それこそ死ぬことなくもっと前で救われた

そして、見逃してはならない大きな変化があったと思うのは「神」というか「クラウス」だと思う。

このクラウスは前作Xenoblade(クロスではない)のラスボスと同一存在である。厳密には彼の左半身が前作のラスボスである

彼は前作で、相転移実験(まあ要はブラックホール作るやつ)を強行し、結果閉じた別世界に行ってしまった(巻き込まれでもう一人研究者が行ったし、作中で3つあったうちのチップの1つもそっちに行った)

そして別世界で彼は神となり、すべての生命を見下した

同じように元いた世界でも彼は神となった。ただし、彼はどうにか地球を再生しようとした

これは作中で会話をしているが、相転移実験を行った頃のクラウスはザンザ(Xenoblade世界でのクラウスの名)にかなり近い思考をしており、現に人(というか生き物すべて)に絶望しているところがあった

しかしアルスト(Xenoblade2世界)で神となった右半身は元の世界でなんと後悔までし、償いとしてどうにかいい世界を作り直そうとした

彼はなぜか元いた世界では変わっていた。半ば人工的であるが作り直した生命体は進化し人の姿になったが、結局過去の人類から変わっていなかった。しかし再び絶望したのではなく、レックスに会うことが出来てよかったとまで言った

後悔した彼はラスボスではなく、ただのいるだけの種明かしの存在だけで、それどころか最後には死を悟り、残った生命体を手助けすることまでした

前作までプレイする必要があるが、彼がものすごく変化していたのは意外であった。なぜそこまで変わったのかは謎だ。孤独がそうさせたのか、失敗がそうさせたのか、はたまた何かあったのかはわからない

ラスボスだった存在も結局は人間だったと示したかったのかもしれないし、ただのシナリオの都合なのかもしれない

Kinect v2が安定しない時

Kinect v2で開発をしようと思いつつ、まあ始めたんだがたまにKinectがうまく動いてくれない事がある

具体的には

  • 赤外線とXboxマークが光ったと思ったらすぐに消える
  • USBのリソース不足と言われる
  • ドライバエラーが出る

と言った感じ

うまく動く事もあればその直後にうまく動かなくなることもある感じで、とにかく安定しない

USBの問題であればUSBコントローラのドライバを更新してみるのもいいが、それでも解決しないこともある


結局USBコントローラとの相性によるところがあるようなので、もしPCケースのUSBコントローラが別であればそっちに接続するのも手

マザボと直結したほうがいいんじゃない? って思いがちだけど実際繋いでみると安定した

ケースにUSB3.0端子がない場合はPCIeからのUSB3.0増設でなんとかなるかもしれない。相性がよければ通るはず

……まあKinect開発してるような人にそんないまさら言うことじゃなくない? とも思ったが万が一詰まってる人がいたら試してみるといいかもしれない

ちなみにケースのUSB端子に繋いだところ、起動直後のWindows Helloがうまく動かないことがあるもののそれ以外の問題はほとんど発生しなくなった模様

リアルタイムゆっくり実況プレイがしたい

最近(2018-02-01現在)バーチャルYoutuberなるものが流行ってるそうで

どのキャラもわかりやすくキャラが立っていて様々な面で感心するなどしているのですがやはり思うのですよ

「俺もやりたい!!!!!」

いやまあぶっちゃけやろうと思えば環境的にはすぐにできるでしょって感じなんだけど、せっかくだしちょっと変化球で行きたいなと思いました

そして実況というとどちらかと言うと生身よりゆっくり実況プレイのほうがなんとなく接していた機会が多い気がしてました


ただ単にゆっくり実況プレイをするならプレイ動画にゆっくりMovieMakerあたりを使って合わせればいい

でもせっかくだし「ゆっくり生放送」をやってみたいなと思った。理由は誰もやってないからじゃないかな(やってるかもしれない

あとやっぱり動画編集面倒だからね。生放送そういうとこ楽だし(だからといって何も考えなくていいわけじゃないが

しかし当然ながらゆっくり実況は

  1. まずプレイ動画を撮る
  2. あとからプレイ動画にゆっくり音声をかぶせる
  3. さらに必要ならゆっくりの表情をつける

という処理を行う必要があるわけで、これをリアルタイムに行うのは

  1. リアルタイプにゆっくり音声を作って再生する
  2. ゆっくりの表情をつける

が必要。で、ここで冒頭のバーチャルYoutuberに戻る

要は「表情を読み取って適当なゆっくりの画像を写す」「音声認識して文字書き起こしてゆっくりで喋らせる」ということをカメラ経由でやればいいのでは

でも「表情を読み取る」とかそんな簡単にできるの?

maretol.hatenablog.jp

できそうなのあったわ


というわけで今後の方針

Kinect v2を使いリアルタイムで表情や奥行き情報を取りそれを用いて適宜ゆっくりの顔を表示する仕組みを作る

さらに音声認識をしてゆっくりで喋らせる

がんばるぞい


リポジトリ

GitHub - maretol/RealTimeYukkuri: リアルタイムゆっくりの開発リポジトリ

System.Speechライブラリを使ってみる

github.com

ソースはここに

maretol.hatenablog.jp

前にこの記事読んでおいたほうがいいかも


結構時間がかかったのはMVVMとかデータバインディングとかの勉強も合わせるかー、と言ってなんか次々試行錯誤したため

おかげでデータバインディングの考え方とかはだいぶわかった気がする。気がする

ひとまず形にはなった

f:id:maretol:20180126164705p:plain

コマンドのところに反応したい単語を書き込んでフォーカスを外す(なんか外クリックしてフォーカス外すようにしたかったけどよくわかんなかった。現状下のテキストボックスにフォーカス合わせるしかなさそう)と開始できるようになるので開始する

認識結果や起動・終了時のメッセージは下のテキストボックスに出てくる。認識時は認識系(RecognizedとHypothesized)と一致率の数値が表示される

ソースコード自体のやってることはぶっちゃけサンプルとほとんど変わらない

もっとしっかりとやりたいならちゃんとDisposeとか呼ぶ環境を作るべきかなというぐらい

いずれにせよやっていることは前回(最初の記事のリンク)に書いたとおりで、エンジンの環境を整えて各イベントを登録し文法データを読み込んで起動、終了というだけ

イベントや文法データの取り込み方、結果の取扱などをいじってあげればテストぐらいはできるかも

前回の記事にも書いたとおり本来は音声コマンドとかで使うものだと思うので自由な認識を期待するとあまりよろしくないかもしれない


解説記事を書こうと思ってたんだけど解説することが特にないことに気づくなど

なんかわかんないこと聞いてもらえればなんか答えるかもしれない

C#(.NET)のSystem.Speech.Recognitionライブラリを使う

1ヶ月ぐらいで辞めた仕事(の出向先)で音声認識をゴニョゴニョしてたけどそのときにSystem.Speech.Recognitionライブラリを使った

このライブラリ何がアレって基本的な使い方の記事も少なく細かいところまでアレコレしようとするとだいたい公式ドキュメント(の英語版か機械翻訳版)しかないという状態だった

なんでまあ覚えてる範囲と出来た範囲でメモを残しておく

いやほんと公式ドキュメントも情報量十分かって言うとどうだろうってなっちゃうやつだったからな……イングリッシュ読めるようになりたい

具体的なコードとかはGithubに上げる。完成したら解説記事を書く(現在未完)

github.com


公式

System.Speech.Recognition 名前空間

基本はこの名前空間のクラスを使う。以下主に使うクラスなどなど

  • System.Speech.SpeechRecognitionEngine : 音声認識のエンジン部分。ここに音声認識時のイベントとか設定とかある。
  • System.Speech.SpeechRecognizer : 上とほぼ同じだがこっちはWindowsDesktop向け。上はプロセス上で動くやつ(違いはよくわからない。さっき見てて気づいた)
  • System.Speech.Grammar : 認識時の主軸となる文法データを取り扱う。同名前空間にGrammarBuilderとかもある
  • System.Speech.DictationGrammar : ディクテーション(発する言葉全てを文字起こしする)の場合に使う文法データ
  • System.Speech.Choices : 文法データのもとになる登録語をまとめるクラス
  • 各種 EventArgs : 認識したときのイベントで渡されるやつ

だいたいこのあたり。文法データを外部データにしたい場合は System.Speech.Recognition.SrgsGrammar 名前空間の SrgsGrammarCompile とかでバイナリデータを出してあげたり、Srgs文法ファイルを読ませたりできる

文法ファイルとはなんぞや、ってなる(なった)ので先に説明しておくと、このライブラリは基本的に音声コマンドを実行するためのライブラリなので、そのコマンドをまとめたのが文法というものである

詳細は後述するが、この文法に則って認識するため、自由な認識をさせることはできない。もっとも DictationGrammar であれば認識できる(が、こちらだと単語の登録はできない)


RecognitioEngine / Recognizer が音声認識機能を提供してくれるクラスになる

違いはドキュメントを見た感じだとRecognitionEngineのほうが高機能。言語・地域を設定したり、AudioStreamで音データを受け取ったり、読み込み途中で文法データを再読込させたりもできる

ただ認識自体は同じようで、イベントとか見た感じその辺に違いがあるようには見えなかった(認識以外だと環境に関係するイベントの違いがあるっぽい?)

ここではRecognitionEngineをベースに解説する。具体的なコードはそのうちGithubに上げるか公式ドキュメントで何となく理解できると思う

SpeechRecognitionEngine クラス (System.Speech.Recognition)

まずインスタンスを作ったら

  1. 文法ファイルを読み込む (LoadGrammar メソッドなど)
  2. Eventの受け取りを追加 (SpeechRecognized イベントなど)
  3. 音声のソースを設定 (SetInputToDefaultAudio メソッドなど)
  4. 音声認識の開始開始する (Recognize メソッドなど)

の順で動かす。厳密に言うと順番は関係ないかもしれないが、公式ドキュメントはどのクラス・メソッドでもだいたいこの順にやっているのでこれに従ったほうがいいと思う


文法ファイルと文法ファイルの読み込みについて

特定のコマンドや単語に反応させる、という機能を作るときにその指定をする機能

具体的にコマンドの例を挙げると「リビングの電気をつけて」とか「キッチンの電気を消して」とか

これらを登録することで認識したときに「リビングの電気をつけて」という認識をしたよー、とイベントが返してくれるわけである(ただしディクテーションは除く)

そして当然だが、これらのコマンドを全部登録するのは骨が折れる。「○○(場所)の電気を××(つけて/消して)」と全パターン登録するのは(不可能じゃないけど)面倒だよね、ってわけでちゃんとどうにかする方法がある

1つはSRGSドキュメントを使って記述し、それを読み込ませる

Speech Recognition Grammar Specification Version 1.0

音声コマンドにおけるXML記述の規格らしく、すでに他環境用に書いてる人とかはこれをそのまま XMLReader で読んで System.Speech.Recognition.SrgsGrammar クラスに渡してそのまま Grammar クラスに渡せばもう辞書登録は完了する

もう1つがGrammarBuilderクラスを用いてその場で組み立てる。

どちらの方法でもワイルドカード、単語リストなどを組み合わせることでコマンドのパターンを網羅する仕組みになっている

以下GrammarBuilderでもっと具体的に解説する。

まず単語のリストはChoicesクラスで用意する。例えばさっきの電気のオンオフであれば

Choices choices1 = new Choices(new string[]{"リビング","キッチン","玄関"});
Choices choices2 = new Choices(new string[]{"つけて","消して"});

と登録し、GrammarBuilder で

GrammarBuilder gb = new GrammarBuilder();
gb.Append(choices1);
gb.Append("の電気を");
gb.Append(choices2);

とすると、{choices1}の電気を{choices2} というパターンに対応できる

当然文法は順序によって内容が異なるのでそこは注意が必要。Appendメソッドで後ろに追加していくのがよく使うパターンだと思う

また、同時にワイルドカードを差し込んだり( AppendWildcard )、一部ディクテーション ( AppendDictation )を挟んだりもできる

この2つはどう違うかというとワイルドカードは内容を認識しないけどディクテーションは認識しようとすることだと思う。試したらまた書くね(少なくともワイルドカードは ... となるだけで内容までは出ない)

GrammarBuilderで文法ファイルを形成したらあとはGrammarクラスに渡してあげて、GrammarクラスをLoadGrammarメソッドで読み込んであげるといい

ちなみに非同期でやってくれるというLoadGrammarAsyncメソッドもあるが、Async/Awaitは使えないので自分で別スレッド作ってあげるかTask.Factory.StartNewあたりで渡してあげないといけないっぽい。終わったらLoadGrammarComplitedイベントが発火する


音声認識は認識した段階で各種イベントとして発火するようになっている

反応するイベントは以下の通り

  • SpeechRecognized
  • SpeechHypothesized
  • RecognizeComplited
  • SpeechDetected
  • SpeechRecognitionRejected

これがまた結構めんどくさく、

イベント 内容
SpeechRecognized Grammarに登録した内容を認識した。一致率は高い
SpeechHypothesized Grammarに登録した内容を認識した。一致率は中程度
RecognizeComplited 音声認識終了時にGrammarに登録した内容を認識した
SpeechDetected 何かを認識した(何を認識したかはわからない)
SpeechRecognitionRejected 認識したものがGrammarに登録したものに一致しなかった

Rejectedの一致しなかった、というのがよくわからないと思うが、ドキュメントを見ても実際に動かしてみても本当によくわからなかった。謎のイベントだった

また、SpeechDetectedもよくわからない(反応するだけで内容は不明、EventArgsも特別それっぽい情報がない)ものだった

とりあえず、認識だけで言うとSpeechRecognizedで十分である。SpeechHypothesizedはあまりにも大雑把で認識しすぎる感じである

認識次第終了、というかたちを取るのであればRecognizeComplitedを使うほうがよさそうである

認識結果は各イベントから渡されるEventArgsの中に入っている(Detected除く)。これを取ってくれば認識結果を得られるというわけになる


精度自体はあんまり高くない(コマンドの種類によっては許容内。ディクテーションは正直イマイチ)。音声認識でメモを取るとかなら Google の Cloud Speech API とか Microsoft の Bing Speech API とか使ったほうがいい

今回は音声認識を起動したら人同士の会話を聞き続けてその中でキーワードが出てきたらそれを列挙するというものだったので、最大1分(WebSocketなら10分?APIによる)しか繋げないAPIを使うことは無理だった

ひとまずここまで。ソースが上がったらGithubに上げて解説記事のような物を書くかもしれない


以下愚痴に近い私見

前職でも前前職でも「マイクを起動しっぱなしで人同士の会話を常に録音したい」というのが言われたが正直なところそんな機能がちゃんと提供できるのはあと5年ぐらいかかると思う。というか機械に向かって話しかけるのと人同士の会話を解析するっていうのは別のことで前者は割と形になってきてるけど後者はまだまだだと思うし、一緒にするのも止めてもらいたい

だいたい人同士の会話というのは人の想像以上に文章として破綻しているケースが多いので、それなりに時間を要するのではないかというのが私見

あとめっちゃどうでもいいけど文末の句点の有無が統一されてなさすぎて気持ち悪かった(全部取った