私はAndroid音声認識に基づいたアプリケーションを開発しています。
今日まで、すべてが適切にタイムリーに機能していました。音声認識ツールを起動して発言し、最大1〜2秒以内にアプリケーションが結果を受け取りました。
これは非常に受け入れやすいユーザーエクスペリエンスでした。
それから今日、認識結果が利用可能になるまで10秒以上待つ必要があります。
私は次のEXTRASを設定しようとしましたが、どれも識別可能な違いはありません
_RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS
_
私はアプリケーションを絶えず変更していますが、これらの変更はいずれも音声認識に関連していませんでした。
音声認識機能がonBeginningOfSpeech()
からonResults()
に切り替わる時間を短縮するために使用できる方法はありますか?
所要時間の例を示します
_07-01 17:50:20.839 24877-24877/com.voice I/Voice: onReadyForSpeech()
07-01 17:50:21.614 24877-24877/com.voice I/Voice: onBeginningOfSpeech()
07-01 17:50:38.163 24877-24877/com.voice I/Voice: onEndOfSpeech()
_
[〜#〜] edit [〜#〜]-2016年8月のリリースで明らかに修正されたベータ版のテスト で確認できます。
これは、Google 'Now' V6.0.23。*のリリースに伴うバグであり、最新のV6.1.28。*でも持続します。
V5.11.34。*のリリース以来、SpeechRecognizer
のGoogleの実装はバグに悩まされてきました。
this Gist を使用して、それらの多くを複製できます。
この BugRecognitionListener を使用して、それらのいくつかを回避できます。
これらをNowチームに直接報告したので、彼らは認識していますが、まだ何も修正されていません。 Google NowはAOSPの一部ではないため、Google Nowには外部バグトラッカーはありません。
あなたが詳述した最新のバグは、あなたが正しく指摘しているように、音声入力のタイミングを制御するパラメータは無視されるため、実装をほとんど使用できなくします。 ドキュメント :
また、認識エンジンの実装によっては、これらの値は効果がない場合があります。
私たちが期待すべきものです......
あなたが話さないか、検出可能な音を出さない場合、認識は無期限に続きます。
私は現在、この新しいバグと他のすべてのバグを再現するプロジェクトを作成していますが、すぐにここに転送してリンクします。
[〜#〜] edit [〜#〜]-部分的または不安定な結果の検出をトリガーとして使用する回避策を作成できると期待していましたユーザーがまだ話していることを知るため。それらが停止したら、一定時間後に手動でrecognizer.stopListening()
を呼び出すことができます。
残念ながら、stopListening()
も壊れており、実際に認識を停止することはありません。そのため、回避策はありません。
上記のような、認識エンジンを破壊し、その時点までの部分的な結果のみに依存する試み(認識エンジンonResults()
が呼び出されないとき)は、信頼できる実装を生成できませんでした 単にキーワードスポッティング 。
Googleがこれを修正するまで、私たちにできることは何もありません。あなたの唯一のアウトレットは、問題を報告するメール[email protected]であり、受け取ったボリュームがナッジを与えることを願っています.....
注!これはオンラインモードでのみ機能します。ディクテーションモードを有効にし、部分的な結果を無効にします。
_intent.putExtra("Android.speech.extra.DICTATION_MODE", true);
intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, false);
_
ディクテーションモードではspeechRecognizerはonPartialResults()
を呼び出しますが、パーシャルを最終結果として扱う必要があります。
UPDATE:
誰かが音声認識の設定に問題がある場合に備えて、Androidの音声タイムアウトの問題を克服するために構築した Droid Speech library を使用できます。
私のアプリは音声認識機能に完全に依存しており、Googleは爆弾を投下しました。物事の見方をすれば、少なくとも近い将来にはこれは修正されないと思います。
とりあえず、グーグルの音声認識が意図したとおりにスピーチの結果を提供するソリューションを見つけました。
注:このアプローチは、上記のソリューションとは少し異なります。
このメソッドの主な目的は、ユーザーが発した単語全体がonPartialResults()でキャッチされるようにすることです。
通常、ユーザーが特定のインスタンスで複数のWordを話す場合、応答時間が速すぎるため、結果の一部ではなく最初のWordだけが取得され、完全な結果は取得されません。
そのため、すべてのWordがonPartialResults()で確実にキャッチされるようにするために、ユーザーの一時停止遅延をチェックして結果をフィルタリングするハンドラーが導入されています。また、onPartialResults()からの結果の配列は、単一のアイテムだけではない場合が多いことに注意してください。
SpeechRecognizer userSpeech = SpeechRecognizer.createSpeechRecognizer(this);
Intent speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
speechIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName());
speechIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
speechIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, ModelData.MAX_VOICE_RESULTS);
Handler checkForUserPauseAndSpeak = new Handler();
Boolean speechResultsFound = false;
userSpeech.setRecognitionListener(new RecognitionListener(){
@Override
public void onRmsChanged(float rmsdB)
{
// NA
}
@Override
public void onResults(Bundle results)
{
if(speechResultsFound) return;
speechResultsFound = true;
// Speech engine full results (Do whatever you would want with the full results)
}
@Override
public void onReadyForSpeech(Bundle params)
{
// NA
}
@Override
public void onPartialResults(Bundle partialResults)
{
if(partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).size() > 0 &&
partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).get(0) != null &&
!partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).get(0).trim().isEmpty())
{
checkForUserPauseAndSpeak.removeCallbacksAndMessages(null);
checkForUserPauseAndSpeak.postDelayed(new Runnable()
{
@Override
public void run()
{
if(speechResultsFound) return;
speechResultsFound = true;
// Stop the speech operations
userSpeech.destroy();
// Speech engine partial results (Do whatever you would want with the partial results)
}
}, 1000);
}
}
@Override
public void onEvent(int eventType, Bundle params)
{
// NA
}
@Override
public void onError(int error)
{
// Error related code
}
@Override
public void onEndOfSpeech()
{
// NA
}
@Override
public void onBufferReceived(byte[] buffer)
{
// NA
}
@Override
public void onBeginningOfSpeech()
{
// NA
}
});
userSpeech.startListening(speechIntent);
(Googleがバグを修正するまで)私が見つけた解決策の最良の回避策は、Googleアプリのアプリ情報に移動し、「アップデートのアンインストール」ボタンをクリックすることでした。これにより、音声認識に直接影響するこのアプリに対して行われたすべての更新が削除され、基本的に工場に返されます。
**修正が判明するまで自動更新を停止することをお勧めします。 ***注:これは開発者専用のソリューションです。明らかにストアにアプリがある場合、これは役に立ちません。ごめんなさい...
更新:今日のテストの時点で、このバグは最終的に解決されたようで、これはもう必要ありません。将来再び壊れた場合に備えて、そのままにしておきます。私のテストから、音声タイムアウトは正常に機能しています。
OKまだ(アプリでこれを使用するので、結果を投稿します)、しかし、私は解決策を切望していました。基本的に、RmsDbがピークを下回り、2秒間onPartialResultsがなくなったと仮定して、ユーザーが話し終わったことをトリガーするためにonRmsChangedを使用しています。
私がこれについて気に入らないことの1つは、SRを破壊すると、二重のビープ音が鳴ることです。 FWIWおよびYMMV。改善点を投稿してください!
注:これを繰り返し使用する場合は、bBeginとfPeakをリセットすることを忘れないでください!また、SRを再作成する必要があります(onStartCommandまたはサービスの停止と開始のいずれか)。
import Android.app.Service;
import Android.content.Intent;
import Android.os.Bundle;
import Android.os.IBinder;
import Android.speech.RecognitionListener;
import Android.speech.RecognizerIntent;
import Android.speech.SpeechRecognizer;
import Android.support.annotation.Nullable;
import Android.util.Log;
import Java.util.ArrayList;
public class SpeechToTextService extends Service {
private String TAG = "STT";
float fPeak;
boolean bBegin;
long lCheckTime;
long lTimeout = 2000;
@Override
public void onCreate() {
super.onCreate();
bBegin = false;
fPeak = -999; //Only to be sure it's under ambient RmsDb.
final SpeechRecognizer sr = SpeechRecognizer.createSpeechRecognizer(getApplicationContext());
sr.setRecognitionListener(new RecognitionListener() {
@Override
public void onReadyForSpeech(Bundle bundle) {
Log.i(TAG, "onReadyForSpeech");
}
@Override
public void onBeginningOfSpeech() {
bBegin = true;
Log.i(TAG, "onBeginningOfSpeech");
}
@Override
public void onRmsChanged(float rmsDb) {
if(bBegin) {
if (rmsDb > fPeak) {
fPeak = rmsDb;
lCheckTime = System.currentTimeMillis();
}
if (System.currentTimeMillis() > lCheckTime + lTimeout) {
Log.i(TAG, "DONE");
sr.destroy();
}
}
//Log.i(TAG, "rmsDB:"+rmsDb);
}
@Override
public void onBufferReceived(byte[] buffer) {
Log.i(TAG, "onBufferReceived");
}
@Override
public void onEndOfSpeech() {
Log.i(TAG, "onEndOfSpeech");
}
@Override
public void onError(int error) {
Log.i(TAG, "onError:" + error);
}
@Override
public void onResults(Bundle results) {
ArrayList data = results.getStringArrayList(
SpeechRecognizer.RESULTS_RECOGNITION);
String sTextFromSpeech;
if (data != null) {
sTextFromSpeech = data.get(0).toString();
} else {
sTextFromSpeech = "";
}
Log.i(TAG, "onResults:" + sTextFromSpeech);
}
@Override
public void onPartialResults(Bundle bundle) {
lCheckTime = System.currentTimeMillis();
ArrayList data = bundle.getStringArrayList(
SpeechRecognizer.RESULTS_RECOGNITION);
String sTextFromSpeech;
if (data != null) {
sTextFromSpeech = data.get(0).toString();
} else {
sTextFromSpeech = "";
}
Log.i(TAG, "onPartialResults:" + sTextFromSpeech);
}
@Override
public void onEvent(int eventType, Bundle params) {
Log.i(TAG, "onEvent:" + eventType);
}
});
Intent iSRIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
iSRIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
iSRIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
iSRIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getPackageName());
iSRIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "en-US");
iSRIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "en-US");
sr.startListening(iSRIntent);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
オフラインのみのソリューション:
同じ問題が発生しました(Androidシステムは、onPartialResults()
がトリガーされた後、onEndOfSpeech()
を介してスピーチのトランスクリプトを生成するのに25秒かかりました。
私は次のコードを試しましたが、うまくいきました:
Intent.putExtra
(
RecognizerIntent.EXTRA_PREFER_OFFLINE,
true
);
このソリューションは私のアプリで機能し、オンラインモードを使用しない場合は機能する場合があります(電話の設定で言語パッケージをダウンロードしました)。