Ирина — опенсорс русский голосовой помощник. Offline-ready

77a3679ff3139d96565690396391b74a

-- Ирина, таймер…
-- Ставлю таймер на пять минут.

Вполне себе обыденная история из моего быта. Я таки сделал собственного автономного голосового помощника.

TL; DR> Ирина вполне неплохо работает дома 24×7.

Потребуется установить Python 3.5+ и зависимости через pip (немного знаний Python).

Скиллы «из коробки»: таймер, погода, контроль медиа (громче/тише/дальше), контроль плеера MPC-HC, запуск медиа из папки, расписание ближайших электричек, «подбрось кубик/монетку».

Плагинами добавляются: другие скиллы, Text-to-Speech и Speech-to-Text движки.

Мотивация

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

Во-первых, я не в восторге, что общедоступные голосовые помощники контролируются корпорациями. Я не могу точно сказать, что X порекомендует моему ребенку на запрос «мультики» и что покажет ему на Ютубе. Я бы предпочел контролировать это самостоятельно, пусть на это уйдёт и несколько больше времени.

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

В-третьих, четкая работа помощника по командам. Мне хотелось бы точно знать, что происходит, когда я произношу то или иное слово. Идея «поболтать с Алисой» мне несколько чужда — в частности, потому, что я не могу до конца доверять мотивациям людей, её создающим. Если брать ребенка, то мне бы хотелось, чтобы он учился командовать компьютером, а не болтать с ним; в конце концов, именно однозначно понимаемый набор команд можно назвать алгоритмом.

В-четвертых, короткие команды. Наверное, их можно настроить и в других помощниках, но тут это сделать гораздо проще — можно их просто запрограммировать.

В-пятых, сложные сценарии. Если весь код у вас на руках, то сделать при необходимости сценарий в духе «реши десять арифметических задачек, а потом можешь посмотреть мультик» гораздо проще.

Если вы в первом приближении разделяете часть моих мотиваций — возможно, Ирина вам подойдет.

Архитектурные компромиссы

Нельзя объять необъятное

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

  1. Основная цель проекта — дать программисту возможность быстро дополнять навыки голосового помощника и настраивать их под себя.

  2. Установка помощника сделана больше для программиста на Python, нежели для конечного пользователя. Потребуется скачать проект с Github, установить зависимости через pip, и запустить Python-файл. Зато дописывать проще. (Я не против, если кто-то упакует это в EXE, но я сам не чувствую в этом необходимости)

  3. Установка плагинов. Плагины надо кинуть в папку plugins, а после их запуска можно настроить их JSON-конфиг в папке config. Возможно, имело смысл сделать какой-нибудь онлайн-репозиторий, и механизм установки, но я делал быстро и максимально просто.

  4. Мультиязычность. Мультиязычность бы потребовала умение обрабатывать разные языки (определенная сложность парсинга команд), а также каждый раз работать с локализованными строками. Я посчитал, что её поддержание обойдется слишком дорого программисту, пишущему «для себя». Поэтому многоязычность плагинов не поддерживается — всё только на русском, но просто. (Ядро поддерживает многоязычность, т.к. там не так много языкозависимых строк. При желании вы можете просто переписать нужные вам плагины на нужный вам язык. Также можно подключить другие Text-to-Speech и Speech-to-Text движки, и работать на другом языке)

  5. Не Python-style кода (личное). С Python я начал работать не так давно, и до сих пор много работаю на других языках. Поэтому при написании кода я часто использую типовое ООП, хотя возможно, что-то можно было сделать компактнее.

Если указанные компромиссы вас не отпугнули — думаю, имеет смысл познакомиться с Ириной.

Быстрый старт

  1. Скачайте проект с Github: https://github.com/janvarev/Irene-Voice-Assistant

  2. Для быстрой установки всех требуемых зависимостей можно воспользоваться командой:  pip install requirements.txt

  3. Для запуска запустите файл runva_vosk.py из корневой папки. По умолчанию он запустит оффлайн-распознаватель vosk для распознавания речи с микрофона, и pyttsx движок для озвучивания ассистента (стандартный движок Windows для синтеза речи).

  4. После запуска проверить можно простой командой — скажите «Ирина, привет!» в микрофон

