Android中的离线语音识别(JellyBean)

时间:2013-07-12 14:14:11

标签: android speech-recognition offline speech-to-text google-now

Google似乎已经为Google第三方应用提供了离线语音识别功能。它由the app named Utter使用。

有没有人看到过如何使用此离线语音记录执行简单语音命令的任何实现?您是否只使用常规的SpeechRecognizer API并自动运行?

8 个答案:

答案 0 :(得分:71)

Google在该搜索更新中悄然启用了离线识别功能,但SpeechRecognizer class中尚未提供API或其他参数。 {请参阅本文底部的编辑} 该功能无需额外编码即可使用,但是需要正确配置用户的设备才能开始工作,这就是问题所在而且我会想象为什么很多开发人员都认为他们“错过了什么”。

此外,由于硬件限制,Google限制某些Jelly Bean设备使用离线识别。哪些适用的设备没有记录,事实上,没有任何文件记录,因此为用户配置功能已经证明是一个试验和错误的问题(对他们而言)。它适用于一些直接 - 对于那些它没有,这是我提供给他们的'指南'。

  1. 确保默认的Android Voice Recogniser设置为Google not not 三星/ Vlingo
  2. 卸载已安装的所有脱机识别文件 来自Google语音搜索设置
  3. 转到Android应用程序设置,看看是否可以卸载 Google搜索和Google语音搜索的更新 的应用程序。
  4. 如果您无法执行上述操作,请转到Play商店,看看您是否拥有             选择那里。
  5. 重新启动(如果您达到2,3或4)
  6. 从Play商店更新Google搜索和Google语音搜索(如果 你达到3或4或者无论如何都有更新。)
  7. 重启(如果你达到了6)
  8. 安装英国英国脱机语言文件
  9. 重新启动
  10. 使用utter!连接
  11. 切换到飞行模式并试一试
  12. 一旦工作,其他语言的离线识别,  比如英国美国也应该开始工作。
  13. 编辑:暂时将设备区域设置更改为英国英语似乎也启动了这项工作。

    有些用户报告说他们在开始工作之前仍然需要多次重启,但他们最终都会到达那里,往往莫名其妙地触发了什么是触发器,其中的关键是Google Search APK内部,所以不属于公共领域或AOSP的一部分。

    根据我的建议,Google在决定是否使用离线或在线识别之前测试连接的可用性。如果连接最初可用但在响应之前丢失,则Google将提供连接错误,它不会退回到脱机状态。作为旁注,如果已经发出了对网络合成语音的请求,则如果失败则没有提供错误 - 您会沉默。

    Google搜索更新在Google即时中未启用任何其他功能,实际上如果您尝试在没有互联网连接的情况下使用它,则会出错。我提到这一点,因为我想知道这种能力是否会像它出现的那样安静地撤回,因此不应该依赖于生产。

    如果您打算开始使用SpeechRecognizer类,请注意,它有一个漂亮的major bug,需要您自己的实现才能处理。

    无法专门请求 offline = true ,无需操作数据连接就无法控制此功能。垃圾。您将收到数百封用户电子邮件,询问您为何没有启用这么简单的内容!

    编辑:自API级别23以来,添加了一个新的参数EXTRA_PREFER_OFFLINE,Google认可服务似乎确实遵守该参数。

    希望以上有所帮助。

答案 1 :(得分:20)

我想通过图片改进答案https://stackoverflow.com/a/17674655/2987828向其用户发送的指南。这句话是“对于那些没有的人,这是我向他们提供的'指南'。”我想改进。

用户应在这些图像中单击蓝色突出显示的四个按钮:

Go to your Android Application Settings, select Languages and input, edit Settings of Google Voice typing, select Download Offline speech recognition,  select your languages in the ALL tab.

然后用户可以选择任何所需的语言。下载完成后,他应断开与网络的连接,然后单击键盘的“麦克风”按钮。

它适用于我(android 4.1.2),然后语言识别开箱即用,无需重启。我现在可以指示终端仿真器的shell指令!在华硕的padfone 2上,离线速度比在线快两倍。

这些图片是根据cc by-sa 3.0获得许可的,其归属地址为stackoverflow.com/a/21329845/2987828;因此,您可以将这些图像与此归属地一起添加到任何位置。

(这是stackoverflow.com上所有图片和文字的标准政策)

答案 2 :(得分:16)

Android上的简单灵活的离线识别是由开源语音识别工具包CMUSphinx实现的。它完全脱机,快速和可配置工作它可以持续监听关键字,例如。

您可以找到最新的代码和tutorial here

答案 3 :(得分:7)

简而言之,我没有实施,而是解释。

Google未向第三方应用提供离线语音识别功能。离线识别只能通过键盘访问。 Ben Randall(utter的开发者!)在Android Police的一篇文章中解释了他的解决方法:

  

我已经实现了自己的键盘,并在谷歌之间切换   语音输入和用户默认键盘具有不可见的编辑功能   文本字段和透明Activity获取输入。肮脏的黑客!

     

这是唯一的方法,因为离线语音输入只能是   由IME或系统应用程序触发(这是我的root hack)。   另一种类型的识别API ...没有触发它,只是失败了   服务器错误。 ...在解决方法上浪费了很多工作!   但至少我已准备好实施......

来自Utter! Claims To Be The First Non-IME App To Utilize Offline Voice Recognition In Jelly Bean

答案 4 :(得分:3)

我通过离线时使用onPartialResults并在线时使用onResults成功实现了具有离线功能的语音服务。

答案 5 :(得分:2)

我正在处理此事,我注意到您需要为您的语言安装离线软件包。我的语言设置是“Español(Estados Unidos)”,但是没有该语言的离线包,所以当我关闭所有网络连接时,我收到来自RecognizerIntent的警告说无法访问Google,然后我将语言更改为“英语(美国)”(因为我已经有了离线软件包)并启动了它刚刚解决的识别器内容。

键:语言设置==离线语音识别器包

答案 6 :(得分:1)

通过直接下载文件并手动将它们安装在正确的位置,显然可以手动安装离线语音识别。我想这只是绕过谷歌硬件要求的一种方式。 但是,就我个人而言,我没有重新启动或任何事情,只需改为英国,然后又回来了。

答案 7 :(得分:0)

工作示例如下,

MyService.class

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);
  }
}

有关更多详细信息,

  

https://github.com/sachinvarma/Speech-Recognizer

希望这会对以后的人有所帮助。