Reconocimiento de voz sin conexión en Android (JellyBean)

78

Parece que Google ha hecho que el reconocimiento de voz sin conexión esté disponible en Google Now para aplicaciones de terceros. Está siendo utilizado por la aplicación llamada Utter .

¿Alguien ha visto alguna implementación de cómo hacer comandos de voz simples con esta grabación de voz sin conexión? ¿Utiliza la API SpeechRecognizer normal y funciona automáticamente?

rmooney
fuente
1
Entonces, mientras descarguemos el idioma, ¿no necesitamos cambiar nuestro código?
Ruchir Baronia

Respuestas:

73

Google habilitó silenciosamente el reconocimiento fuera de línea en esa actualización de búsqueda, pero (hasta ahora) no hay API o parámetros adicionales disponibles dentro de la clase SpeechRecognizer . {Ver Editar en la parte inferior de esta publicación} La funcionalidad está disponible sin codificación adicional, sin embargo, el dispositivo del usuario deberá configurarse correctamente para que comience a funcionar y aquí es donde radica el problema y me imagino por qué muchos desarrolladores suponga que "les falta algo".

Además, Google ha restringido el uso del reconocimiento fuera de línea para ciertos dispositivos Jelly Bean debido a limitaciones de hardware. No se documenta a qué dispositivos se aplica esto, de hecho, no se documenta nada, por lo que configurar las capacidades para el usuario ha demostrado ser una cuestión de prueba y error (para ellos). Funciona para algunos de inmediato - Para aquellos que no lo hace, esta es la 'guía' que les proporciono.

  1. Asegúrese de que el Reconocimiento de voz de Android predeterminado esté configurado en Google, no en Samsung / Vlingo
  2. Desinstale cualquier archivo de reconocimiento sin conexión que ya haya instalado desde la configuración de búsqueda por voz de Google
  3. Vaya a la configuración de la aplicación de Android y vea si puede desinstalar las actualizaciones para las aplicaciones de búsqueda de Google y búsqueda por voz de Google.
  4. Si no puede hacer lo anterior, vaya a Play Store para ver si tiene la opción allí.
  5. Reiniciar (si lograste 2, 3 o 4)
  6. Actualice la Búsqueda de Google y la Búsqueda por voz de Google desde Play Store (si logró 3 o 4 o si hay una actualización disponible de todos modos).
  7. Reiniciar (si lograste 6)
  8. Instalar archivos de idioma sin conexión en inglés del Reino Unido
  9. Reiniciar
  10. ¡Utilice total! con una conexión
  11. Cambia al modo avión y pruébalo
  12. Una vez que esté funcionando, el reconocimiento fuera de línea de otros idiomas, como el inglés de EE. UU., También debería comenzar a funcionar.

EDITAR: Cambiar temporalmente la configuración regional del dispositivo a inglés del Reino Unido también parece impulsar esto para que funcione para algunos.

Algunos usuarios informaron que todavía tenían que reiniciar varias veces antes de que comenzara a funcionar, pero todos llegan allí eventualmente, a menudo inexplicablemente a cuál fue el disparador, cuya clave está dentro del APK de búsqueda de Google , por lo que no es de dominio público. o parte de AOSP .

Por lo que puedo establecer, Google prueba la disponibilidad de una conexión antes de decidir si usar el reconocimiento en línea o fuera de línea. Si una conexión está disponible inicialmente pero se pierde antes de la respuesta, Google proporcionará un error de conexión, no volverá a estar fuera de línea. Como nota al margen, si se ha realizado una solicitud para la voz sintetizada de red, no se proporciona ningún error si falla: se obtiene silencio.

La actualización de la Búsqueda de Google no habilitó funciones adicionales en Google Now y, de hecho, si intenta usarlo sin conexión a Internet, se producirá un error. Menciono esto mientras me preguntaba si la habilidad se retiraría tan silenciosamente como parecía y, por lo tanto, no debería confiarse en la producción.