Общая логика

Запуск всех команд начинается с имени ассистента (настраивается в options/core.json, по умолчанию — Ирина). Так сделано, чтобы исключить неверные срабатывания при постоянном прослушивании микрофона. Далее будут описываться команды без префикса «Ирина».

Плагины

Поддержка плагинов сделана на собственном движке Jaa.py — минималистичный однофайловый движок поддержки плагинов и их настроек.

Плагины располагаются в папке plugins и должны начинаться с префикса «plugins_». Плагины задают навыки/скиллы голосового помощника.

Настройки плагинов, если таковые есть, располагаются в папке «options» (создается после первого запуска).

Готовые плагины

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

plugin_greetings.py — приветствие (оффлайн). Пример команды: «ирина, привет»

plugin_timer.py — таймер (оффлайн). Примеры: «таймер, таймер шесть минут, таймер десять секунд, таймер десять» (без указания единиц ставит на минуты — «таймер десять» — на десять минут. Просто «таймер» ставит на пять минут)

plugin_mediacmds.py — команды управления медиа (оффлайн). Пример: «дальше, громче, тише, сильно громче, сильно тише, пауза». (Если установлено mpcIsUseHttpRemote, то сначала делается попытка вызвать команду плеера MPC-HC, если не удается — используется эмуляция мультимедийных клавиш)

plugin_mpchcmult.py — проигрывание мультиков через MPC-HC из определенной папки (оффлайн). Пример «мультик <название_мультика>». Папка задается в конфиге. При вызове команды в папке ищется файл с соответствующим названием <название_мультика> и любым расширением. Если найден — запускается на проигрывание. (Как можно догадаться, этот плагин предназначен для показа отобранных медиа без обращения к ютубу.)

plugin_random.py — рандом (оффлайн). Примеры: «подбрось|брось кубик|монетку». Содержит примеры парсинга дерева команд (команды можно задавать деревом). Больше демонстрационный плагин.

plugin_weatherowm.py — погода (онлайн). Примеры: «погода, погода завтра, погода послезавтра, прогноз погоды». Требует установки в конфиге бесплатного API-ключа с https://openweathermap.org/ , а также местоположения пользователя.

plugin_yandex_rasp.py — расписание ближайших электричек через Яндекс.Расписания. Пример: «электричка, электрички». Требует установки в конфиге бесплатного API-ключа для личных нужд (до 500 запросов в сутки) с https://yandex.ru/dev/rasp/raspapi/ , а также станций отправления и назначения. (Если вы ездите на электричке — фраза «ирина, электричка» очень удобна для проверки расписания)

plugin_tts_pyttsx.py — (оффлайн) позволяет делать TTS (Text-To-Speech, озвучку текста) через pyttsx движок. Используется по умолчанию.

plugin_tts_console.py — (оффлайн) заглушка для отладки. Вместо работы TTS просто выводит текст в консоль.

Свои Text-to-Speech и Speech-to-Text движки

По умолчанию для распознания речи используется движок VOSK, для синтеза — Windows (голос Irene).

Дописать свои варианты вполне можно, это стандартная операция. Детали — в Github.

Уже доступен STT через модуль SpeechReсognition (онлайн-распознавание от Гугла и пр.), а также TTS через Silero (нейросетевая генерация оффлайн). Мне не очень понравился результат Silero (хотя сам проект прекрасен) — генерируется дольше, задержка в несколько секунд, а также есть «металлические» шумы, но, возможно, он подойдет вам. (Кстати, в одном из комментариев @putnik поделился собственным анализом доступных движков TTS и STT.)

Кстати, имя помощника тоже настраивается в файле конфигурации — так что если нужно, можете сделать, чтобы он откликался на имя «Джарвис». И можно поставить мужской голос, конечно.

Аналоги

Честно говоря, я начал писать свой проект без анализа аналогов. Ну, точнее, беглый гуглеж позволил мне найти прекрасную хабрастатью @EnjiRouz Пишем голосового ассистента на Python, а также соответствующий репозиторий, который и послужил основой для проекта.

