Google 语音识别超时

Google Speech Recognition timeout

我正在开发一个基于语音识别的 Android 应用程序。

直到今天,一切都运行良好且及时,例如我会启动我的语音识别器,说话,最多 1 或 2 秒内应用程序收到结果。

这是一个非常可接受的用户体验。

那今天要等十几秒才能出识别结果

我试过设置以下 EXTRAS,none 其中有明显差异

RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS

我一直在不断更改我的应用程序,但是 none 这些更改与语音识别器有关。

有什么方法可以减少语音识别器从 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()

编辑 - 显然已在 2016 年 8 月即将发布的版本中修复 您可以test the beta 确认。

这是 Google 'Now' V6.0.23.* 版本中的一个错误,并且在最新的 V6.1.28.*

中仍然存在

自从发布 V5.11.34.* Google 以来,SpeechRecognizer 的实现一直被错误所困扰。

您可以使用 this gist 复制其中的许多内容。

您可以使用此 BugRecognitionListener 解决其中的一些问题。

我已将这些直接报告给 Now 团队,所以他们知道了,但到目前为止,还没有任何问题得到解决。 Google 现在没有外部错误跟踪器,因为它不是 AOSP 的一部分,所以恐怕您无法加注星标。

您详细说明的最新错误几乎使它们的实现无法使用,正如您正确指出的那样,控制语音输入时间的参数被忽略了。根据 the documentation

Additionally, depending on the recognizer implementation, these values may have no effect.

是我们应该期待的……

如果您不说话或发出任何可检测到的声音,识别将无限期地继续。

我目前正在创建一个项目来复制这个新错误和所有其他错误,我将在此处转发并 link 很快。

编辑 - 我希望我可以创建一个解决方法,使用部分或不稳定结果的检测作为触发器来了解用户仍在说话。一旦他们停止,我可以在一段时间后手动调用 recognizer.stopListening()

不幸的是,stopListening() 也被破坏了,实际上并没有停止识别,因此没有解决方法。

围绕上述尝试破坏识别器并仅依赖部分结果直到那一点(当破坏识别器时 onResults() 未被调用)未能产生可靠的实现,除非你是.

在 Google 解决此问题之前我们无能为力。您唯一的出路是发送电子邮件至 apps-help@google.com 报告问题,并希望他们收到的数量能给他们一个推动......

更新:根据我今天的测试,这个错误似乎终于得到解决,不再需要这样做了。留下它以防它将来再次坏掉。根据我的测试,语音超时工作正常。

好吧,我知道这很丑陋,但它似乎可以使用 onPartialResults(我理解 onPartialResults 的陷阱,但我已经尝试了几次,直到 Google 修复了这个荒谬的错误!) 我还没有对它进行详尽的测试(我会 post 返回结果,因为我将在应用程序中使用它)但我迫切需要一个解决方案。基本上,我使用 onRmsChanged 来触发用户说完话,假设当 RmsDb 低于峰值并且 2 秒内没有 onPartialResults 时,我们就完成了。

我不喜欢的一件事是摧毁 SR 会发出两声呃哦的哔哔声。 FWIW 和 YMMV。请post任何改进!

注意:如果您要重复使用它,请不要忘记重置 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;
    }
}

我找到的最佳解决方案(直到 google 修复了错误)是进入 Google App 应用程序信息,然后单击 "Uninstall Updates" 按钮。这将删除对该应用程序所做的所有直接影响语音识别器的更新,基本上将其返回工厂。

** 在我们知道它已修复之前停止自动更新可能是个好主意。 ***注意:这是仅适用于开发人员的解决方案,显然,如果您在商店中有应用程序,这对您没有帮助。抱歉...

更新:

如果有人在设置语音识别时遇到问题,您可以使用我构建的 Droid Speech library 来克服 android 中的语音超时问题。


我的应用完全依赖于语音识别功能,Google 投下炸弹。从目前的情况来看,我相信这至少在不久的将来不会得到解决。

目前,我确实找到了让 google 语音识别按预期提供语音结果的解决方案。

注意:此方法与上述解决方案略有不同。

此方法的主要目的是确保在 onPartialResults() 中捕获用户说出的整个单词。

在正常情况下,如果用户在给定实例中说出多个单词,则响应时间太快,部分结果往往只会得到第一个单词,而不是完整的结果。

因此,为了确保每个单词都在 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);

注意!这仅适用于在线模式。 启用听写模式并禁用部分结果:

intent.putExtra("android.speech.extra.DICTATION_MODE", true);
intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, false);

在听写模式下,speechRecognizer 仍会调用 onPartialResults(),但您应该将部分部分视为最终结果。

仅离线解决方案:

我遇到了同样的问题(Android 触发 onEndOfSpeech() 后,系统用了 25 秒的时间通过 onPartialResults() 生成演讲的转录本。

我已经尝试了以下代码并且有效:

Intent.putExtra
(
    RecognizerIntent.EXTRA_PREFER_OFFLINE,
    true
);

此解决方案适用于我的应用程序,如果您不使用在线模式,它可能也适用于您(我通过 phone 设置下载了语言包)。