看起来 Google 已经为第三方应用程序提供了 Google Now 的离线语音识别功能。它被名为 Utter 的应用程序使用。
有没有人见过如何使用这个离线语音记录执行简单的语音命令的任何实现?您是否只使用常规 SpeechRecognizer API 并且它会自动工作?
看起来 Google 已经为第三方应用程序提供了 Google Now 的离线语音识别功能。它被名为 Utter 的应用程序使用。
有没有人见过如何使用这个离线语音记录执行简单的语音命令的任何实现?您是否只使用常规 SpeechRecognizer API 并且它会自动工作?
Google 确实在该搜索更新中悄悄启用了离线识别,但SpeechRecognizer 类中(目前)还没有可用的 API 或其他参数。{参见本文底部的编辑}该功能无需额外编码即可使用,但是需要正确配置用户的设备才能开始工作,这就是问题所在,我想为什么很多开发人员假设他们“缺少某些东西”。
此外,由于硬件限制,Google 已限制某些 Jelly Bean 设备使用离线识别。这适用于哪些设备没有记录,事实上,没有任何记录,因此为用户配置功能已被证明是一个反复试验的问题(对他们来说)。它适用于某些人——对于那些不适用的人,这是我提供给他们的“指南”。
编辑:暂时将设备区域设置更改为英国英语似乎也开始了这对某些人的工作。
一些用户报告说他们仍然需要重新启动多次才能开始工作,但他们最终都到达了那里,通常莫名其妙地知道触发器是什么,其中的关键在Google 搜索 APK内,所以不在公共领域或AOSP的一部分。
据我所知,谷歌在决定使用离线还是在线识别之前测试连接的可用性。如果连接最初可用但在响应之前丢失,Google 将提供连接错误,它不会退回到离线状态。附带说明一下,如果已发出对网络合成语音的请求,则如果失败,则不会提供任何错误——您会得到静默。
Google 搜索更新在 Google Now 中没有启用任何附加功能,事实上,如果您尝试在没有互联网连接的情况下使用它,它会出错。我提到这一点是因为我想知道该功能是否会像它出现的那样悄悄地被撤回,因此不应该在生产中依赖它。
如果您打算开始使用 SpeechRecognizer 类,请注意,有一个与之相关的相当大的错误,需要您自己的实现来处理。
无法专门请求offline = true,如果不操纵数据连接,就无法控制此功能。垃圾。您将收到数百封用户电子邮件,询问您为什么没有启用如此简单的功能!
编辑:自 API 级别 23 以来,添加了一个新参数EXTRA_PREFER_OFFLINE,Google 识别服务似乎确实遵守该参数。
希望以上有所帮助。
我想改进答案https://stackoverflow.com/a/17674655/2987828发送给其用户的指南,并带有图像。就是这样一句话“对于那些没有的人,这是我提供给他们的‘指南’。” 我想改进。
用户应单击这些图像中以蓝色突出显示的四个按钮:
然后用户可以选择任何所需的语言。下载完成后,应断开网络连接,然后点击键盘上的“麦克风”按钮。
它对我有用(android 4.1.2),然后语言识别开箱即用,无需重新启动。我现在可以向终端仿真器的外壳发出指令了!在华硕的 padfone 2 上,离线速度比在线快两倍。
这些图像在 cc by-sa 3.0 下获得许可,需要归属于 stackoverflow.com/a/21329845/2987828;因此,您可以将这些图像与此属性一起添加到任何地方。
(这是 stackoverflow.com 上所有图像和文本的标准策略)
简而言之,我没有实现,但有解释。
谷歌没有为第三方应用提供离线语音识别功能。离线识别只能通过键盘访问。Ben Randall(utter! 的开发者)在 Android Police 的一篇文章中解释了他的解决方法:
我已经实现了自己的键盘,并在 Google Voice Typing 和用户默认键盘之间切换,使用不可见的编辑文本字段和透明的 Activity 来获取输入。肮脏的黑客!
这是唯一的方法,因为离线语音输入只能由 IME 或系统应用程序触发(这是我的 root hack)。另一种类型的识别 API……没有触发它,只是因为服务器错误而失败。......在解决方法上浪费了我很多工作!但至少我已经为实施做好了准备……
通过在离线时使用 onPartialResults 和在线时使用 onResults,我成功地实现了具有离线功能的语音服务。
我正在处理这个问题,我注意到您需要为您的语言安装离线包。我的语言设置是“Español (Estados Unidos)”,但该语言没有离线包,所以当我关闭所有网络连接时,我收到来自 RecognizerIntent 的警报,说无法访问 Google,然后我将语言更改为“英语(美国)”(因为我已经有离线包)并启动了它刚刚解决的识别器意图。
键:语言设置 == 离线语音识别器包
显然可以通过直接下载文件并手动将它们安装在正确的位置来手动安装离线语音识别。我想这只是绕过谷歌硬件要求的一种方法。但是,就我个人而言,我不必重新启动或任何其他操作,只需更改为 UK 并再次返回即可。
下面给出了工作示例,
我的服务类
public class MyService extends Service implements SpeechDelegate, Speech.stopDueToDelay {
public static SpeechDelegate delegate;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
try {
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
((AudioManager) Objects.requireNonNull(
getSystemService(Context.AUDIO_SERVICE))).setStreamMute(AudioManager.STREAM_SYSTEM, true);
}
} catch (Exception e) {
e.printStackTrace();
}
Speech.init(this);
delegate = this;
Speech.getInstance().setListener(this);
if (Speech.getInstance().isListening()) {
Speech.getInstance().stopListening();
} else {
System.setProperty("rx.unsafe-disable", "True");
RxPermissions.getInstance(this).request(permission.RECORD_AUDIO).subscribe(granted -> {
if (granted) { // Always true pre-M
try {
Speech.getInstance().stopTextToSpeech();
Speech.getInstance().startListening(null, this);
} catch (SpeechRecognitionNotAvailable exc) {
//showSpeechNotSupportedDialog();
} catch (GoogleVoiceTypingDisabledException exc) {
//showEnableGoogleVoiceTyping();
}
} else {
Toast.makeText(this, R.string.permission_required, Toast.LENGTH_LONG).show();
}
});
}
return Service.START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
//TODO for communication return IBinder implementation
return null;
}
@Override
public void onStartOfSpeech() {
}
@Override
public void onSpeechRmsChanged(float value) {
}
@Override
public void onSpeechPartialResults(List<String> results) {
for (String partial : results) {
Log.d("Result", partial+"");
}
}
@Override
public void onSpeechResult(String result) {
Log.d("Result", result+"");
if (!TextUtils.isEmpty(result)) {
Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onSpecifiedCommandPronounced(String event) {
try {
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
((AudioManager) Objects.requireNonNull(
getSystemService(Context.AUDIO_SERVICE))).setStreamMute(AudioManager.STREAM_SYSTEM, true);
}
} catch (Exception e) {
e.printStackTrace();
}
if (Speech.getInstance().isListening()) {
Speech.getInstance().stopListening();
} else {
RxPermissions.getInstance(this).request(permission.RECORD_AUDIO).subscribe(granted -> {
if (granted) { // Always true pre-M
try {
Speech.getInstance().stopTextToSpeech();
Speech.getInstance().startListening(null, this);
} catch (SpeechRecognitionNotAvailable exc) {
//showSpeechNotSupportedDialog();
} catch (GoogleVoiceTypingDisabledException exc) {
//showEnableGoogleVoiceTyping();
}
} else {
Toast.makeText(this, R.string.permission_required, Toast.LENGTH_LONG).show();
}
});
}
}
@Override
public void onTaskRemoved(Intent rootIntent) {
//Restarting the service if it is removed.
PendingIntent service =
PendingIntent.getService(getApplicationContext(), new Random().nextInt(),
new Intent(getApplicationContext(), MyService.class), PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
assert alarmManager != null;
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
super.onTaskRemoved(rootIntent);
}
}
更多细节,
希望这对将来的人有所帮助。