Правда, например, код для получения погоды c OpenWeatherMap пришлось полностью переписать, потому что они перестали поддерживать старое API.

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

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

Один из самых больших проектов на github с открытым кодом голосового помощника называется Leon. Система сделана французом…

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

После, у нас есть JARVIS из Железного Человека. <…> Это позволит вам создавать вашу собственную Сири в пределах отдельно взятой сети.

Интересно, получилось ли у автора создать собственную Сири, или всё же самостоятельная настройка споттера, распознавания голоса и озвучки текста на отдельно взятой малинке всё же сильно выходят за рамки «небольшой конфигурации». Ну, и если ничего не поменялось, то у него была проблема с поддержкой даже не русского, а вообще какой-либо локализации. Так что, вероятно, вам придётся делать форк и переводить все сообщения.

Чуть более популярная чем Jarvis, но уступающая Леону — система Mycroft.

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

Ядро небольшое, почти всё вынесено в плагины и навыки. Есть какое-никакое сообщество, которое эти навыки пишет и поддерживает. Хотя встречается довольно много говна и палок не самых лучших архитектурных решений. Ядро в интернет ломится за настройками навыков, которые хранятся на сервере, сами навыки за данными. По умному дому более-менее нормальная интеграция есть только с Home Assistant, остальное вам придётся писать с нуля. По музыке есть интеграция со Spotify (если вас не смущает необходимость хранить пароль в открытом виде на чужих серверах).

Лично я немного потыкал Jarvis, который мне показался похожим по архитектуре на мою собственную. Сделан достаточно удобно;, но это, вообще говоря, проект, рассчитанный под консольные команды (!) на английском (!). Т.е. адекватная локализация на русский — дело крайне большое; не говоря уже о том, что ряд кейсов плохо укладывается в голосовое, а не консольное управление (например, игра «Быки и коровы»).

В общем, на мой взгляд, проект «Ирина» для русского пользователя — совсем неплохо. С другими проектами придется серьезно решать проблемы локализации. Хотя, конечно, интеграций в аналогах больше -, но при желании их можно попытаться портировать под Ирину.

Заключение

Честно говоря, я сам не ожидал, но Ирина вполне себе прижилась у нас в семье.

Самый часто используемый навык — таймер, потому что рядом кухня. Иногда используется погода и электрички. Мультики пока ещё не востребованы, думаю заняться ими позже.

Крутится это все на ноутбуке, который в настоящее время является сервером. Встроенного микрофона хватает на эффективное распознавание с 2–3 метров; хотя, конечно, иногда не срабатывает и приходится либо повторять, либо подходить вплотную.

Загрузка процессора минимальна; думаю, пойдет и на Малинке, но, конечно, не пробовал.

Свои плагины

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

Например, по «ирина, запусти музыку» открывается Яндекс.Музыка.

Еще у нас есть локальный, не сетевой доставщик неплохой пиццы (PushPizza, если кому интересно). Где-то за полчаса я написал плагин, который проверяет, в каком состоянии доставка — готовится, или едет. Написан алгоритм с использованием библиотеки pyautogui, позволяющей эмулировать ввод пользователя (мышь и клавиатуру):

  1. Открыть страницу доставки

  2. Подождать чуть-чуть

  3. Найти на экране картинку (форму ввода телефона) (да, в pyautogui такое есть из коробки)

  4. Перевести туда мышь и кликнуть

  5. Сэмулировать ввод телефона

  6. Вуаля! Страница со статусом доставки доступна

В общем, вроде писать плагины оказалось несложно. (Если вы вдруг что-то напишете и захотите поделиться, можете кидать ссылки в https://github.com/janvarev/Irene-Voice-Assistant/issues/1

Благодарности

@EnjiRouz за проект голосового ассистента:  https://github.com/EnjiRouz/Voice-Assistant-App, который стал основой (правда, был очень сильно переработан), а также за отличную статью на Хабре: Пишем голосового ассистента на Python

AlphaCephei за прекрасную библиотеку распозавания Vosk ( https://alphacephei.com/vosk/index.ru )

@putnik за разбор других голосовых помощников и список TTS и STT решений

Github проекта

© Habrahabr.ru