Голосовое управление на базе X-Control Dispatcher

В прошлой статье было описано как с помощь X-Control Dispatcher опрашивать устройство, к которому подключены термодатчики и которое имеет возможность управления двумя каналами. Температура отображалась на стрелочном приборе, а каналами можно было управлять с помощью галочки и кнопки. Но мы не постоянно торчим у компа, иногда лучше было бы просто попросить его включить канал или сообщить Вам температуру.

Задание

  • Сделать возможность голосового управления.
  • Программа должна по голосовой комманде включать/выключать нужный канал, а при запросе температуры сообщать температуру.
  • Автоматическая активация распознавания. Программа должна постоянно «слушать» и когда она услышит речь, отвечающую заданным критериям, она должна попытаться её распознать.
  • Программа должна «иметь имя», по которому к ней «Нужно обращаться». К примеру: «Алиса, включи канал 1».

Решение

Синтезация и, особенно, распознавание речи — довольно сложная задача, но Google и Yandex предоставляют нам свои сервисы для этих целей. Для X-Control Dispatcher было создано расширение Speech, позволяющее распознавать и синтезировать речь используя эти сервисы. У гугла это Speech API, у яндекса — SpeechKit Cloud. Оба они поддерживают как распознавание, так и синтезацию. Наперед скажу, что гугл делает это заметно лучше и быстрее яндекса.
Yandex. Вы должны зарегистрироваться в кабинете разработчика и получить API-ключ, который необходим для распознавания и синтезации. Для распознавания в бесплатном режиме разрешено до 10000 запросов в сутки.
Google. Вам так же нужно зарегистрироваться и получить API-ключ, который нужен только для распознавания, для синтезации можно даже не регистрироваться. В бесплатном режиме он поддерживает до 50 запросов на распознавание в сутки, но в реале получается значительно больше (где-то читал, что до 500). Как получить ключ, написано здесь.

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

Реализация

Качаем расширение Speech и делаем то, что написано в ReadMe.txt. После того, как скопировали содержимое в modules_lib, открываем modules_lib\SpeechDir\extension\extension.ini. Содержимое примерно такое:
[General]
libFileName=Speech.dll

recognitionServiceType=google
synthesisServiceType=google

google_key=AIzaSyCzcOFnw89KTCHmI3LbbbbGJrbwL-zjHc
yandex_key=9a2b6bb0-1adc-4004-9750-f2b9b36cfce6

speech_lang=ru-ru
yandex_speaker_name=zahar

  • recognitionServiceType. Сервис для распознавания. Может быть google или yandex.
  • synthesisServiceType. То же самое для синтезации.
  • google_key. API — ключ для гугла.
  • yandex_key. API — ключ для яндекса.
  • speech_lang. Язык (для улучшения распознавания и синтезации).
  • yandex_speaker_name. Имя спикера для синтезации через яндекс. Может быть zahar или jane.
При необходимости изменяем настройки и сохраняем.
Запускаем программу, на вкладке «Модули» добавляем новый модуль, называем его как-то (у меня Speech), в окне выбора библиотеки модуля выбираем Speech:

Окно опций:

