Я создал виртуального голосового ассистента, который работает без интернета

12

Этот текст написан в Сообществе, в нем сохранены авторский стиль и орфография

Введение

Вообще, Siri на Mac — штука странная. Чтобы она просто открыла приложение или сказала время, нужен интернет. Без сети она молчит. Вообще никак. Это бесит особенно, когда сейчас начали жестко глушить интернет. Ну, сами знаете.

Но я понимаю, почему Apple требует интернет для работы Siri. Apple обрабатывает голос в облаке, там своя нейросеть, свои алгоритмы. Но когда я говорю "открой Safari" — зачем тут облако? Это же просто команда.

К тому же меня напрягает, что мой голос куда-то улетает. Даже если Apple ничего с ним не делает. Просто не нравится.

В какой-то момент я подумал: а почему бы не сделать своего ассистента?

Причем такого, который работает локально. Без интернета. Без отправки данных.

Как я начал

Сначала я, конечно же погуглил. Оказалось, что на macOS есть встроенные штуки для распознавания речи. SFSpeechRecognizer. Он умеет распознавать голос в текст прямо на устройстве. Без облака. Это стандартная библиотека от Apple.

Я хотел взять готовые библиотеки, скрипты и прочие штуки и написать крутого ассистента. Но все, что находил, работало через облако или было написано на Swift с привязкой к экосистеме Apple. А я хотел сделать независимую и очень быструю штуку. Которая не умрет, если Apple что-то поменяет.

Поэтому я решил писать на чистом C (без внедрения остальных языков, имеется в виду).

Работа со звуком операционной системы

Прежде чем приступить к написанию проекта, мне нужно было уяснить, как вообще работает звук. Как работает микрофон. Что такое потоки звука, что такое сэмплы, что за дуплексные и полнодуплексные устройства. Естественно, ответы на эти вопросы я не знал. К счастью, в документации PortAudio (библиотека для работы со звуком) это рассказывалось. Я очень обрадовался.

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

Захват звука — PortAudio

Чтобы взять звук с микрофона, я использовал PortAudio. Это кросс-платформенная библиотека для работы с аудио. На macOS она общается с CoreAudio, но мне не пришлось лезть в низкоуровневые дебри.

PortAudio старый, но благо, надежный.

Распознавание речи — Whisper

Чтобы распознавать голос, я взял библиотеку Whisper. Она весьма нелегкая по сложности, но работает локально, без интернета. Качество — очень приличное, даже на фоне шума.

Я уделил документации по этой библиотеке примерно неделю, написал несколько тестовых программ.

Даже на старом MacBook Air от 2015 года команда распознается за доли секунды. На M1 — вообще мгновенно. Хах, это не может не радовать.

Графика

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

Я просто создал окно, нарисовал кружок и текст сверху.

Вручную.

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

Парсер. Никакого AI

Когда я только начинал, меня пугала мысль: "Как научить программу понимать, что сказал человек?"

В интернете полно решений через нейросети, трансформеры, эмбеддинги и прочую радость. Но я не хотел тащить в проект ещё и огромную языковую модель. Whisper и так уже много весил.

Поэтому я пошел другим путем.

Я написал простой анализатор команд. Он работает так: берет текст, приводит к нижнему регистру, выбрасывает всякую ерунду типа "пожалуйста", "прошу", "ну-ка" и потом смотрит на ключевые слова.

Например, если в тексте есть слово "open", а после него название приложения — значит, надо открыть программу. Если есть "brightness" и рядом число — значит, изменить яркость. Если есть "shutdown" или "выключи" — да, подтверждение, но потом выключить компьютер.

Никаких нейросетей. Простой алгоритм, который работает быстро, предсказуемо и без интернета.

Контекст. Забываем про команды сразу после выполнения

Я специально не стал делать поддержку диалогов. Почему? Потому что ассистент не должен запоминать, что ты сказал минуту назад. Это называется stateless.

Сказал команду — выполнил — забыл. Никакой памяти между запусками. Никаких "помни, что я открыл браузер пять минут назад".

Так проще для приватности. Программа не хранит историю твоих команд (если ты сам не включишь логирование, но по умолчанию — выключено).

Текстовый режим

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

Нажимаешь T (обычная буква, без модификаторов), открывается поле ввода. Печатаешь команду, Enter — выполняется. Алгоритм парсинга тот же самый, что для голоса.

Кстати, это очень помогло при отладке. Я мог тестировать команды без произношения вслух, просто вбивая текст в окошке.

Что в итоге

Command Siri — это голосовой ассистент, который работает локально, не шпионит и не требует интернета.

