連続音声認識っぽくなったAndroid SpeechRecognizer速報


※追記: Googleアプリは日々アップデートされているので、最新版のGoogleアプリには本問題はありません。

Androidに必ずインストールされているGoogleアプリがバージョン6に上がってから、SpeechRecognizerの挙動が大幅に変わりました。

音声認識するdurationがかなり長くなり、認識途中経過をコールバックしてくれるようになったようです。
これは半ば連続音声認識のような挙動とも言え、ボイスコマンドとしてSpeechRecognizerを使うには非常にありがたいアップデートです。

しかし現状その弊害もあり(バグの可能性もある)、長めのメッセージ入力は不便になっています。
さすがに使いづらいので改善はされると思いますが

連続音声認識っぽい機能

startlisteningしてからその認識終了まで、スタンダードな使い方としてはonResultで結果、onErrorでエラーを受け取って終了するか、stopListeningを呼んで終了する使い方でしたが、partialResultの受け取りがonPartialResultできるようになりました。
とはいえ、これは新しく追加されたインターフェースでもなく、昔からあります。
しかしGoogleのdocumentにも「途中経過の認識結果返せるようだったら返す」みたいなやる気のないスタンスが定義されていたので、何もonPartialResultsに返さないことが多く(というか返ってきたのを見たことがない)、DeveloperたちはpartialResultに頼るなと言っていました。

最近ではかなり積極的に返すようになったようです。

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, context.getPackageName());
//これこれ
intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
SpeechRecognizer recognizer = SpeechRecognizer.createSpeechRecognizer(context);
recognizer.setRecognitionListener(new RecognitionListener() {
    //...略

    // これこれ
    @Override
    public void onPartialResults(Bundle partialResults) {
        List<String> recData = results.getStringArrayList(android.speech.SpeechRecognizer.RESULTS_RECOGNITION);
    }

    @Override
    public void onResults(Bundle results) {
        List<String> recData = results.getStringArrayList(android.speech.SpeechRecognizer.RESULTS_RECOGNITION);
    }
});
recognizer.startListening(intent);

これでどういうことができるかというと、認識結果の途中経過をユーザーにフィードバックできる他、ボイスコマンドとして利用する場合はかなり認識速度が早くなります。
フローとしては下記のような感じです。

【従来】
startListening

室伏さん「私の」(認識中)

認識終了、onResultsで「私の」という結果を受け取る

もしくは

startListening

室伏さん「私のおじさんは鉛筆です」(認識中)

認識終了、onResultsで「私のおじさんは鉛筆です」という結果を受け取る

【今】
startListening

室伏さん「私の」(認識中)

onPartialResultsで「私の」という結果を受け取る(認識中)

室伏さん「おじさんは」(認識中)

onPartialResultsで「私のおじさんは」という結果を受け取る(認識中)

室伏さん「鉛筆です」(認識中)

onPartialResultsで「私のおじさんは鉛筆です」という結果を受け取る(認識中)

認識終了、onResultsで「私のおじさんは鉛筆です」という結果を受け取る

なのでonPartialResultsで受け取るコールバックは早いし頻度も高いので、ボイスコマンドのようなキーワード抽出するパターンだと非常に有用です。

onResultが遅くなった・・・

これは仕様だとは思えないほど遅くなってます。
「まだ認識してたの!?」と思うほどに遅く、ユーザーの立場に立つと画面が止まったと思ってしまうリスクがあります。
多分改善されるだろうと思うのですが、現状partialResultsを無理やり使うなり工夫するのがいいかと思います。

あとこれは完全にバグですが、stopListeningを呼んでもstopされずに認識し続けることがたまにあったりします。はっきり言って不安定なのでこのあたりも改善されることを期待したいところです。

あとなんかあったっけな?

  |l、{   j} /,,ィ//|     / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
  i|:!ヾ、_ノ/ u {:}//ヘ     | あ…ありのまま 今 起こった事を話すぜ!
  |リ u' }  ,ノ _,!V,ハ |     < 『おれは奴の前で階段を登っていたと
  fト、_{ル{,ィ'eラ , タ人.    |  思ったらいつのまにか降りていた』
 ヾ|宀| {´,)⌒`/ |<ヽトiゝ   | 催眠術だとか超スピードだとか

過去記事

Android Speech Recognizerを使いこなす