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

avatar
50calrevolver
8 апреля 2018 в 09:33
2019
2
3

Я создал простое приложение для Android для управления реле, подключенным к моему Raspberry Pi. Я использовал кнопки, а также базовое распознавание голоса, чтобы активировать эти кнопки и включать/выключать соответствующий релейный канал.

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

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

Вот мой существующий код, очень простое средство распознавания голоса, которое позволит мне включать и выключать кнопки для различных устройств, подключенных к реле:

public void micclick(View view) {
        if(view.getId()==R.id.mic)
        {promptSpeechInput();}
}

private void promptSpeechInput() {
    Intent i= new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
    i.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
    i.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
    i.putExtra(RecognizerIntent.EXTRA_PROMPT,"Speak!");
    try{
        startActivityForResult(i,100);

    }
    catch (ActivityNotFoundException a)
    {
        Toast.makeText(MainActivity.this,"Sorry your device doesn't support",Toast.LENGTH_SHORT).show();
    }
}
public void onActivityResult(int requestCode, int resultCode, Intent i) {
    super.onActivityResult(requestCode, resultCode, i);
    String voicetxt;
    switch (requestCode) {
        case 100:
            if (resultCode == RESULT_OK && i != null) {
                ArrayList<String> result2 = i.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
                voicetxt = result2.get(0);
                if (voicetxt.equals("fan on")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton1.setChecked(true);
                    result.append("Fan: ").append(toggleButton1.getText());
                    sc.onRelayNumber="a";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("fan of")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton1.setChecked(false);
                    result.append("Fan: ").append(toggleButton1.getText());
                    sc.onRelayNumber = "a_off";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("light on")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton2.setChecked(true);
                    result.append("Light: ").append(toggleButton2.getText());
                    sc.onRelayNumber = "b";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("light off")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton2.setChecked(false);
                    result.append("Light: ").append(toggleButton2.getText());
                    sc.onRelayNumber = "b_off";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("air conditioner on")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton3.setChecked(true);
                    result.append("AC: ").append(toggleButton3.getText());
                    sc.onRelayNumber = "c";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("air conditioner of")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton3.setChecked(false);
                    result.append("AC: ").append(toggleButton3.getText());
                    sc.onRelayNumber = "c_off";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("heater on")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton4.setChecked(true);
                    result.append("Heater: ").append(toggleButton4.getText());
                    sc.onRelayNumber = "d";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("heater off")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton4.setChecked(false);
                    result.append("Heater: ").append(toggleButton4.getText());
                    sc.onRelayNumber = "d_off";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
            }
            break;
    }
}

Я хочу добиться той же функциональности, не нажимая кнопку. Обратите внимание, что я новичок в разработке приложений для Android. Если возможно, опишите использование внешних библиотек, если они необходимы, потому что я не думаю, что непрерывное распознавание возможно с помощью Google RecognizerIntent. Я предположил, что мне может понадобиться включить такие библиотеки, как CMUSphinx, но я не знаю, как это сделать.

Источник

Ответы (2)

avatar
bko
31 октября 2021 в 08:27
0

Вы можете заставить его реагировать на "дом, (пауза) включить свет", используя следующий метод (хотя он будет реагировать и на другие слова, а не только на "дом"):

Вы можете непрерывно записывать звук (но не в файл), используя класс AudioRecord, пока необработанные данные записи не сообщат вам, что вы обнаружили некоторый порог громкости (например, при произнесении «дом»). Когда вы обнаружите этот порог, вы продолжите запись, пока не будет по крайней мере 0,5 секунды тишины. В этот момент вы останавливаете запись и немедленно вызываете функцию speechRecognizer.StartListening. Затем пользователь услышит звуковой сигнал, и когда он услышит звуковой сигнал, он может сказать «включи свет».

Поэтому что-то вроде этого должно обеспечивать желаемую функциональность, хотя и не идеальную.

С уважением.

avatar
Vincent Elbert Budiman
13 апреля 2018 в 06:55
5

Есть несколько вещей, которые вы можете сделать для режима непрерывного распознавания/диктовки. Вы можете использовать распознавание речи Google из самого андроида, это не рекомендуется для непрерывного распознавания (как указано на https://developer.android.com/reference/android/speech/SpeechRecognizer.html)

Реализация этого API, скорее всего, будет передавать аудио на удаленный серверы для распознавания речи. Таким образом, этот API не предназначен для использования для непрерывного распознавания, что потребовало бы значительный объем батареи и пропускная способность.

Но если вам это действительно нужно, вы можете найти обходной путь, создав свой собственный класс и унаследовав IRecognitionListener. (это я писал на xamarin-android, синтаксис очень похож на родной андроид)

public class CustomRecognizer : Java.Lang.Object, IRecognitionListener, TextToSpeech.IOnInitListener
{
    private SpeechRecognizer _speech;

    private Intent _speechIntent;


    public string Words;


    public CustomRecognizer(Context _context)
    {
        this._context = _context;
        Words = "";
        _speech = SpeechRecognizer.CreateSpeechRecognizer(this._context);
        _speech.SetRecognitionListener(this);
        _speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
        _speechIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
        _speechIntent.PutExtra(RecognizerIntent.ActionRecognizeSpeech, RecognizerIntent.ExtraPreferOffline);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1000); 
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1000);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 1500);
    }

    void startover()
    {
        _speech.Destroy();
        _speech = SpeechRecognizer.CreateSpeechRecognizer(this._context);
        _speech.SetRecognitionListener(this);
        _speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1000);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1000);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 1500);
    StartListening();
    }
    public void StartListening()
    {
        _speech.StartListening(_speechIntent);
    }

    public void StopListening()
    {
        _speech.StopListening();
    }

    public void OnBeginningOfSpeech()
    {

    }

    public void OnBufferReceived(byte[] buffer)
    {
    }

    public void OnEndOfSpeech()
    {

    }

    public void OnError([GeneratedEnum] SpeechRecognizerError error)
    {
        Words = error.ToString();
        startover();
    }

    public void OnEvent(int eventType, Bundle @params)
    {
    }

    public void OnPartialResults(Bundle partialResults)
    {
    }

    public void OnReadyForSpeech(Bundle @params)
    {
    }

    public void OnResults(Bundle results)
    {

        var matches = results.GetStringArrayList(SpeechRecognizer.ResultsRecognition);
        if (matches == null)
            Words = "Null";
        else
            if (matches.Count != 0)
            Words = matches[0];
        else
            Words = "";

        //do anything you want for the result
        }
        startover();
    }

    public void OnRmsChanged(float rmsdB)
    {

    }

    public void OnInit([GeneratedEnum] OperationResult status)
    {
        if (status == OperationResult.Error)
            txtspeech.SetLanguage(Java.Util.Locale.Default);
    }


}