Он написан на чистом C, использует Whisper для распознавания речи, PortAudio для захвата звука и raylib для графики. Без Swift, без XIB, без магии Apple.

Он весит копейки, запускается в три клика после скачивания, и им может пользоваться любой владелец Mac.

А что с обычной Siri

Apple сделала сложную систему, которая умна, но требует облака и интернета. Мой ассистент — нет.

Он проще. Он глупее. Он не умеет поддерживать диалог, не интегрирован в систему, не запоминает контекст.

Но он выполняет основные команды даже в бункере без связи.

И не шпионит.

Ну, я себе такой сделал. Может, кому-то тоже пригодится.

Вопросы под постом отвечу.

  • ВасильгаОтлично!! Очень интересно узнать продолжение..делитесь..0
  • Paul's pageинструкция - https://www.youtube.com/watch?v=zFsZpnsYS9c скачать и протестировать ассистента - https://github.com/Storm999-alt/Command-Siri0
  • Тра ля ляА нажать на кнопку мыши вместо того чтобы говорить "siri, открой safari" ты не пробовал? Или тебя беспокоит тот факт, что щелчок мыши улетит куда-то на сервера гугла? Для этого специально своего ассистента надо создавать?1
  • Paul's pageТра, чувак, я четко дал понять, что это только начало. Я развиваю ассистента, и в скором времени он сам сможет звонить людям по telegram, discord и в др. мессенджеров по голосовой команде, а также полностью управлять файловой системой компа. То, на что у тебя сейчас уходит 20-30 сек (найти программу, открыть, найти чат, позвонить или, в моем случае, найти впн, открыть, запустить, открыть приложение, найти чат, позвонить), — будет работать не дольше 3 секунд (зависит от быстроты произнесения команды. В остальном случае программа делает все сама). И это только одна из 50+ продвинутых команд, который ассистент сможЕТ выполнить. Вот в чем разница. Повторюсь, это только начало. И да, эту программу я делаю под себя, а не под других. Мне плевать на коммерцию. Я лишь делюсь своими идеями и/или проектами в открытой сети и выставляю бесплатно как open source PS об упр. файловой системы компа я вообще молчу. Там надо знать команды вроде ls, mv, ls -l, chmod, ls | grep ".txt" и многие, многие другие. Опять же, если применить ассистента, все эти команды можно даже не заучивать. Достаточно просто четко произнести, что требуется3
  • Alex V KОтлично! Я бы и на айфоне не отказался от такой - не слушается Сири. и на винде поставил бы!) Благодарю за вложенное время. Подписался.0
  • Дмитрий СоколовPaul's, мне вот интересно, и как же это надо будет произносить «ls | grep .txt»? Особенно для инструмента принципиально без ML.0
  • Дмитрий СоколовВ целом это всё полезно для личного развития и тэдэ и тэпэ, не спорю… Но я бы просто порекомендовал чуть ближе ознакомиться с macOS, где под все простые сценарии были все встроенные инструменты ещё при царе Горохе. Вот буквально ещё на PowerPC. И если ещё можно сказать, что обычному человеку слишком сложен тот же Automator, а уж голый AppleScript и подавно, то в сравнении с приложением на C оно всё просто игрушки…0
  • Владислав КузьминВстроенный spotlight (если его не убрали из системы) разве не делает тоже самое? Конкретно про голосовой ввод https://support.apple.com/ru-ru/guide/mac-help/mchl9899c8a5/mac0
  • Paul's pageДмитрий, ls | grep .txt - это "покажи содержимое папки только с форматом txt". Фразу можно сказать как угодно, меняя слова и порядок. Программа все равно поймет, потому что она считывает не все слова, а только ключи: "show" (покажи/отобрази), "content" (содержимое), "folder" (папка), "txt". Например, в запросе "please, show me weather in London" обрабатываются только "weather" и "London", а стоп-слова вроде "please", "me", "show", "in" игнорируются0
  • Дмитрий СоколовPaul's, неправильно: это «перечисли все файлы, потом оставь строки, содержащие .txt». Если интересны именно текстовые файлы, то тут либо ls *.txt, либо хотя бы grep .txt$, и неплохо бы ещё исполняемые отфильтровать. Ну да речь не об этом. И не о погоде в Лондоне тем более. Вот что конкретно голосовой (!) ассистент должен сделать такого, чтоб это было аналогом ls?1
  • Valeri Romanработает ли программа с windows 10 и можно ли загрузить только русский язык0
  • Valeri Romanработает ли программа с windows 10 и можно ли загрузить только русский язык0