【问题标题】:Google Speech Recognition timeout谷歌语音识别超时
【发布时间】:2016-11-04 03:43:19
【问题描述】:

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

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

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

那么今天我必须等待十秒或更长时间才能获得识别结果。

我已尝试设置以下 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()

【问题讨论】:

  • 嗨@Hector,我在我的应用程序中遇到了同样的问题,并且有任何解决方案或解决时间延迟的问题。如果您已经解决了您的问题,请在评论中指导我您如何处理此问题。我已经在这里stackoverflow.com/q/38179290/4657065 发布了我的问题。提前致谢
  • 这似乎已经解决了,所以我在底部的条目应该不再需要了。
  • 对于不喜欢哔声的约翰史密斯,您可以通过将 STREAM_MUSIC 的音量设置为零来摆脱它。当然,如果您的应用程序暂停,您应该保存原始值并恢复它。我在自己的语音识别应用程序中使用它。我认为它可能仍在等待它认为它正在发出哔哔声:我在我的识别器中看到了死时间。确实,Google 应该提供一个选项来完全抑制哔哔声,而不是等待它。

标签: android speech-recognition voice-recognition google-voice-search


【解决方案1】:

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

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

自 V5.11.34.* 发布以来,Google 对 SpeechRecognizer 的实现一直存在错误。

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

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

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

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

此外,根据识别器的实现,这些值 可能没有效果。

是我们应该期待的......

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

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

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

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

围绕上述尝试销毁识别器并仅依赖部分结果直到该点(销毁识别器时onResults() 未被调用)未能产生可靠的实现,除非您是simply keyword spotting

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

【讨论】:

  • 为什么不尝试取消而不是停止监听?
  • @Hector cancel() 阻止 onResults() 被调用,因此在此之前您将依赖于部分或不稳定的结果。恐怕和毁灭一样的结果。
  • 我想出的解决方案(或者尽管它是为了加快获得结果)是请求部分结果,当我得到它们时,我又取消了,因为它们比完整结果返回得更快。如果没有返回部分结果,那么我会正常等待完整的结果。
  • @Hector 在我当前的实现中,如果我在部分或不稳定的结果中检测到我想要的语音stackoverflow.com/a/37033162/1256219,我也会取消识别。但是对于用户可能正在口述电子邮件等的情况,如果这些结果的规律性足以确定用户已经停止说话,那么依赖部分结果可能是一种解决方法。在我的测试中,这还不够成功,无法考虑将其作为生产解决方法。对于关键字发现,绝对没问题。
【解决方案2】:

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

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

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

【讨论】:

  • 它有效!我推荐此解决方案以进行快速临时修复
  • 这为我修好了!谢谢!这是最好的解决方案。
  • 这并没有解决我的问题。阅读段落时仍然会发生超时
  • 这个对当前的实现没有影响。
【解决方案3】:

更新:

以防万一有人在设置语音识别时遇到问题,您可以使用我为克服 android 中的语音超时问题而构建的Droid Speech library


我的应用完全依赖于语音识别功能,而 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);

【讨论】:

    【解决方案4】:

    我找到的最佳解决方案(直到 google 修复错误)是进入 Google App App 信息,然后点击“卸载更新”按钮。这将删除对该应用程序所做的所有对语音识别器有直接影响的更新,基本上将其恢复为出厂状态。

    **在我们知道它已修复之前停止自动更新可能是个好主意。 ***注意:这只是针对开发人员的解决方案,显然如果您在商店中有应用程序,这将无济于事。对不起...

    【讨论】:

    • 不过,这将删除用户对 Google Now 的所有功能,因此需要在此建议的同时向用户发出重大警告。
    • 这会杀死 android wear "ok google"(我试过):/
    【解决方案5】:

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

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

    我不喜欢这件事的一件事是摧毁 SR 会发出双 uh-oh 哔哔声。 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;
        }
    }
    

    【讨论】:

    • 我担心onRmsChanged() 也无法正常工作,这是我报告的错误之一gist.github.com/brandall76/…。有时在语音识别过程中根本无法调用。这也不是每次都可以复制的东西,这使得它成为一种不可靠的解决方法......
    • 我现在大部分时间都在我的应用程序中使用它来语音文本,它运行良好。我正在使用 sdk v24,所以我不知道这是否有帮助。我也只在MM上试过。我没有任何更低的设备。如果您可以使用 v24 sdk 测试我的代码并查看您的结果是否仍然粗略,我将不胜感激。
    • 我已经仔细检查过,但确认onRmsChanged() 绝对不是我需要的——这是在许多不同的设备/版本/sdk 变体上。如果您在设备上转到 Google 应用的应用信息,您运行的是什么版本?
    • 6.0.23.21.arm。 - 我刚刚将我更新的应用放到了 Play 商店(不是免费的,也不想无耻地推广),所以我们拭目以待!
    • 为你祈祷!为了使您的实现更加全面,请在此处查看问题github.com/Kaljurand/speechutils/issues/2
    【解决方案6】:

    仅离线解决方案:

    我也遇到过同样的问题(在onEndOfSpeech() 被触发后,Android 系统需要 25 秒才能通过onPartialResults() 生成演讲稿。

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

    Intent.putExtra
    (
        RecognizerIntent.EXTRA_PREFER_OFFLINE,
        true
    );
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多