Android의 오프라인 음성 인식 (JellyBean)


78

Google이 타사 앱에 대해 Google Now에서 오프라인 음성 인식을 사용할 수 있도록 한 것 같습니다. Utter라는 앱 에서 사용 중 입니다.

이 오프라인 음성 녹음으로 간단한 음성 명령을 수행하는 방법에 대한 구현을 본 사람이 있습니까? 일반 SpeechRecognizer API를 사용하면 자동으로 작동하나요?


1
언어를 다운로드하는 한 코드를 변경할 필요가 없습니까?
Ruchir Baronia

답변:


73

Google은 해당 검색 업데이트에서 오프라인 인식을 조용히 활성화했지만 아직 SpeechRecognizer 클래스 내에서 사용할 수있는 API 또는 추가 매개 변수가 없습니다 . {이 게시물 하단의 편집 참조} 이 기능은 추가 코딩없이 사용할 수 있지만 작동을 시작하려면 사용자의 장치를 올바르게 구성해야하며 여기에 문제가 있으며 많은 개발자가 왜 많은지 상상할 수 있습니다. 그들이 '뭔가 빠졌다'고 가정합니다.

또한 Google은 하드웨어 제약으로 인해 특정 Jelly Bean 기기에서 오프라인 인식을 사용하지 못하도록 제한했습니다. 이것이 적용되는 장치는 문서화되어 있지 않으며 실제로 문서화되어 있지 않으므로 사용자를위한 기능 구성은 시행 착오의 문제임이 입증되었습니다. 그것은 곧바로 효과가 있습니다 – 그렇지 않은 사람들에게는 이것이 제가 그들에게 제공하는 '가이드'입니다.

  1. 기본 Android 음성 인식기가 Samsung / Vlingo가 아닌 Google로 설정되어 있는지 확인합니다.
  2. Google 음성 검색 설정에서 이미 설치 한 모든 오프라인 인식 파일을 제거합니다.
  3. Android 애플리케이션 설정으로 이동하여 Google 검색 및 Google 음성 검색 애플리케이션에 대한 업데이트를 제거 할 수 있는지 확인합니다.
  4. 위의 작업을 수행 할 수없는 경우 Play 스토어로 이동하여 옵션이 있는지 확인하십시오.
  5. 재부팅 (2, 3 또는 4를 달성 한 경우)
  6. Play 스토어에서 Google 검색 및 Google 음성 검색을 업데이트합니다 (3 개 또는 4 개를 달성했거나 업데이트가있는 경우).
  7. 재부팅 (6을 달성 한 경우)
  8. 영어 영국 오프라인 언어 파일 설치
  9. 재부팅
  10. 완전히 사용하십시오 ! 연결되어
  11. 비행기 모드로 전환하여 사용해보세요
  12. 일단 작동하면 영어 US와 같은 다른 언어의 오프라인 인식도 작동하기 시작합니다.

편집 : 일시적으로 장치 로케일을 영어 영국으로 변경하면 일부에서 작동하는 것으로 보입니다.

일부 사용자는 여전히 작동을 시작하기 전에 여러 번 재부팅해야한다고보고했지만 결국에는 모두 도달합니다. 종종 트리거가 무엇인지, Google 검색 APK 내부에있는 키에 대해 설명 할 수없는 경우가 많으 므로 공개 도메인이 아닙니다. 또는 AOSP의 일부입니다 .

내가 설정할 수있는 한, Google은 오프라인 또는 온라인 인식 사용 여부를 결정하기 전에 연결 가용성을 테스트합니다. 처음에 연결을 사용할 수 있지만 응답 전에 연결이 끊어진 경우 Google은 연결 오류를 제공하고 오프라인으로 대체하지 않습니다. 부수적으로, 네트워크 합성 음성에 대한 요청이 있으면 실패해도 오류가 제공되지 않습니다.-당신은 침묵을 얻습니다.

Google 검색 업데이트는 Google Now의 추가 기능을 활성화하지 않았으며 실제로 인터넷 연결없이 사용하려고하면 오류가 발생합니다. 나는 그 능력이 보이는 것처럼 조용히 철회 될 것이기 때문에 생산에 의존해서는 안 될지 궁금해서 이것을 언급했습니다.