Si tiene la intención de comenzar a usar la clase SpeechRecognizer, tenga en cuenta que hay un error bastante importante asociado, que requiere su propia implementación para manejarlo.

No poder solicitar específicamente offline = true , hace que controlar esta función sea imposible sin manipular la conexión de datos. Basura. Recibirá cientos de correos electrónicos de usuarios preguntándole por qué no ha habilitado algo tan simple.

EDITAR: Desde el nivel de API 23, se ha agregado un nuevo parámetro EXTRA_PREFER_OFFLINE al que parece adherirse el servicio de reconocimiento de Google.

Espero que lo anterior ayude.

Brandall
fuente
Esto funciona muy bien para mí y fue muy fácil de implementar. Usé esta muestra aquí como punto de partida. jameselsey.co.uk/blogs/techblog/…
rmooney
@brandall Me pregunto si puedo elegir el idioma en el que hago el reconocimiento. ¡El archivo de idioma sin conexión admite mi idioma (vietnamita) ahora! ¡Quiero crear una aplicación que haga reconocimiento de voz sin conexión para mi idioma (vietnamita)! ¿¿Es eso posible?? ¡Muy agradecido!
truongnm
1
@truongmn - ¿Esto ayuda? stackoverflow.com/q/10538791/1256219 Si no es así, haz una nueva pregunta y
enlázame
En mi Samsung Galaxy Grand Prime con Kitkat 4.4, tuve que deshabilitar las aplicaciones de Búsqueda de Google (y Google+) desde el Administrador de aplicaciones, luego activar "Restringir datos de fondo" (o asegurarme de que no tenía una conexión disponible), luego volver a habilitar las aplicaciones de Búsqueda de Google (y Google+) (posiblemente también tuve que borrar todos los datos de esas aplicaciones justo antes de desactivarlas). Mientras que cuando intenté activar "Restringir datos en segundo plano" mientras esas aplicaciones estaban habilitadas, el micrófono no se mostraba en el marcador. Aparentemente, la reactivación sin conexión (o restringida) fuerza el uso de fuera de línea.
Shelby Moore III
Hola, ayúdame en esto stackoverflow.com/questions/32866239/…
Rao's
20

Me gustaría mejorar la guía que la respuesta https://stackoverflow.com/a/17674655/2987828 envía a sus usuarios, con imágenes. Es la frase "Para aquellos que no lo hacen, esta es la 'guía' que les proporciono". que quiero mejorar.

El usuario debe hacer clic en los cuatro botones resaltados en azul en estas imágenes:

Vaya a la configuración de la aplicación de Android, seleccione Idiomas y entrada, editar la configuración de escritura por voz de Google, seleccione Descargar reconocimiento de voz sin conexión, seleccione sus idiomas en la pestaña TODOS.

Luego, el usuario puede seleccionar los idiomas que desee. Cuando finalice la descarga, debe desconectarse de la red y luego hacer clic en el botón "micrófono" del teclado.

Me funcionó (Android 4.1.2), luego el reconocimiento de idioma funcionó de inmediato, sin reiniciar. ¡Ahora puedo dictar instrucciones al shell de Terminal Emulator! Y es dos veces más rápido sin conexión que en línea, en un padfone 2 de ASUS.

Estas imágenes tienen licencia cc by-sa 3.0 y se requiere atribución a stackoverflow.com/a/21329845/2987828; por lo tanto, puede agregar estas imágenes en cualquier lugar junto con esta atribución.

(Esta es la política estándar de todas las imágenes y textos en stackoverflow.com)

usuario2987828
fuente
18

CMUSphinx, un conjunto de herramientas de reconocimiento de voz de código abierto, implementa un reconocimiento fuera de línea simple y flexible en Android. Funciona puramente fuera de línea, rápido y configurable. Puede escuchar continuamente palabras clave, por ejemplo.

Puede encontrar el último código y tutorial aquí .

