Учим Андроид слушать…
Распознавание речи — процесс преобразования речевого сигнала в текстовый поток. Первое устройство для распознавания речи появилось в 1952 году, оно могло распознавать произнесённые человеком цифры. Современные телефоны могут намного больше. В этой статье я расскажу о том, как с помощью Голосового поиска Google Inc. научить ваши приложения слушать.
Немого теории. Андроид сам по себе не умеет распознавать речь. Поэтому, если у вас “голое” устройство с Андроидом на борту, то распознавать на нем ничего не получится. Как же тогда быть? Можно поискать стороннюю библиотеку для этих целей и добавить ее в проект (тернистый путь) или попросить другое приложение распознавать для нас речь (простой пусть). Мы пойдем по простому пути, следовательно, у нас на устройстве должно быть установлено хотя бы одно приложение способное обрабатывать специально созданный для такой задачи Intent с действием RecognizerIntent.ACTION_RECOGNIZE_SPEECH.
Одним из таких приложений является Голосовой поиск Google Inc. Работает оно просто замечательно, поддерживает различные языки. Для успешной работы требуется выход в интернет, так как сам процесс распознавания происходит где-то на серверах Google. При запуске приложения появляется Activity с парой управляющих кнопок (представлена на рисунке ниже), которая информирует пользователя о том, что надо говорить. Как только пользователь заканчивает говорить, диалог закрывается, а нам в приложение возвращается массив текстовых строк – распознанная речь.
Блок-схемы еще никто никто не отменял. Учитывая вышеизложенное, напрашивается следующая логика работы, представленная на схеме ниже.
Приступаем к реализации. Напишем программный код, который позволит максимально просто интегрировать голосовой поиск в наше приложение. Согласно представленной выше схеме, код должен делать следующее:
- принимать запрос на распознавание речи
- проверять наличие приложения способного распознавать речь.
- если распознавание доступно, то вызвать стороннее приложение для распознавания речи, получать результат
- если распознавание не доступно, то показать диалог запроса установки Голосового поиска Google и отправлять пользователя в маркет, если он захочет
Создадим класс, в котором реализуем логику для распознавания речи. Назовем этот класс SpeechRecognitionHelper. В классе объявим статичную, публичную функцию run, которая будет принимать запрос на запуск распознавания.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/** * Класс-помощник для распознавания речи */ public class SpeechRecognitionHelper { /** * Запускает процесс распознавания. Проверяет наличие Activity для распознавания речи. * Если Activity нет, отправляет пользователя в маркет установить Голосовой Поиск * Google. Если активи для распознавания есть, то отправляет Intent для ее запуска. * * @param ownerActivity Activity, которая инициировала процесс распознавания */ public static void run(Activity ownerActivity) { // проверяем есть ли Activity для распознавания if (isSpeechRecognitionActivityPresented(ownerActivity) == true) { // если есть - запускаем распознавание startRecognition(ownerActivity); } else { // если нет, то показываем уведомление что надо установить Голосовой Поиск Toast.makeText(ownerActivity, "Чтобы активировать голосовой поиск необходимо установить \"Голосовой поиск Google\"", Toast.LENGTH_LONG).show(); // начинаем процесс установки installGoogleVoiceSearch(ownerActivity); } } } |
Кроме функции run нам необходимо реализовать еще три функции:
- isSpeechRecognitionActivityPresented – проверяет установлено ли приложение способное распознавать речь
- startRecognition – формирует правильный Intent и запускает распознавание
- installGoogleVoiceSearch – инициирует процесс установки Голосового Поиска Google
Проверить установлено ли на устройстве приложение для распознавания речи можно с помощью метода queryIntentActivities класса PackageManager. Данный метод выдает список Activity, которые могут обработать указанный Intent. Получить экземпляр класса PackageManager можно с помощью функции getPackageManager. Вот что получилось:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/** * Проверяет наличие Activity способной выполнить распознавание речи * * @param ownerActivity Activity, которая запросила проверку * @return true - если есть, false - если такой Activity нет */ private static boolean isSpeechRecognitionActivityPresented(Activity ownerActivity) { try { // получаем экземпляр менеджера пакетов PackageManager pm = ownerActivity.getPackageManager(); // получаем список Activity способных обработать запрос на распознавание List activities = pm.queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0); if (activities.size() != 0) { // если список не пустой return true; // то умеем распознавать речь } } catch (Exception e) { } return false; // не умеем распознавать речь } |
Приступаем к реализации функции startRecognition. Данная функция должна сформировать правильный Intent для запуска Activity распознавания речи. О том как это сделать изучаем на страничке документации. Получаем следующую реализацию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * Отправляет Intent с запросом на распознавание речи * @param ownerActivity инициировавшая запрос Activity */ private static void startRecognitionActivity(Activity ownerActivity) { // создаем Intent с действием RecognizerIntent.ACTION_RECOGNIZE_SPEECH Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); // добавляем дополнительные параметры: intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Голосовой поиск Inforino"); // текстовая подсказка пользователю intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH); // модель распознавания оптимальная для распознавания коротких фраз-поисковых запросов intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); // количество результатов, которое мы хотим получить, в данном случае хотим только первый - самый релевантный // стартуем Activity и ждем от нее результата ownerActivity.startActivityForResult(intent, SystemData.VOICE_RECOGNITION_REQUEST_CODE); } |
При настройке параметров Intent’а мы указали: строку-подсказку для пользователя, которая отобразиться в диалоге запроса голосового ввода; модель распознавания – поисковый запрос; количество результатов – 1 (самый релевантный, другие нам в данном случае не нужны).
Переходим к реализации функции installGoogleVoiceSearch. Данная функция будет отображать диалог, в котором спросит у пользователя хотел ли они установить Голосовой Поиск Google и отправить его в маркет устанавливать его, если он захочет.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
/** * Запрашивает разрешение на установку Голосового Поиска Google, отображая диалог. Если разрешение * получено - направляет пользователя в маркет. * @param ownerActivity Activity инициировавшая установку */ private static void installGoogleVoiceSearch(final Activity ownerActivity) { // создаем диалог, который спросит у пользователя хочет ли он // установить Голосовой Поиск Dialog dialog = new AlertDialog.Builder(ownerActivity) .setMessage("Для распознавания речи необходимо установить \"Голосовой поиск Google\"") // сообщение .setTitle("Внимание") // заголовок диалога .setPositiveButton("Установить", new DialogInterface.OnClickListener() { // положительная кнопка // обработчик нажатия на кнопку Установить @Override public void onClick(DialogInterface dialog, int which) { try { // создаем Intent для открытия в маркете странички с приложением // Голосовой Поиск имя пакета: com.google.android.voicesearch Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.google.android.voicesearch")); // настраиваем флаги, чтобы маркет не попал к в историю нашего приложения (стек Activity) intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); // отправляем Intent ownerActivity.startActivity(intent); } catch (Exception ex) { // не удалось открыть маркет // например из-за того что он не установлен // ничего не поделаешь } }}) .setNegativeButton("Отмена", null) // негативная кнопка .create(); dialog.show(); // показываем диалог } |
В принципе все готово. У нас есть механизм проверки наличия требуемой нам Activity для распознавания речи, мы можем запустить эту Activity, можем запросить у пользователя разрешения на установку Голосового Поиска и при положительно ответе отправить его в маркет. Единственное что мы еще не умеем – это получать результаты распознавания голоса.
Отправка запроса на распознавание речи была неспроста реализована с помощью функции startActivityForResult, указывающий на то, что мы хотим получить результат запущенной нами ативити. Чтобы его получить требуется в нашей основной ативити, из которой мы отправили запрос на распознавание речи, переопределить метод OnActivityResult и получить в нем результаты распознавания голоса. Делается это следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Обработчик события получения результатов работы Activity, которых мы ждали @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { // если это результаты распознавания речи // и процесс распознавания прошел успешно if (requestCode == SystemData.VOICE_RECOGNITION_REQUEST_CODE && resultCode == RESULT_OK) { // получаем список текстовых строк - результат распознавания // строк может быть несколько, так как не всегда удается точно распознать речь // более релевантные результаты идут в начале списка ArrayList matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); // все, в массиве matches мы получили результаты... отобразим в уведомлении самый релевантный if (matches.size() > 0) Toast.makeText(this, matches.get(0), Toast.LENGTH_LONG).show(); } super.onActivityResult(requestCode, resultCode, data); } |
Вот теперь действительно все готово. Созданный класс SpeechRecognitionHelper позволяет вызовом всего лишь одной функции run выполнить запрос на распознавание речи, обработав ситуации отсутствия соответствующей Activity и установку Голосового Поиска из маркета. Все что вам нужно для реализации распознавания – это добавить в ваш проект созданный класс, вызвать в нужном месте функцию run и реализовать логику обработки результатов, правильно переопределив метод onActivityResult Activity, которая инициировала процесс.
Дополнительную информацию по теме можно получить на сайте разработчиков Андроид. Есть полезный пример, в котором показано, как реализовать распознавание речи, и что важно – в нем рассказано, как получить список доступных языков. Данный список понадобиться вам, если вы хотите распознать язык отличный от языка выбранной локали пользователя. Чтобы быстро интегрировать речевой ввод в ваше приложение можете скачать и свободно использовать код класса SpeechRecognitionHelper.
Если статья оказалась вам полезной или почему на сайте есть реклама
4 комментариев
ZipovUA Сообщает:
02.11.2012 на 3:33 пп (UTC 0 )
Доброго времени суток.
1) Есть уточняющий вопрос: как настроить распознавание речи на конкретный язык (английский / украинский / русский)
)
2) Возможно ли каким нибудь образом увеличить словарный запас гугла нужным словарем? (например слово FireBall у меня не распознаётся
PandaСoder Сообщает:
04.11.2012 на 6:06 пп (UTC 0 )
1) по умолчанию используется язык локали, если нужен другое – передайте параметр EXTRA_LANGUAGE
2) нельзя, научитесь правильно говорить фаербол )
анатолий Сообщает:
03.02.2014 на 2:25 пп (UTC 0 )
распознование речи фаербол
Михаил Сообщает:
28.02.2014 на 12:21 пп (UTC 0 )
1) Вопрос – если хочется воспользоваться не гугловским распознавателем а сторонним, например Голосовой поиск Плюс, то как явно указать на это. Потому что я так понял программа ищет наличие люого распознавателя и ессно выбирает гугловский.
2) Также хотелось бы в связи с предыдущим вопросом поинтересоваться – реально ли программу распознавать не слова а наборы букв на заданном языке (например отдельные слоги) – а то как то совсем не хочется реализовывать такую программу самому