SpeechRecognizer 클래스 사용을 시작하려는 경우 관련하여 처리하기 위해 자체 구현이 필요한 매우 중요한 버그 가 있다는 점에주의하십시오.

특별히 offline = true를 요청할 수 없기 때문에 데이터 연결을 조작하지 않고는이 기능을 제어 할 수 없습니다. 쓰레기. 그렇게 간단한 것을 활성화하지 않은 이유를 묻는 수백 개의 사용자 이메일을 받게됩니다!

수정 : API 레벨 23 이후 Google 인식 서비스가 준수하는 것으로 보이는 EXTRA_PREFER_OFFLINE 새 매개 변수가 추가되었습니다 .

위의 내용이 도움이되기를 바랍니다.


이것은 나를 위해 잘 작동하고 구현하기가 매우 쉬웠습니다. 이 샘플을 시작점으로 사용했습니다. jameselsey.co.uk/blogs/techblog/...
rmooney

@brandall 내가 인식하는 언어를 선택할 수 있는지 궁금합니다. 오프라인 언어 파일이 이제 내 언어 (베트남어)를 지원합니다! 내 언어 (베트남어)에 대해 오프라인 음성 인식을 수행하는 앱을 만들고 싶습니다! 가능할까요 ?? 감사합니다!
truongnm 2014 년

1
@truongmn-도움이 되나요? stackoverflow.com/q/10538791/1256219 그렇지 않은 경우 새 질문을하고 여기에 연결하면 제가 도울 수 있는지 알아 볼게요
brandall 2014 년

Kitkat 4.4를 실행하는 Samsung Galaxy Grand Prime에서는 응용 프로그램 관리자에서 Google 검색 (및 Google+) 앱을 비활성화 한 다음 "백그라운드 데이터 제한"(또는 사용 가능한 연결이 없는지 확인)을 다시 활성화해야했습니다. Google 검색 (및 Google+) 앱 (사용 중지하기 직전에 해당 앱에 대한 모든 데이터를 삭제해야 할 수도 있음). 앱이 활성화 된 상태에서 "백그라운드 데이터 제한"을 켜려고했을 때 마이크가 다이얼러에 표시되지 않았습니다. 연결 (또는 제한)없이 다시 활성화하면 오프라인 사용이 강제됩니다.
Shelby Moore III


20

https://stackoverflow.com/a/17674655/2987828 답변 이 이미지와 함께 사용자에게 보내는 가이드를 개선하고 싶습니다 . "그렇지 않은 사람들에게는 이것이 제가 그들에게 제공하는 '가이드'입니다."라는 문장입니다. 개선하고 싶습니다.

사용자는 다음 이미지에서 파란색으로 강조 표시된 4 개의 버튼을 클릭해야합니다.

Android 애플리케이션 설정으로 이동하여 언어 및 입력을 선택하고 Google 보이스 입력 설정 수정, 오프라인 음성 인식 다운로드를 선택하고 모두 탭에서 언어를 선택하십시오.

그런 다음 사용자는 원하는 언어를 선택할 수 있습니다. 다운로드가 완료되면 네트워크 연결을 끊고 키보드의 "마이크"버튼을 클릭해야합니다.

그것은 나를 위해 일했습니다 (android 4.1.2), 그런 다음 재부팅하지 않고 언어 인식이 즉시 작동했습니다. 이제 터미널 에뮬레이터의 쉘에 명령을 지시 할 수 있습니다! 그리고 ASUS의 padfone 2에서 온라인보다 오프라인에서 두 배 더 빠릅니다.

이러한 이미지는 stackoverflow.com/a/21329845/2987828에 속성이 필요한 cc by-sa 3.0에 따라 라이센스가 부여됩니다. 따라서이 속성과 함께이 이미지를 어디에나 추가 할 수 있습니다.

(이것은 stackoverflow.com의 모든 이미지와 텍스트에 대한 표준 정책입니다)


18

Android에서 간단하고 유연한 오프라인 인식은 오픈 소스 음성 인식 툴킷 인 CMUSphinx에 의해 구현됩니다. 순전히 오프라인에서 작동하며 빠르고 구성 가능합니다. 예를 들어 키워드를 지속적으로 수신 할 수 있습니다.

