Локальное голосовое управление

d1e2aad4f40ec62beb56f6c8e51275fe

Я не художник…

Привет. В очередной раз задумался о локальном голосовом управлении устройствами умного дома, а тут как раз наткнулся на статью @CyberexTech «Моя безумная колонка» — https://habr.com/ru/companies/timeweb/articles/772080. Их там две части. Я тоже запускал на распбери готовые проекты типа voice2json, но все это оказалось не о том, речь распознавалась, но дальше никакого движения. А тут статья от Кибертеха (мне проще его так называть). Очень интересный проект показался, особенно после видео довольно быстрого распознавания vosk-ом голоса, но дочитав до конца я понял, что это опять не то, нам-то нужно чтобы включалось/крутилось всякое железо, навешанное на умный дом, типа лампочек и кондиционеров, а в статье это оказалось как-то очень усложненно и неявно. В общем решил сам попробовать что-нить запилить. А самая хохма в том, что я не программист и писать код не умею, но у нас теперь есть программист от бога, которого называют ChatGPT. Пришлось обращаться к нему.
Так, вступление закончил, теперь от чего отталкивался и к чему все это пришло. Задача состояла в том, чтобы для начала произнести две обычные фразы «Включи свет в зале» и «Открой шторы на кухне», после чего микрокомпьютер не просто распознал бы речь, а в зависимости от фразы произвел необходимое действие — включил свет в зале и открыл шторы в кухне, ну, это понятно. Одним из вариантов, кстати основным и практически единственным во всех готовых голосовых проектах, которые я пробовал, это был вариант отталкиваться от речи, чтобы комп эту фразу разбил на слова, разобрался что в этой фразе действие, что местоположение, что функционал, как-то понял как привязать все это к конкретному устройству и как-то дать команду на устройство, короче логику я не осилил, тут выходило что на комп надо ставить чуть ли не обученную нейросеть. Подумав , я решил не к фразам устройства прикручивать, а к к железу — фразы. Итак, что у нас представляет обычный умный дом? Это комп, на котором крутится софт, позволяющий по проводу/беспроводу дать команду на устройство, лампочку там, пылесос, телевизор и так далее. А на подавляющем большинстве умных домов команды взаимодействие крутится вокруг MQTT. Итак, на каждом умном доме есть куча устройств и все умения этого устройства в софтовом виде — это топики MQTT. Немного подумав, я решил убрать локацию (типа кухня, зал, прихожая) из отдельного свойства устройства и привязал ее непосредственно к идентификатору, то есть не «Свет» в «Ванной», как отдельные элементы, а использовал как общность «Свет в ванной». Если нужно будет прикрутить локацию с устройству, то ее можно будет вывести как отдельно дополнительное свойство. Это важное замечание кстати.
Дальше. В своей статье Кибертех описал очень классную штуку — словарь соответствия, типа вот этого:
command_dic = {
«SmartSwichON»: ('включи розетку', 'вкл розетку', 'розетку включить', 'розетку вкл'),
«SmartSwichOFF»: ('выключи розетку', 'выкл розетку', 'розетку отключи', 'розетку выкл'),
Вот сама идея такого словаря и решила проблему точного преобразования голоса в команду, но все же есть один нюанс. Кибертех пошел по пути отталкивания от команды. Я же решил во первых, словарь перевернуть и оттолкнуться от железа, а во вторых — использовать два словаря:

equipment_dic = {
«zigbee2mqtt/8acc.ЗАЛ Свет/set»: ['свет в зале'],
«zigbee2mqtt/jdyЖелезка»: ['лампа в кухне'],
«zigbee2mqtt/5e24.КУХНЯ Пылесос/set»: ['пылесос']

action_dic = {
«включи»: ['on', 'true', '1'],
«открой»: ['on', 'true', '1'],
«выключи»: ['off', 'false', '0'],
«закрой»: ['off', 'false', '0'],
«громче»: ['+1'],
«выше»: ['+1'],
«следующий»: ['+1'],
«тише»: ['-1'],
«ниже»: ['-1'],
«прежний»: ['-1'],
«предыдущий»: ['-1']
Результат: фраза управления не разбивается на несколько элементов, которые надо еще обработать и, что сложнее, понять что к чему относится, а собирается из них и уже собранный пакет сравнивается в результатом распознавания голоса. Что происходит в дальнейшем? Если фразы совпадают, ну например «включи» «лампа в кухне», то берутся соответствующие элементы, это топик mqtt из equipment_dic, в который загоняется 'on' в качестве нагрузки из action_dic. Могут конечно возникнуть возражения, мол фразы не везде одинаковые, но это просто обойти, достаточно расширить словари на элементы/синонимы, например сделать строки типа »'включи','запусти','вруби'»: ['on', 'true', '1'], и пропустить их при сравнении через фильтры и к этому же привязать функции нечеткого сравнения, но это мелочи, расширить код.
Короче, составив примерную логику работы, подал это в виде обычного текстового запроса с кусками словарей на блюде великому программисту. Программист справился! В результате я смог подключиться к своему умному дому, который живет на распбери и управляется Алисой, и включить/выключить две лампочки, находящихся в разных комнатах, не используя Алису, а чисто локально. Понадобилось два скрипта на питоне, один из которых был взят у Кибертеха и немножко допилен, а второй полностью написал ChatGPT. Что они делают. Первый обрабатывает речь и преобразовывает ее в текст, а также открывает сокет, в который отправляется результат распознавания, а второй — получает из сокета этот же результат, дальше, вот тут кстати я не допонял, сравнивает его со словарями, скорей всего перебором вариантов, при совпадении отправляет в соответствующий топик MQTT нагрузку, ну и после чего включается/выключается требуемое устройство.
Так как программист от бога, но неопытный, скрипты сырые и постоянно отваливаются. Но сама идея оказалась рабочей, так что теперь вся надежда на опытных программеров, которые смогут это все допилить.
Ну и как отчет что ли, резюмирую короче. Настройка микрокомпьютера вот отсюда
https://habr.com/ru/companies/timeweb/articles/772080/ — самый конец, где тестировал работу микрофона и динамиков, все что до того — для желающих
https://habr.com/ru/companies/timeweb/articles/817929/ -, а вот здесь от начала и до примерно середины, дальше идет настройка синтеза речи, в что я пока не буду вникать. Но вот идея использовать нечеткое сравнение для распознавания это очень хорошая идея, я ее попробую реализовать.
Ну и сами скрипты
https://github.com/alex1iam/crazyGPT
Скрипты запускаются по очереди, сначала сервер, потом клиент. Без запущенного сервера клиент сразу упадет. Ну, он упадет и после, но сначала отработает)))

© Habrahabr.ru