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 设置下载了语言包)。
我正在开发一个基于语音识别的 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 设置下载了语言包)。