Actualización en 2019 : el tiempo pasa rápido, CMUSphinx ya no es tan preciso. Recomiendo probar el kit de herramientas Kaldi en su lugar. La demostración está aquí .

Nikolay Shmyrev
fuente
1
Acabo de probar la demostración y funciona bastante bien. Rápido y fácil de usar.
Micer
2
Hola, ¿CMUSphinx también funciona para inglés con acento indio?
Lucifer
1
@Kedarnath parece que está en lo alto de su lista, vea la encuesta aquí: cmusphinx.sourceforge.net
Jerther
Gracias, probándolo ahora!
Hermandroid
¿Funciona para árabe? ¿Conoces alguno que funcione para árabe?
Youssef Sherif
7

En resumen, no tengo la implementación, sino la explicación.

Google no puso el reconocimiento de voz sin conexión a disposición de las aplicaciones de terceros. Solo se puede acceder al reconocimiento sin conexión a través del teclado. Ben Randall (¡el desarrollador de utter!) Explica su solución en un artículo en Android Police:

Había implementado mi propio teclado y estaba cambiando entre Google Voice Typing y el teclado predeterminado de los usuarios con un campo de texto de edición invisible y Actividad transparente para obtener la entrada. ¡Hack sucio!

Esta era la única forma de hacerlo, ya que la escritura por voz sin conexión solo podía activarse mediante un IME o una aplicación del sistema (ese era mi truco raíz). El otro tipo de API de reconocimiento ... no lo activó y simplemente falló con un error del servidor. … ¡Mucho trabajo perdido para mí en la solución! Pero al menos estaba listo para la implementación ...

¡De Utter! Afirma ser la primera aplicación sin IME en utilizar el reconocimiento de voz sin conexión en Jelly Bean

Leon Joosse
fuente
4
Pensé que eso es lo que dijo que solía hacer antes de la última actualización. Después de su cita: "Randall continuó explicando que Utter! Ahora usa SpeechRecognizer, que se ha actualizado para permitir a los desarrolladores usar el reconocimiento fuera de línea en una variedad de aplicaciones, mientras que Recognizerintent, el código de escritura por voz sin conexión anterior, requería un token IME válido".
rmooney
3

Implementé con éxito mi Speech-Service con capacidades fuera de línea usando onPartialResults cuando estaba fuera de línea y onResults cuando estaba en línea.

P. Stresow
fuente
¿Puedo saber más sobre esto, por favor? Tengo un error relacionado con la publicación aquí stackoverflow.com/questions/32866239/…
Rao's
2

Estaba lidiando con esto y me di cuenta de que necesita instalar el paquete sin conexión para su idioma. Mi configuración de idioma era "Español (Estados Unidos)", pero no hay un paquete sin conexión para ese idioma, por lo que cuando desactivé toda la conectividad de red recibí una alerta de RecognizerIntent que decía que no se puede comunicar con Google, luego cambio el idioma a "English (US)" (porque ya tengo el paquete sin conexión) y lancé RecognizerIntent, simplemente funcionó.

Teclas: Configuración de idioma == Paquete de reconocimiento de voz sin conexión

Akino
fuente
¿Puedo saber qué dispositivo usaste? ¿Es compatible en lugar de dispositivo de Google? Como Samsung, Asus, etc. Estoy trabajando en él y sin conexión no es compatible con otro dispositivo.
Rao's
1

Aparentemente, es posible instalar manualmente el reconocimiento de voz sin conexión descargando los archivos directamente e instalándolos en las ubicaciones correctas manualmente. Supongo que esta es solo una forma de eludir los requisitos de hardware de Google. Sin embargo, personalmente no tuve que reiniciar ni nada, simplemente cambiar a Reino Unido y viceversa lo hice.

Riju Chatterjee
fuente
0

A continuación se da un ejemplo de trabajo,

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

Para más detalles,

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

Espero que esto ayude a alguien en el futuro.

Sachin Varma
fuente