여기에서 최신 코드와 튜토리얼을 찾을 수 있습니다 .

2019 년 업데이트 : 시간이 빨라지고 CMUSphinx는 더 이상 정확하지 않습니다. 대신 Kaldi 툴킷을 사용해 보는 것이 좋습니다. 데모는 여기에 있습니다 .


1
방금 데모를 시도했으며 꽤 잘 작동합니다. 빠르고 사용하기 쉽습니다.
Micer

2
안녕하세요, CMUSphinx는 인도 억양 영어에서도 작동합니까?
Lucifer

1
@Kedarnath 그것은 그들의 목록에서 높은 것 같습니다, 여기 여론 조사를 참조하십시오 : cmusphinx.sourceforge.net
Jerther

감사합니다. 지금 사용해보세요!
Hermandroid

아랍어에서 작동합니까? 아랍어에서 작동하는 것을 알고 있습니까?
Youssef Sherif

7

요컨대, 구현이 아니라 설명입니다.

Google은 타사 앱에 오프라인 음성 인식을 제공하지 않았습니다. 오프라인 인식은 키보드를 통해서만 액세스 할 수 있습니다. Ben Randall (utter! 개발자)은 Android Police의 기사에서 해결 방법을 설명합니다.

나는 내 자신의 키보드를 구현했고 Google 보이스 타이핑과 사용자 기본 키보드와 보이지 않는 편집 텍스트 필드와 투명한 활동을 전환하여 입력을 얻었습니다. 더러운 해킹!

오프라인 음성 입력은 IME 또는 시스템 응용 프로그램 (내 루트 해킹)에 의해서만 트리거 될 수 있기 때문에 이것이 유일한 방법 이었습니다. 다른 유형의 인식 API는… 트리거하지 않고 서버 오류로 인해 실패했습니다. … 해결 방법에 많은 작업이 낭비되었습니다! 하지만 적어도 나는 구현할 준비가되어 있었다 ...

에서 철저한! Jelly Bean에서 오프라인 음성 인식을 활용하는 최초의 비 IME 앱이라고 주장


4
나는 그가 최신 업데이트 전에했던 일이라고 생각했습니다. "Randall은 Utter!가 이제 개발자가 다양한 응용 프로그램에서 오프라인 인식을 사용할 수 있도록 업데이트 된 SpeechRecognizer를 사용하는 반면, 이전 오프라인 음성 입력 코드 인 Recognizerintent에는 유효한 IME 토큰이 필요하다고 설명했습니다."
rmooney

3

오프라인에서는 onPartialResults를 사용하고 온라인에서는 onResults를 사용하여 오프라인 기능으로 음성 서비스를 성공적으로 구현했습니다.


그것에 대해 더 많이 알 수 있습니까? 여기에 관련 버그가 게시되어 있습니다. stackoverflow.com/questions/32866239/…
Rao의

2

나는 이것을 다루고 있었고 당신의 언어에 대한 오프라인 패키지를 설치해야한다는 것을 알았습니다. 내 언어 설정은 "Español (Estados Unidos)"이지만 해당 언어에 대한 오프라인 패키지가 없어서 모든 네트워크 연결을 끄면 RecognizerIntent에서 Google에 연결할 수 없다는 경고가 표시되고 언어를 다음으로 변경합니다. "영어 (미국)"(이미 오프라인 패키지가 있기 때문에) RecognizerIntent를 시작했습니다.

키 : 언어 설정 == 오프라인 음성 인식기 패키지


어떤 장치를 사용했는지 알 수 있습니까? 구글 장치보다는 지원합니까? 삼성, Asus 등과 같이 다른 장치에서는 지원하지 않고 오프라인으로 작업하고 있습니다.
Rao의

1

파일을 직접 다운로드하고 올바른 위치에 수동으로 설치하여 오프라인 음성 인식을 수동으로 설치할 수 있습니다. 이것은 Google 하드웨어 요구 사항을 우회하는 방법 일뿐입니다. 그러나 개인적으로 재부팅하거나 아무것도 할 필요가 없었습니다. 단순히 영국으로 변경하고 다시 시작했습니다.


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

이것이 미래에 누군가를 도울 수 있기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.