Снизу группа «Синтезация». Здесь задается только громкость воспроизведения.
Распознавание. В самой верхней части мы видим уровень микрофона, когда будете говорить в него, этот уровень будет отклоняться. Вертикальная синяя линия — это нижний уровень для начала записи, его можно изменять ползунком «Минимальный уровень». Его нужно выставить так, чтобы когда нет никаких звуков, уровень не переваливал за эту черту. Когда программа услышит звук и уровень перевалит за эту черту, то сам уровень изменит цвет с зеленого на красный, это значит, что началась запись. Запустится таймер с интервалом, установленном в «Максимальное значение тишины» и будет сбрасываться постоянно при превышении минимального уровня, после того, как уровень микрофона не будет превышать минимальный уровень в течении максимального время тишины (когда говорить перестали), прога проверит продолжительность записанного звука и если она меньше больше «Минимального времени» и меньше «Максимального времени», то записанный звук будет передан на сервер для распознавания.
Заметка: за процессом записи, распознавания и синтезации Вы можете следить в окне «Отладка».
После распознавания речи сервером (если он её понял), он вернет одно или несколько вариантов текста, самое первое — это самое вероятное совпадение с по его мнению (почти всегда так и есть). Далее полученные варианты будут отфильтрованы с помощью «Префикса». Префикс — это слово, которое должно быть в самом начале, проще говоря, это то самое имя, по которому мы будем обращаться (ну чувствительно к регистру).
В принципе, можно было бы просто установить остальное содержание распознанной речи в компонент, но с учетом того, что сервер нам может передать несколько вариантов, есть возможность с помощью таблицы выбрать один с вариантов. Допустим, префикс у Вас «Алиса», Вы можете сказать «Алиса, включи канал» или «Алиса, включить канал», в этих двух случаях в компонент должно устанавливаться значение «включить канал». И даже если вы уверены, что будете всегда говорить только первую фразу, то сервер (с вероятностью 30-50%) вернет 2 и больше варианта, в которых будут эти 2 фразы. Будет произведено сравнение полученных фраз с теми, которые есть в таблице (столбик «Команда»). К примеру, «Количество совпадений» равно 1, вы получили от сервера 3 варианта, в этом случае, с командами таблицы будет сравниваться только первый вариант, если «Количество совпадений» равно 2, то будут сравниваться 2 первые варианта (с первой строкой таблицы будут сравниваться 2 первые варианта, если совпадений нет, то они будут сравниваться со второй строкой, затем с третей и т.д.). Если нашло совпадение, то его «Устанавливаемое значение» будет установлено на компонент. Если совпадений не найдено и стоит галочка «Если не найдено совпадение, устанавливать прямое значение», то самый первый вариант будет установлен в компонент.
Проще говоря, если таблица пуста, не указан префикс и стоит эта галка, то после распознавания всё содержимое первого варианта будет установлено в компонент, если указан префикс, то в компонент будет установлено всё, что после него. Если префикс «Алиса» и Вы скажите «Алиса, включи канал», то в компонент будет установлено «включи канал».

Компоненты:

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

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

Создадим виджет с двумя компонентами типа xwcLabel:

И подключим его к расширению:

Теперь распознанная фраза будет установлена в компонент виджета «rec». Можете проверить. Я говорю «Алиса, как поживаешь?»:


Собственно, больше нам трогать это расширение не нужно, все дальнейшие действия будут проходить через этот виджет (точней, через 2 его компонента).
В прошлой статье мы сделали виджет со шкалой и стрелкой термометра, кнопкой и галочкой для управления каналами.
Сейчас сделаем так, чтобы после фразы «Алиса, включи канал», включался канал 1, «Алиса, выключи канал» — выключался канал 1, а после «Алиса, температура», программа выговаривала температуру, которая установлена на этом виджете.

Для данных действий нам понадобится модуль «xtask_manager», он позволяет автоматизировать разные процессы. Модуль не с простых, чтобы у Вас появились понятия о нем, просьба посмотреть этот видос.

Алгоритм
У нас есть 4 переменные:
  1. rec. Подключена к компоненту виджета, в который записывается принятая фраза.
  2. syn. Подключена к компоненту виджета, который воспроизводит текст.
  3. temp. Подключен к компоненту термодатчика.
  4. ch. Подключен к компоненту канала.
При установке значения в компонент виджета rec, проверить, какой текст установился в rec:
  • включить канал. Устанавливаем ch в true
  • выключить канал. Устанавливаем ch в false
  • температура. Вообще, можно просто записать значение temp в syn, для лучше установить в syn такое значение: «Температура %temp% градусов».

Создаем новый модуль, библиотеку выбираем «xtask_manager».
Добавляем выше указанные переменные, подключаем к ним компоненты виджетов. Так же, сознаем триггер, который будет реагировать на установку значения в компонент «rec»:

В триггер добавим несколько условий и к ним команды. После всех настроек должно выглядеть примерно так:


Запускаем таск на выполнение (кнопка снизу посередине).

Готово!

Теперь программа реагирует на такие фразы:
  • Алиса, включи канал
  • Алиса, выключи канал
  • Алиса, температура

Пример
Ссылка на ютуб (когда вставляю через тег «видео», оно не отображается)

Исходники расширения

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

По поводу дизайна
В прошлой статье меня просили его переделать, ибо, насколько понял, он негативно действует на человеческую психику. К сожалению, у меня нет возможности вплотную им заняться, сейчас работаю исключительно над улучшением функционала программы. Но обязательно займусь им, когда проект «выйдет в люди».
  • +1
  • 22 апреля 2015, 21:43
  • MrMisha

Комментарии (30)

