Ирина, голосовой помощник. Продолжение
— Слушай, она меня на кухне не слышит.
— Ну да, далековато. Давай дополнительный микрофон протянем.
<покупается 5 метров кабеля>
— О, классно!
— …
— Теперь в комнате не работает.
Это продолжение статьи Ирина — опенсорс русский голосовой помощник. Offline-ready. Расскажу, что поменялось за два месяца с момента прошлой статьи.
Отлажена работа в режиме клиент-сервер с несколькими микрофонами/машинами
Сделан Телеграм-клиент для удаленного управления
Прикручено несколько новых голосов (TTS)
Добавлена возможность обрабатывать голос в контексте (можно делать голосовые игры)
Мне прислали плагин, позволяющий запускать сценарии Home Assistant:)
Новые плагины и улучшенная документация
Клиент-сервер, или как командовать с нескольких микрофонов
В комментариях к прошлой статье спрашивали, можно ли сделать распознавание команд с нескольких микрофонов. Чуть позднее мне пришлось самому столкнуться с этой проблемой — очень хотелось, чтобы можно было командовать Ириной как с кухни (ставить кухонный таймер), так и рядом с сервером.
Кабель купили, микрофон поставили, на кухне всё заработало…, но оказалось, что теперь не идет аудиопоток с микрофона в сервере.
В общем возникла проблемка.
Я оптимистично предположил, что в Windows есть функция сведения микрофонов…, но оказалось, что её НЕТ. Во всяком случае, быстро найти мне её не удалось.
Писать оригинальную функцию в Питоне для сведения потока с двух микрофонов мне не захотелось — не мой профиль, и быстро бы не получилось.
Так что был выбран третий путь — довести до ума клиент-серверную инсталляцию, где два отдельных клиента слушали бы микрофоны, распознавали с них ввод, и отсылали на сервер для обработки. Заодно возникла бы возможность командовать Ириной с других машин, или вообще через Телеграм-клиент.
…
Долго ли коротко ли, клиент-серверная модель была отлажена. (Кто её пробовал в 3.0 — извиняюсь, я там немного накосячил с многопоточностью; попробуйте самую свежую версию, она устойчива).
Обычная работа Ирины выглядит так:
Speech-To-Text (распознавание голоса) → vacore (ядро) → plugin → Text-To-Speech (генерация голосового ответа)
В то время, как клиент-серверный вариант — так:
[клиент] Speech-To-Text (распознавание голоса) ----> [сервер] webapi (vacore) → plugin → Text-To-Speech (генерация голосового ответа)
На клиент возлагается ответственность передавать текстовый поток. Можно это делать через распознавание голоса, или просто посылать команды через командный интерфейс.
Сейчас сделаны примеры нескольких клиентов:
run_remoteva_vosk.py — запускает распознавание с определенного микрофона с помощью VOSK, и отсылает результат на сервер. Кроме того, я собрал этот клиент в EXE-файл c помощью Auto-py-to-exe, что позволяет запускать его на машинах без установленного Питона. В предельном варианте у меня работало 4 таких клиента — по клиенту на 2 микрофонах на сервере + еще по клиенту на двух ноутбуках.
run_remoteva_cmdline.py — компактный демо-вариант клиента, позволяющий работать с Ириной через командную строку.
run_remoteva_cmdline_min.py — Абсолютно минимальный вариант для удаленного управления Ириной через командную строку (около 50 строк кода). Сделан только на нативных функциях Python, без установок пакетов (что может быть полезно, если захотите реализовать вариант для чего-то компактного без pip).
run_remote_telegrambot.py — Телеграм-клиент, о котором чуть позже
Про проблему голосового ответа в клиент-сервере
Вот сижу я за ноутбуком, и говорю «Ирина, прогноз погоды».
Вопрос — как должен осуществляться вывод? На сервере Ирины, через колонки? Или же на моем компьютере, звуком? Или, если я сижу в клиенте командной строки, возможно, я ожидаю ответ в текстовом виде?
Я решил, что однозначного ответа на этот вопрос нет, и для каждого клиента должны быть свои настройки. Для этого при вызове REST API предусмотрен параметр ttsFormat, который может принимать следующие значения:
«none» (TTS реакции будут на сервере)
«saytxt» (сервер вернет текст, возможно, TTS будет на клиенте. Или же клиент просто покажет сообщение текстом)
«saywav» (TTS на сервере, сервер создаст WAV согласно установленному голосу и вернет клиенту, клиент его проиграет) (звук на клиенте)
Более того, поддерживаются комбинации параметров. Например, можно задать «none, saywav» — как что вызовет озвучку на сервере, так и передаст WAV-файл на клиент.
Подробнее о клиент-серверных инсталляциях можно почитать в документации.
В общем, можно сделать как вам удобно.
Телеграм-клиент
Поскольку клиент-серверная модель была отлажена, возникла интересная идея — почему бы не сделать опцию управления Ириной через Телеграм-бота?
Долго ли коротко ли, он был сделан. Инструкция по установке здесь.
Из интересного — мне адски захотелось сделать фичу обработки голосовых сообщений в Телеграме, чтобы опыт команд был приближен к голосовому. Можно, конечно, и просто текстом команды посылать, но это не так весело.
В общем, сейчас можно:
отправить голосовое сообщение в бот
бот его распознает (с помощью VOSK)
далее вы можете либо запустить распознанную команду, либо проиграть исходное голосовое сообщение там, где запущен Телеграм-клиент (!). Этакая широковещательная штучка — возможность озвучить своё сообщение прямо через колонки.
Новые TTS (Text-to-Speech) движки
С момента запуска были добавлено несколько новых движков и голосов. Хочу отметить следующие:
RHVoice — для маломощных машин и Linux (стандартный Linux espeak не очень хорош, а вот RHVoice вполне)
silero_v3 — вчера был анонс на Хабре, голоса там очень качественные. Мне удалось быстро добавить их поддержку в Ирину; однако они предназначены для относительно мощных машин
Впрочем, я по-прежнему использую стандартный pyttsx, он мне нравится — в том числе и тем, что явно ощущается, что это робот. Предпочитаю об этом не забывать.
Поддержка контекста при общении
Изначально планировалось, что все обращения к Ирине будут начинаться с имени помощника — так предполагалось отсеивать команды от обычного разговора в комнате.
Но на практике оказалось, что это не всегда удобно. Иногда хочется, чтобы помощник просто переспросил — например, после фразы, «Ирина, мультик пыагьа», чтобы переспросил «Какой мультик?». Или, после фразы «Ирина, таймер ыывашел», был вопрос «Что после таймер?».
Сейчас это сделано. Плагины в определенных ситуациях могут задавать »контекст» — и если контекст задан, то голосовые обращения будут идти прямо в него, минуя остальные стадии распознавания команд. При этом контекст сбрасывается через 10 секунд (настраиваемо) — это позволяет Ирине возвращаться в обычное состояние даже если пользователь не ответил, или куда-то ушел.
Это может быть полезно в реализации голосовых игр, или, например, арифметических тестов для ребенка.
Как примера была сделана плагин-игра «Больше-меньше». В ней загадывается число от 1 до 30; задача отгадать его не более чем за 5 попыток.
Попробовал — вполне играбельно.
Интеграция с Home Assistant
Несмотря на несколько запросов на интеграцию Ирины с Home Assistant, я не хотел этим заниматься. У меня правило — стараться не программировать то, чем не пользуешься сам, а то сделаешь неудобно почти наверняка.
Однако юзер timhok буквально на днях выложил плагин, который позволяет запускать сценарии Home Assistant через команды Ирины (через REST API HA). Там есть красивое решение — если в описании сценарии есть строка типа ttsreply (Приятных снов), то именно этот ответ будет озвучен, если сценарий выполнен.
Если вы до этого командовали HA только через Алису, то теперь это вполне можно сделать и через Ирину.
Новые плагины и документация
Из новых интересных плагинов могу выделить:
plugin_finstockmoex.py — курс акций на Московской бирже (ох, намучался я с его получением!). В конфиге можно задать:
список акций для озвучки, несколько наборов при желании
собрать портфель из акций — тогда будет озвучиваться стоимость портфеля
Примеры команд: «ирина акции», «ирина акции сбер», ирина портфель тест»
plugin_urlopener.py — полезный плагин, если вы планируете открывать ссылки в браузере по голосовым командам.
Позволяет задать в конфиге набор команд, и URL, которые будут по ним открываться.
Конфиг настраивается в options/plugin_urlopener.json
Пример:
"cmds": {
"главная яндекс": "https://yandex.ru/",
"ютуб|юту": "https://www.youtube.com/results?search_query={}",
"яндекс": "https://yandex.ru/search/?text={}"
},
Если в URL содержится {}, то он будет заменен на оставшуюся часть произнесенной фразы. Так, фраза «яндекс погода» запустит поиск в Яндексе по слову «погода».
Про документацию
Документация сильно обновилась. Сделаны примеры разработки плагинов, процедура настройки клиент-серверной модели. Ещё несколько важных документов по решению проблем при установке на Mac и Linux на основе отзывов пользователей.
В общем, это наконец-то не одна страничка. Вот например, оглавление документа «Разработка плагинов»:
Типовые задачи
Простейший плагин
Плагин с пользовательскими настройками
Плагин с кастомной обработкой пользовательских фраз
Плагин с деревом команд
Плагин с непрерывным взаимодействием (установлением контекста), или переспрашивающий
Плагин, устанавливающий голосовые команды в зависимости от пользовательских настроек
В общем, документация правда стала сильно более полной.
В заключение — немного о поддержке проекта
Я немного поработал в западном опенсорсе. Впечатлило меня следующее — я понял, что живучесть проекта почти не определяется идеей, в него заложенной.
Живучесть определяется тем, сколько времени проект поддерживают.
Потому что писать код относительно весело.
А вот писать документацию, отвечать на вопросы, разбирать пулл-реквесты, договариваться с контрибьюторами, отлаживать баги в не самых обычных конфигурациях, обновлять проект под новые зависимости — уже не очень. Но проект в реальности во многом живет именно этим — небольшими проблемами и вопросами абсолютно реальных любдей.
Опенсорс-разработчик вынужден быть не только разработчиком, но и немного менеджером, техническим писателем, просто писателем и т.д. Но найти соавторов, которые взяли бы на себя часть функций непросто.
Так или иначе, у меня есть ощущение, что будущее «Ирины» — кастомизируемого голосового помощника, не завязанного на крупные корпорации — сейчас в значительной степени зависит от моего интереса. Скорее всего, именно от него зависит, сколько проект будет жить в публичном поле и получать апдейты.
Если Ирина вас порадовала, и вы хотите, чтобы проект жил подольше, то можно:
Написать плагин для Ирины. Это то, что меня очень сильно мотивирует — когда видишь, что кому-то проект настолько небезразличен :)
Поддержать материально подпиской на Boosty.to. Это тоже форма внимания. Видя подписчиков я понимаю, что кто-то действительно заинтересован в проекте.
Выразить благодарность в комментариях или личном сообщении. Это меня всегда радует :)
Спасибо за внимание!
Буду работать дальше.
Github проекта