首页 文章

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

提问于
浏览
78

看起来谷歌已经从Google即时版为第三方应用程序提供了离线语音识别功能 . 它被the app named Utter使用 .

有没有人看过如何使用这个离线语音rec进行简单的语音命令的任何实现?您是否只使用常规的SpeechRecognizer API并自动运行?

8 回答

  • 20

    谷歌在该搜索更新中悄然启用了离线识别功能,但SpeechRecognizer class中尚未提供API或其他参数 . 该功能可用,无需额外编码,但是用户的设备需要正确配置才能开始工作,这就是问题所在,我想为什么很多开发人员都认为他们“缺少某些东西” .

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

    • 确保默认的Android语音识别器设置为Google而非Samsung / Vlingo

    • 从Google语音搜索设置中卸载您已安装的所有脱机识别文件

    • 转到Android应用程序设置,看看是否可以卸载Google搜索和Google语音搜索应用程序的更新 .

    • 如果您无法执行上述操作,请转到Play商店,看看您是否有选项 .

    • 重启(如果你达到2,3或4)

    • 从Play商店更新Google搜索和Google语音搜索(如果您已达到3或4,或者无论如何都有更新) .

    • 重启(如果你达到了6)

    • 安装英国英国脱机语言文件

    • 重启

    • 使用带有连接的utter!

    • 切换到飞行模式并尝试一下

    • 一旦它正常工作,其他语言的离线识别,例如英语美国也应该开始工作 .

    编辑:暂时将设备区域设置更改为英语英国似乎也启动了这项工作 .

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

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

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

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

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

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

    希望以上有所帮助 .

  • 70

    我想通过图像改进答案https://stackoverflow.com/a/17674655/2987828发送给用户的指南 . 这是我要改进的句子"For those that it doesn't, this is the ‘guide’ I supply them with." .

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

    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

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

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

  • 3

    总之,我没有实施,而是解释 .

    谷歌没有为第三方应用程序提供离线语音识别功能 . 离线识别只能通过键盘访问 . Ben Randall(utter的开发者!)在Android Police的一篇文章中解释了他的解决方法:

    我已经实现了自己的键盘,并在Google Voice Typing和用户默认键盘之间切换,其中包含一个不可见的编辑文本字段和透明的Activity来获取输入 . 肮脏的黑客!这是唯一的方法,因为离线语音输入只能由IME或系统应用程序触发(这是我的root hack) . 另一种类型的识别API ...没有触发它,只是因服务器错误而失败 . ...在解决方法上浪费了很多工作!但至少我已准备好实施......

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

  • 1

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

  • 16

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

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

  • 0

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

  • 7

    工作实例如下,

    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

    希望这将有助于将来的某些人 .

相关问题