RSS свернуть / развернуть
я хочу предупредить, что он ориентирован на тех, кто кодить не умеет
А зачем в таком случае использовать "==" из С? Какой-то смысл этот дурацкий значок имеет только для программистов.

Алсо, сделай нормальную документацию. Искать нужный кусок в видео неудобно, да еще и видео сделано отвратительно. К съемке готовиться надо, а результат должен выглядеть как у sania_3, а не как у uni с его мычательными видушками.

(когда вставляю через тег «видео», оно не отображается)
Читай справку и делай точно так же, как там.
+1
  • avatar
  • Vga
  • 22 апреля 2015, 22:12
Было бы неплохо стартовый маркер («Алиса») пытаться предварительно проверить локально (пусть очень грубо, с кучей ложных срабатываний). Иначе, например при реализации «умного дома», все что я говорю (достаточно громко) будет отправляться на сервера для распознавания – что плохо по ряду причин.
+2
Угу, но для этого нужно, как минимум, распознать, хотя бы коряво.
0
Распознать действительно тяжело. Я подразумевал хранение голосового паттерна для «Алиса» и грубое сравнение начала фразы на соответствие этому паттерну. Это тоже не так просто, но проще чем распознавать.
0
Может и так, но ведь распознавание прекрасно работает даже с инетом в 5/3 мбит. Зачем создавать лишние проблемы?)))
0
Еще такой вопрос – эти API умеют работать по HTTPS?
0
Если я правильно понял вопрос, то да.
0
А почему Вы тогда не используете HTTPS (раз уж мы гоним весь голосов трафик на сервер для распознавания)? ЕМНИП, QNetworkRequest поддерживает HTTPS (или я ошибаюсь?).
0
Если Вы про HTTPS для web интерфейса, то только потому, что до него ещё руки не дошли.
0
Нет, я имел ввиду, почему бы не использовать HTTPS для работы с WEB API распознавания. Я не являюсь параноиком, но мне как-то не очень нравиться, что все что я говорю отправляется на сервер для распознавания по открытому каналу.

Да и Вам, по идее, запросто перейти на HTTPS, достаточно просто указать соответствующий протокол в УРЛ.

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

А то получится, поругался с женой, гугл этого наслушался, и потом в контекстной рекламе предлагает услуги адвоката для развода :) Я конечно утрирую но все же.
Кстати, а Гугл использует результаты распознавания для персонализации рекламы (как в других своих сервисах), там в EULA ничего об этом не сказано?
0
Так там и так используется HTTPS, как для гугла, так и для андекса.
Для Вас это хороший повод с женой не ругаться))).
А том, что гугл использует результаты для рекламы, я нигде не слышал, а если используют для шпионских целей, то врятле официально об этом сообщат.
0
Так там и так используется HTTPS

Упс, извиняюсь, не досмотрел (я просто увидел в коде… req.setUrl(QUrl(QString(«translate.google.com…, теперь понял, что это для синтеза, в распознавании https)

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

Я сомневаюсь, что моя персона интересна NSA:). А вот использовать данные для персонализации рекламы – Гугл вполне может, он такой…
0
Да, но опять же, официально они об этом врятле скажут.
0
Кстати, гугл при распознавания не цензуры эти слова заменяет звездочками, поэтому при ссоре с женой часть диалога будет отброшена.
0
Ну, хоть это это радует :)

А если серьёзно – то это странно. Если они уж предоставили API для распознавания голоса – то оно должно работать однозначно. Если мне нужна «цензура» – я могу ввести цензурирование на уровне моего приложения. От speech-to-text API я ожидаю именно распознавания, а не контроль морали :)

Но, из того что я нагуглил по speech-to-text API от гугла – фактически оно есть и вполне неплохо работает. Но официально (на уровне формализованного API и четко детерминированных условий его использования) пока информации нет…
0
Какой только херни не придумают, лишь бы просто выключатель не жмякнуть.
0
Ну, многие вещи в «умных домах» делаются не ради практической выгоды от автоматизации, а просто «потому что могу», или там ради «вызвать ВАУ-эффет у гостей» :) Хотя можно придумать и полезное практическое применение голосового интерфейс (первое что приходит в голову – инвалиды)
+1
С этими «умными домами» и «интернетами вещей» на каждом углу уже забываешь, что автоматизация действительно может быть умной и полезной (и, о ужас!, удобной и неглючной)…
0
С этими «умными домами» и «интернетами вещей»

