Тайм-аут распознавания речи Google

Я разрабатываю приложение для Android, которое основано на распознавании речи.

до сегодняшнего дня все работало нормально и своевременно, например, я бы начал распознаватель речи, говорить, и в течение 1 или 2 секунд максимум приложение получило результаты.

Это был очень приемлемый пользовательский опыт.

тогда сегодня я теперь должен ждать десять или более секунд, прежде чем результаты распознавания будут доступны.

Я попробовал установить следующие дополнения, ни один из которых не делает заметной разницы

RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS
RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS

Я постоянно менял свое приложение, однако ни одно из этих изменений не было связано с распознавателем речи.

есть ли какой-либо метод, который я могу использовать, чтобы уменьшить время между переключением распознавателя речи от onBeginningOfSpeech() to onResults()?

вот пример того, сколько времени это занимает

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()

6 ответов


редактировать - по-видимому, был исправлен в августе 2016 года предстоящего выпуска вы можете тест бета для подтверждения.

Это ошибка с выпуском Google ' Now ' V6.0.23.* и сохраняется в последней версии V6.1.28.*

С момента выпуска V5.11.34.* Реализация Google SpeechRecognizer был заражен ошибками.

можно использовать в этом суть для репликации многих из них.

вы можно использовать это BugRecognitionListener чтобы обойти некоторые из них.

Я сообщил об этом непосредственно команде Now, поэтому они знают, но пока ничего не исправлено. Нет внешнего трекера ошибок для Google Now, так как он не является частью AOSP, поэтому ничего вы не можете снимать, Я боюсь.

самая последняя ошибка, которую вы подробно описываете, делает их реализацию непригодной для использования, как вы правильно указываете, параметры для управления таймингами ввода речи игнорируемый. Который согласно документация:

кроме того, в зависимости от реализации распознавателя, эти значения может не иметь никакого эффекта.

это то, что мы должны ожидать......

распознавание будет продолжаться бесконечно, если вы не говорите или не делаете какой-либо обнаруживаемый звук.

в настоящее время я создаю проект для репликации этой новой ошибки и всех других, которые я перешлю и свяжу здесь вкратце.

редактировать - Я надеялся, что смогу создать обходной путь, который использует обнаружение частичных или нестабильных результатов в качестве триггера, чтобы знать, что пользователь все еще говорит. Как только они остановились, я мог вручную вызвать recognizer.stopListening() после определенного периода времени.

к сожалению, stopListening() также сломан и на самом деле не останавливает распознавание, поэтому для этого нет обходного пути.

попытки вокруг вышеуказанного, уничтожения распознавателя и полагаясь только на частичные результаты до этого момента (при уничтожении распознавателя onResults() не вызывается) не удалось создать надежную реализацию, если вы не просто ключевое слово spotting.

мы ничего не можем сделать, пока Google не исправит это. Ваш единственный выход по электронной почте apps-help@google.com сообщая о проблеме и надеясь, что объем, который они получают, дает им толчок.....


внимание! это работает только в онлайн режиме. Включить режим диктовки и отключить частичные результаты:

intent.putExtra("android.speech.extra.DICTATION_MODE", true);
intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, false);

в режиме диктовки speechRecognizer все равно вызовет onPartialResults() однако вы должны рассматривать частичные как окончательные результаты.


обновление:

на всякий случай, если у кого-то возникли проблемы с настройкой распознавания речи, вы можете использовать библиотека речи дроидов который я построил, чтобы преодолеть проблему тайм-аута речи в android.


мое приложение полностью зависело от функции распознавания голоса, и Google сбросить бомбу. Судя по всему, я считаю, что это не будет исправлено, по крайней мере, в ближайшем будущем.

в настоящее время я нашел решение, чтобы Google voice recognition доставлял результаты речи по назначению.

Примечание: этот подход немного отличается от вышеперечисленных решений.

основная цель этого метода - убедиться, что все слова, произнесенные пользователем, пойманы в onPartialResults().

в обычных случаях, если пользователь говорит более одного слова в данном экземпляре, время ответа слишком быстро, и частичные результаты будут чаще чем не получить только первое слово и не полный результат.

поэтому, чтобы убедиться, что каждое слово поймано в onPartialResults (), вводится обработчик для проверки задержки паузы пользователя, а затем фильтрует результаты. Также обратите внимание, что массив результатов onPartialResults() чаще всего будет иметь только один элемент.

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

лучшим решением я нашел (пока Google не исправляет ошибку) был поехать в Google App App информация, а затем нажмите на кнопку "Удалить обновления". Это удалит все обновления, сделанные в этом приложении, которое напрямую влияет на распознаватель речи, в основном возвращая его на завод.

**вероятно, хорошая идея остановить автоматические обновления, пока мы не узнаем, что это исправления. ***Примечание: это решение только для разработчиков, очевидно, если у вас есть приложение в магазине это не поможет тебе. Извиняюсь...


UPDATE: по состоянию на мое тестирование сегодня эта ошибка, похоже, была решена окончательно, и это больше не нужно. Оставляю его на случай, если он снова сломается в будущем. Из моих тестов тайм-аут речи работает нормально.

хорошо, я знаю, что это очень уродливо, но, похоже, работает с помощью onPartialResults (я понимаю gotchas с onPartialResults, но я пробовал это несколько раз, и это что-то, пока Google не исправит эту нелепую ошибку!) Я еще не исчерпывающе протестировал его (Я буду и публиковать результаты, как я буду использовать это в приложении), но я отчаянно нуждался в решении. В принципе, я использую onRmsChanged для запуска этого пользователя, предполагая, что когда RmsDb падает ниже пика и нет onPartialResults в течение 2 секунд, мы закончили.

единственное, что мне не нравится в этом, это уничтожение SR делает двойной звуковой сигнал. FWIW и YMMV. Пожалуйста, опубликуйте любые улучшения!

Примечание: Если вы собираетесь использовать это повторно, не забудьте сброс bBegin и fPeak! Также вам нужно будет воссоздать SR (либо onStartCommand, либо stop и start 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;
    }
}

решение только для офлайн:

я столкнулся с той же проблемой (система Android заняла 25 секунд, чтобы получить транскрипт речи через onPartialResults() после onEndOfSpeech() срабатывает.

Я пробовал следующий код, и он работал:

Intent.putExtra
(
    RecognizerIntent.EXTRA_PREFER_OFFLINE,
    true
);

Это решение работает для моего приложения, и это может работать для вас, если вы не используете онлайн-режиме (я скачал языковой пакет через настройки телефона).