Je développe une application Android basée sur la reconnaissance vocale.
Jusqu'à aujourd'hui, tout fonctionnait bien et dans les délais, par exemple. Je commençais ma reconnaissance vocale, parlais et, en 1 ou 2 secondes maximum, l’application recevait les résultats.
Ce fut une expérience utilisateur TRES acceptable.
Aujourd'hui, je dois maintenant attendre dix secondes ou plus avant que les résultats de la reconnaissance ne soient disponibles.
J'ai essayé de régler les extras suivants, dont aucun ne fait la différence
RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS
Je modifie continuellement mon application, mais aucun de ces changements n'était lié à la reconnaissance vocale.
Existe-t-il une méthode que je peux utiliser pour réduire le délai entre le passage de la fonction de reconnaissance vocale de onBeginningOfSpeech()
à onResults()
?
Voici un exemple de combien de temps cela prend
07-01 17:50:20.839 24877-24877/com.voice I/Voice: onReadyForSpeech()
07-01 17:50:21.614 24877-24877/com.voice I/Voice: onBeginningOfSpeech()
07-01 17:50:38.163 24877-24877/com.voice I/Voice: onEndOfSpeech()
EDIT - A apparemment été corrigé dans la version à venir d'août 2016 Vous pouvez tester la version bêta _ _ pour confirmer.
Il s'agit d'un bogue lié à la publication de la version 6.0.23. * De Google 'Now' et persiste dans la dernière version V6.1.28. *.
Depuis la publication de la V5.11.34. * La mise en œuvre de la variable SpeechRecognizer
par Google était encombrée de bogues.
Vous pouvez utiliser this Gist pour en répliquer plusieurs.
Vous pouvez utiliser ce BugRecognitionListener pour contourner certains d'entre eux.
Je les ai signalés directement à l'équipe Now, ils sont donc au courant, mais rien n'a encore été corrigé. Il n’existe pas de traqueur de bogues externe pour Google Now, car il ne fait pas partie de l’APSP, vous avez donc peur de rien.
Le bogue le plus récent que vous décrivez rend assez bien leur implémentation inutilisable. Comme vous le signalez à juste titre, les paramètres permettant de contrôler le minutage des entrées vocales sont ignorés. Lequel selon la documentation :
De plus, selon l’implémentation du logiciel de reconnaissance, ces valeurs peut avoir aucun effet.
est quelque chose que nous devrions nous attendre ......
La reconnaissance continuera indéfiniment si vous ne parlez pas ou ne produisez aucun son détectable.
Je suis en train de créer un projet pour reproduire ce nouveau bogue et tous les autres, que je vais vous transmettre et mettre en lien ici sous peu.
EDIT - J'espérais pouvoir créer une solution de contournement utilisant la détection des résultats partiels ou instables comme déclencheur pour savoir que l'utilisateur parlait toujours. Une fois qu'ils se sont arrêtés, je pouvais appeler manuellement recognizer.stopListening()
après une période donnée.
Malheureusement, stopListening()
est également défectueux et n'arrête pas la reconnaissance. Il n'y a donc pas de solution de contournement.
Les tentatives visant à détruire le dispositif de reconnaissance et à ne s’appuyer que sur les résultats partiels jusqu’à ce point (lorsqu’on détruit le dispositif de reconnaissance, onResults()
n’est pas appelé) n’ont pas abouti à une implémentation fiable, sauf si vous êtes simplement la détection de mots clés .
Nous ne pouvons rien faire jusqu'à ce que Google répare ce problème. Votre seul moyen consiste à envoyer un e-mail à l'adresse [email protected] en signalant le problème et en espérant que le volume reçu .....
REMARQUE! cela ne fonctionne qu'en mode en ligne. Activez le mode dictée et désactivez les résultats partiels:
intent.putExtra("Android.speech.extra.DICTATION_MODE", true);
intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, false);
En mode dictée, speechRecognizer appelle toujours onPartialResults()
, mais vous devez traiter les partiels comme des résultats finaux.
METTRE À JOUR:
Juste au cas où quelqu'un aurait du mal à configurer la reconnaissance vocale, vous pouvez utiliser Droid Speech library que j'ai construit pour résoudre le problème du délai d'attente de la parole dans Android.
Mon application était entièrement dépendante de la fonction de reconnaissance vocale et Google a lancé une bombe. À en juger par les choses, je crois que cela ne serait pas réglé du moins dans un proche avenir.
Pour le moment, j'ai trouvé une solution permettant à la reconnaissance vocale de Google de fournir les résultats de la parole comme prévu.
Note: Cette approche varie légèrement des solutions mentionnées ci-dessus.
L'objectif principal de cette méthode est de s'assurer que tous les mots prononcés par l'utilisateur sont interceptés par onPartialResults ().
Dans des cas normaux, si un utilisateur parle plus d'un mot à une instance donnée, le temps de réponse est trop rapide et les résultats partiels obtiendront le plus souvent le premier mot et non le résultat complet.
Donc, pour s'assurer que chaque mot est attiré par onPartialResults (), un gestionnaire est introduit pour vérifier le délai de pause de l'utilisateur, puis filtrer les résultats. Notez également que le tableau de résultats de onPartialResults () aura le plus souvent un seul élément.
SpeechRecognizer userSpeech = SpeechRecognizer.createSpeechRecognizer(this);
Intent speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
speechIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName());
speechIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
speechIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, ModelData.MAX_VOICE_RESULTS);
Handler checkForUserPauseAndSpeak = new Handler();
Boolean speechResultsFound = false;
userSpeech.setRecognitionListener(new RecognitionListener(){
@Override
public void onRmsChanged(float rmsdB)
{
// NA
}
@Override
public void onResults(Bundle results)
{
if(speechResultsFound) return;
speechResultsFound = true;
// Speech engine full results (Do whatever you would want with the full results)
}
@Override
public void onReadyForSpeech(Bundle params)
{
// NA
}
@Override
public void onPartialResults(Bundle partialResults)
{
if(partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).size() > 0 &&
partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).get(0) != null &&
!partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).get(0).trim().isEmpty())
{
checkForUserPauseAndSpeak.removeCallbacksAndMessages(null);
checkForUserPauseAndSpeak.postDelayed(new Runnable()
{
@Override
public void run()
{
if(speechResultsFound) return;
speechResultsFound = true;
// Stop the speech operations
userSpeech.destroy();
// Speech engine partial results (Do whatever you would want with the partial results)
}
}, 1000);
}
}
@Override
public void onEvent(int eventType, Bundle params)
{
// NA
}
@Override
public void onError(int error)
{
// Error related code
}
@Override
public void onEndOfSpeech()
{
// NA
}
@Override
public void onBufferReceived(byte[] buffer)
{
// NA
}
@Override
public void onBeginningOfSpeech()
{
// NA
}
});
userSpeech.startListening(speechIntent);
La meilleure solution de contournement que j'ai trouvée (jusqu'à ce que Google corrige le bogue) consistait à accéder aux informations de l'application Google App, puis à cliquer sur le bouton "Désinstaller les mises à jour". Cela supprimera toutes les mises à jour effectuées sur cette application, qui ont un effet direct sur le système de reconnaissance vocale, en le renvoyant à l’usine.
** Probablement une bonne idée d'arrêter les mises à jour automatiques jusqu'à ce que nous sachions que cela a été corrigé . *** Remarque: il s'agit d'une solution réservée aux développeurs. Évidemment, si vous avez une application dans le magasin, cela ne vous aidera pas. Pardon...
MISE À JOUR: À la lumière de mes tests d’aujourd’hui, ce bogue semble avoir été résolu et ce n’est plus nécessaire. Laissant au cas où il se casse encore à l'avenir. D'après mes tests, le délai d'attente de la parole fonctionne normalement.
Ok, je sais que c'est TRÈS UGLY, mais cela semble fonctionner avec onPartialResults (je comprends les pièges avec onPartialResults mais je l'ai essayé plusieurs fois et c'est quelque chose jusqu'à ce que Google corrige ce bug ridicule!) Je ne l'ai pas testé de manière exhaustive pourtant (je vais et poster les résultats que je vais utiliser dans une application), mais j'étais désespéré pour une solution. Fondamentalement, j'utilise onRmsChanged pour déclencher la parole de l'utilisateur, en supposant que lorsque la valeur RmsDb tombe en dessous du maximum et qu'il n'y ait pas onPartialResults pendant 2 secondes, nous avons terminé.
La seule chose que je n'aime pas à ce sujet, c'est que SR détruit un double bip. FWIW et YMMV. S'il vous plaît poster des améliorations!
NOTE: Si vous comptez utiliser ceci à plusieurs reprises, n'oubliez pas de réinitialiser bBegin and fPeak! De plus, vous devrez recréer SR (soit onStartCommand, soit arrêter et redémarrer le service.)
import Android.app.Service;
import Android.content.Intent;
import Android.os.Bundle;
import Android.os.IBinder;
import Android.speech.RecognitionListener;
import Android.speech.RecognizerIntent;
import Android.speech.SpeechRecognizer;
import Android.support.annotation.Nullable;
import Android.util.Log;
import Java.util.ArrayList;
public class SpeechToTextService extends Service {
private String TAG = "STT";
float fPeak;
boolean bBegin;
long lCheckTime;
long lTimeout = 2000;
@Override
public void onCreate() {
super.onCreate();
bBegin = false;
fPeak = -999; //Only to be sure it's under ambient RmsDb.
final SpeechRecognizer sr = SpeechRecognizer.createSpeechRecognizer(getApplicationContext());
sr.setRecognitionListener(new RecognitionListener() {
@Override
public void onReadyForSpeech(Bundle bundle) {
Log.i(TAG, "onReadyForSpeech");
}
@Override
public void onBeginningOfSpeech() {
bBegin = true;
Log.i(TAG, "onBeginningOfSpeech");
}
@Override
public void onRmsChanged(float rmsDb) {
if(bBegin) {
if (rmsDb > fPeak) {
fPeak = rmsDb;
lCheckTime = System.currentTimeMillis();
}
if (System.currentTimeMillis() > lCheckTime + lTimeout) {
Log.i(TAG, "DONE");
sr.destroy();
}
}
//Log.i(TAG, "rmsDB:"+rmsDb);
}
@Override
public void onBufferReceived(byte[] buffer) {
Log.i(TAG, "onBufferReceived");
}
@Override
public void onEndOfSpeech() {
Log.i(TAG, "onEndOfSpeech");
}
@Override
public void onError(int error) {
Log.i(TAG, "onError:" + error);
}
@Override
public void onResults(Bundle results) {
ArrayList data = results.getStringArrayList(
SpeechRecognizer.RESULTS_RECOGNITION);
String sTextFromSpeech;
if (data != null) {
sTextFromSpeech = data.get(0).toString();
} else {
sTextFromSpeech = "";
}
Log.i(TAG, "onResults:" + sTextFromSpeech);
}
@Override
public void onPartialResults(Bundle bundle) {
lCheckTime = System.currentTimeMillis();
ArrayList data = bundle.getStringArrayList(
SpeechRecognizer.RESULTS_RECOGNITION);
String sTextFromSpeech;
if (data != null) {
sTextFromSpeech = data.get(0).toString();
} else {
sTextFromSpeech = "";
}
Log.i(TAG, "onPartialResults:" + sTextFromSpeech);
}
@Override
public void onEvent(int eventType, Bundle params) {
Log.i(TAG, "onEvent:" + eventType);
}
});
Intent iSRIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
iSRIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
iSRIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
iSRIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getPackageName());
iSRIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "en-US");
iSRIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "en-US");
sr.startListening(iSRIntent);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Solution pour hors ligne uniquement:
J'ai rencontré le même problème (le système Android a mis 25 secondes pour générer la transcription du discours via onPartialResults()
après le déclenchement de onEndOfSpeech()
.
J'ai essayé le code suivant et cela a fonctionné:
Intent.putExtra
(
RecognizerIntent.EXTRA_PREFER_OFFLINE,
true
);
Cette solution fonctionne pour mon application et peut l'être pour vous si vous n'utilisez pas le mode en ligne (j'ai téléchargé le package de langue via les paramètres du téléphone).