Ну, это имя нарицательное и маркетинговое. На самом деле «умный дом» может вполне быть «умным и полезным». Я, например, активно занимался строительством велосипедов по мотивам «умного дома» just for fun. Но, потом сменил место жительства и монтировать систему мне стало лень, все девайсы остались пылиться на балконе. Об этом я пожалел уже пару раз (один раз, когда обокрали квартиру, второй – когда меня залил сосед сверху).

Вы, как всегда категоричны – если Вам не нравиться идея голосового интерфейса, значит это плохая идея :)

Я вот тоже не использую, например,«голосовой поиск от Гугл» и аналогичные вещи, но это не значит, что технология бесполезна. Как минимум – они сделали существеннй шаг в алгоритмах распознавания голоса. Пусть пока распознавание далеко от идеала – но «Москва не сразу строилась».
+1
Вы, как всегда категоричны – если Вам не нравиться идея голосового интерфейса, значит это плохая идея :)
Голосовой интерфейс далеко не всегда удобен, на самом деле. Скажем, фирма IBM прикрыла это направление (хотя продвинулась, пожалуй, дальше всех в этом направлении — OS/2 Warp 4.0 выпущенная в 1996-м году имела встроенные средства голосового ввода и управления). Эксперименты показали, что если ввод еще куда ни шло (иногда он даже очень удобен, например, одна из разработок IBM примерно тех же времен — система ввода описаний рентгеновских снимков в компьютер), то управление банально не удобно из-за низкой скорости голосового канала.
+1
Голосовой интерфейс далеко не всегда удобен, на самом деле
Да я с этим и не спорю. Но голосовой интерфейс может быть удобен в отдельных, специфических случаях.
0
ДВС тоже не всегда удобен. Мало того, что у него малый КПД, так ещё и для перевозки одного-двух человек нужно перемещать ещё и сам вес автомобиля (в среднем он больше тонны). Но это не значит, что теперь нужно отказываться от ДВС.
PS: имея мотоцикл и авто, я предпочитаю велик.
0
В свое время я хотел собрать ДУ для управления светом и шторами в комнате просто потому, что мне лень было вставать включать свет, когда я читаю, и я тянул до тех пор, пока буквы было видно… Голосовое управление для меня тогда было чем-то из разряда фантастики)
Лень в итоге победила, а сама задача утратила актуальность в связи с переходом на комп и электронные книги…
0
Подождите, получается что яндексовский сервис платный? По крайней мере, здесь они говорят что «бесплатный тестовый период — 1 месяц с момента отправки первого запроса на сервер»…

А гугловый тоже платный?
0
хм, действительно, как-то не доглядел.
Гугловский, вроде как платный, если делать более 50 запросов в сутки, но у меня запросов явно больше и денег он ещё не просил))).
Точней скажу через месяц, если денег попросит.
0
Вот в том числе поэтому маркер надо выделять самостоятельно. К тому же, хоть я и не ковырял инет на эту тему, но сдается мне, что для какого-никакого распознавания маркера найдется с десяток готовых библиотек.
+1
Угу, тогда без вариантов нужно детектить маркер, притом минимизировать кол-во ложных срабатываний.

Иначе громко включенный телевизор в «умном доме» быстро уменьшит размер вашего счета :) У Яндекс озвучена цена: «в среднем составляет $5 за 1000 запросов»
0
Возьмем гугл, как я понимаю, он бесплатно дает 500 запросов в сутки (позавчера было 331 — не забанил). 500/24 = 20 запросов в час. Минимум 5 часов хозяева будут спать, плюс время, пока никого нет дома, это ещё минимум 2 часа. Получается, 30 запросов в час (если во сне не разговариваете). Итого имеем 1 запрос в 2 минуты, чего более чем достаточно с учетом того, что Вы не будете разговаривать 17 часов без остановки (телик тоже столько орать не будет).
0
(телик тоже столько орать не будет)
Оптимист… У нас телевизор выключается разве что на ночь.
Иначе громко включенный телевизор в «умном доме» быстро уменьшит размер вашего счета :)
«Кто вчера смотрел „гостью из будущего“ и выжрал всю квоту запросов?!»
+1
Если телевизор работает достаточно громко и детектируется по уровню сигнала – то он запросто нагенерит 500 запросов за несколько часов работы.
Ведь по сути, любой достаточно громкий звук будет генерировать запрос …
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.