Чтобы вызвать это действие:

void StartRecording()
    {
        string rec = PackageManager.FeatureMicrophone;

        if (rec != "android.hardware.microphone")
        {
            // no microphone, no recording. Disable the button and output an alert
            Toast.MakeText(this, "NO MICROPHONE", ToastLength.Short);
        }
        else
        {

            //you can pass any object you want to connect to your recognizer here (I am passing the activity)
            CustomRecognizer voice = new CustomRecognizer(this);
            voice.StartListening();

        }
    }

Не забудьте запросить разрешение на использование микрофона!

Объяснение :

— это уберет раздражающее сообщение «нажмите, чтобы начать запись»

.

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

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

-Распознавание Google не очень хорошо подходит для голосовой команды, так как языковая модель - "предложения [lang]", поэтому вы не можете ограничить слово, и в результате Google всегда будет пытаться составить "хорошее предложение".

Для лучшего результата и UX я действительно рекомендую вам использовать Google Cloud API (но он должен быть онлайн и стоит дорого), второе предложение — CMUSphinx / PocketSphinx, это открытый исходный код, может работать в автономном режиме, но вы должны делать все вручную

Преимущество PocketSphinx:

  1. Вы можете создать свой собственный словарь
  2. Совместимость с автономным режимом

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

  4. Вы можете получить результат в режиме реального времени, открыв "PartialResult"

Недостаток PocketSphinx: вам придется делать все вручную, от настройки вашей акустической модели, словаря, языковой модели, порога и т. д. (излишнее, если вы хотите что-то простое).

thilim9
11 октября 2020 в 14:09
0

В моем случае я хочу остановить загрузку всплывающего окна Google Talk и постоянно запускать прослушиватель при нажатии кнопки. Как я могу это сделать без использования распознавания речи?