Всем привет! Я уже писал про своего голосового помощника Ирину статьи на Хабре: раз, два и три; первый раз был аж 3.5 года назад.

Самое главное — опенсорспроект жив. А если опенсорс жив в течение 3.5 лет — значит, он дошел до какой‑то точки зрелости. А если у него 900 звезд на Гитхабе — значит, им кто‑то пользуется, и даже успешно :)

О функциональности:

  • Ирина — голосовой помощник, написанный на Python.

  • Полностью оффлайн, локальный и приватный (но при желании можно подключить функции, требующие онлайна типа погоды)

  • Плагинами подключается много всего, в частности: новые навыки и TTS (Text‑to‑Speech) решения. Из часто спрашиваемого — есть плагин для Home Assistant (3 штуки, от сообщества) и болтания с ChatGPT‑подобными моделями (через OpenAI‑compatible интерфейс, можно использовать онлайн или оффлайн). Для плагинов от комьюнити есть специальная ветка на Гитхабе, там их много.

  • Высокая отзывчивость при малых ресурсах. По умолчанию Ирина использует VOSK STT для распознавания речи пользователя «на лету» (а не «записали — расшифровали», что увеличивает latency). При этом она может отдавать озвучку в локальные скоростные TTS, что приводит к тому, что при оптимальных настройках между вызовом и ответом проходит меньше секунды (что чуть ли не быстрее всех остальных помощников).

  • При желании есть режим клиент‑сервер (для девайсов в разные комнаты), где клиент может быть «тонким» (только записывать звук, например). Есть примеры клиентов на Python, сообщество делало программу на Android (можно использовать старые мобилки как колонки), для ESP32 вроде тоже была прошивка, но не тестировал. API есть, можно дописывать свои варианты.

  • Простая архитектура, ориентированная на возможность самостоятельного написания плагинов. Никакой многоязычности (только русский), никакого оверинжиниринга.

Ключевые принципы

Напомню ряд принципов из первой статьи с Хабра, которыми я руководствовался при написании проекта, т. к. они мне близки:

  • Мне не хочется отдавать свои данные корпорациям, видеть ухудшение софта с апдейтами, а также слушать рекламу из проприетарных колонок, если вдруг чьи‑то менеджеры решат, что это хорошая идея. Поэтому Ирина планировалась как то, что может работать чисто оффлайн, без апдейтов софта. Я ценю свое время.

  • Есть ряд других универсальных языковых помощников. На международном рынке лично я не собираюсь конкурировать, а поддержка многоязычности усложняет архитектуру и написание прикольных плагинов «под себя». Поэтому Ирина одноязычна и ориентирована только на работу на русском языке (её можно адаптировать под любой другой язык, но это потребует от вас некоторого времени)

  • В целях упрощения жизни и обработки при запуске плагинов принят формат «имя_помощника ключевое_слово_команды параметры» (имя помощника может быть любым, не только Ирина). Я считаю, что нормально УПРАВЛЯТЬ компьютером, а не беседовать с ним (впрочем, позже под давлением времени я добавил режим болталки). Такой формат не подойдет для всех (надо помнить команды), но зато позволяет избавиться от неточного понимания интентов или долгой обработки с помощью LLM.

  • Простая архитектура для написания плагинов. Считается, что каждому лучше подстроить Ирину под себя.

Пример плагина (30 строк):

import random
from vacore import VACore

# функция на старте
def start(core:VACore):
    manifest = { # возвращаем настройки плагина - словарь
        "name": "Рандом", # имя
        "version": "1.0", # версия
        "require_online": False, # требует ли онлайн?

        "description": "Демонстрационный плагин\n"
                       "Голосовая команда: подбрось монетку",

        "commands": { # набор скиллов. Фразы скилла разделены | . Если найдены - вызывается функция
              "подбрось монетку|брось монетку": play_coin,
            }
        }
    }
    return manifest

def play_coin(core:VACore, phrase: str): # в phrase находится остаток фразы после названия скилла,
                                              # если юзер сказал больше
                                              # в этом плагине не используется
    arrR = [
        "Выпал орел",
        "Выпала решка",
    ]
    core.play_voice_assistant_speech(arrR[random.randint(0, len(arrR) - 1)])

Плагины по дефолту

Есть из наиболее интересного:

  • таймер

  • погода

  • электрички

  • контроль плейера MPC-HC

  • болталка с GPT-нейросетью

  • справка у GPT-нейросети (разница - использует нейросеть с интернет-поиском, чтобы предоставить точный ответ)

  • (комьюнити) MQTT-команды

  • (комьюнити) HomeAssistant интеграция (есть 3 плагина с несколько разной функциональностью)

  • (комьюнити) Запуск видео на плейере Dune HD

Оптимальные настройки STT (Speech-to-Text) и TTS (Text-to-Speech)

Работа голосового помощника очень сильно зависит от настройки STT и TTS — она может быть как наиболее точной и долгой, так и быстрой и менее точной (и с менее качественной озвучкой)

Мне важна максимальная отзывчивость, поэтому я использую связку «стриминговый STT от VOSK» с Windows TTS (pyttsx). Такая конфигурация начинает озвучивать ответ менее чем за 1 секунду после окончания произнесения команды (при возможности локальной обработки, например, если нужно что‑то загуглить, время будет больше).

Чуть менее оптимальной, но возможной на всех системах (не только Win), является рекомендуемая связка «стриминговый STT от VOSK» с Vosk TTS. Нейросетевой Vosk TTS очень на уровне, и при этом значительно быстрее, например, Silero, который тоже качественный. (Другой вариант для быстрого TTS — RHVoice, но его может быть немного проблемно ставить)

Для желающих максимального качества TTS — есть плагины для онлайн‑решений: Elevenlabs и OpenAI TTS (последний поддерживает настройку интонаций говорящего и доступен в России через VseGPT). Но онлайн всегда будет помедленнее.

Поддержка устройств

Лично я запускаю Ирину на старом домашнем ноутбуке, но знаю, что комьюнити допилило разные варианты для девайсов. Сам не ставил, но укажу:

  • Docker — работает в том числе под Малинки

  • ESP 32 — плагин для устройств ESP32-S3-BOX с прошивкой Willow позволяющий использовать их с Ириной в качестве приема команд и озвучивания ответов

Использование LLM

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

Сейчас существует плагин «болталка», который позволяет общаться или запрашивать справку у LLM по OpenAI‑совместимому API. По умолчанию он настроен на поддерживаемый мною же сервис VseGPT, который позволяет получать доступ к самым разным топовым нейросетям по OpenAI API; но при желании его легко, путем замены baseURL, можно перенаправить на нужный вам сервис, или на локальный инференс LLM типа LMStudio или Ollama.

В плагине поддерживается две команды:

  • поболтаем или поговорим — запускает диалог с LLM (id модели в настройке model). По умолчанию — GPT-4o‑mini.

  • справка — отправляет запрос другой LLM (id модели в настройке model_spravka). По умолчанию это онлайн‑модель Perplexity, которая дает свежую информацию с учетом интернет‑поиска.

..но «болталки» народу было мало, поэтому читаем далее — про версию 12.

Версия 12 Ирины — с поддержкой распознавания команд через LLM

Долгое время в Телеграм‑группе Ирины были пожелания «а можно сделать так, чтобы команды распознавались произвольно, а не по формату? Например „выключить свет во всем доме“.

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

Но в конечном счете я занялся этим сам :) в частности, потому что понял, что из комьюнити, возможно, лучше многих понимаю в протоколах LLM.

Итак, в 12версии сделана следующая функциональность: поддерживаются как классические плагины Ирины (команда + параметры), так и новые ИИ‑плагины (поддержка и тех и других — настройка уровня ядра)

ИИ‑плагины опираются на так называемую поддержку tools по OpenAI‑совестимому интерфейсу. Поддерживаются они не только OpenAI, сейчас это стандарт для всех, их поддерживают и Anthropic Claude, и Google Gemini, и опенсорс‑сети (DeepSeek, Qwen и пр.) — так что можно использовать почти любые сети. Работает это так:

  • Определяется список tools — формальных инструментов, которые может вызвать LLM. В каждом определяется функция и список типизированных параметров (например, для таймера это может быть три параметра: hours:int, minutes:int, seconds:int)

  • Каждый ИИ‑плагин определяет свои tools — одну или несколько. Ядро собирает все tools вместе.

  • Запрос пользователя отсылается в LLM с просьбой сказать, какую из предложенных tools выполнить, и с какими параметрами.

  • По получении ответа tool выполняется в коде. Бонус — коду плагина ничего расшифровывать «что сказал пользователь» не надо, он работает с типизированными параметрами.

Пример ИИ‑плагина:

Первое — определение tool в манифесте плагина (самое нудное, тут в промте надо описать все детали)

  "ai_tools": {
    "set_timer": {
        "v": "1", # версия описания AI Tool.
        # В зависимости от неё будет по-разному обрабатываться доп параметры
        "function": set_timer,
        "manifest": {
            "type": "function",
            "function": {
                # "name": "set_timer",
                # name будет автоматически присвоено на основании базового ключа словаря
                "description": "Set timer for specific time. "
                               "You must specify hours, minutes and seconds for it. All must be integers."
                               "If no specifications, set timer for 5 minutes, 0 hours, 0 seconds."
                               "Если указывается, например, на \"полминуты\", сконвертируй их в integer величины."
                               "Например, полминуты будет 30 секунд, полчаса - 30 минут.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "hours": {
                            "type": "integer",
                            "description": "Количество часов, на которое ставится таймер",
                        },
                        "minutes": {
                            "type": "integer",
                            "description": "Количество минут, на которое ставится таймер",
                        },
                        "seconds": {
                            "type": "integer",
                            "description": "Количество секунд, на которое ставится таймер",
                        },

                    },
                    "required": ["hours", "minutes", "seconds"],
                },
            },
        }
    }
}

А теперь сама функция, самое простое :)

def set_timer(core:VACore, hours:int, minutes:int, seconds:int):
    txt = "" # вычисляем текст, который надо будет произнести при установке таймера
    if hours > 0:
        txt += num_to_text.num2text(hours, male_units_hour)+" "
    if minutes > 0:
        txt += num_to_text.num2text(minutes, female_units_min)+" "
    if seconds > 0:
        txt += num_to_text.num2text(seconds, female_units_sec)+" "

    set_timer_real(core, hours*3600+minutes*60+seconds, txt)

def set_timer_real(core:VACore, num:int, txt:str):
    core.set_timer(num,(after_timer, txt))
    core.play_voice_assistant_speech("Ставлю таймер на "+txt)

Вызов «Ирина, поставь таймер на полчаса» выливается в «Ставлю таймер на 30 минут».

В общем, получается очень удобно.

Из минусов — при каждом вызове ИИ‑плагина надо делать запрос к LLM, что увеличивает задержку ответа.

Плюс, данная функциональность появилась только весной 2025 года, и поэтому плагинов с её использованием не очень много.

Заключение

Проект «Ирина» даже продолжает жить и немного развиваться, подстраиваясь под современные реалии. Если захотите вдруг сделать себе голосового помощника — мне кажется, проще настроить Ирину и что‑то дописать, чем делать все самому.

Надеюсь, было полезно.

Гитхаб проекта

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


  1. makartarentiev
    29.07.2025 12:56

    Вышла 12 версия русского опенсорс голосового помощника Ирина (900+ звезд Гитхаб)

    Простите но заголовок выглядит как "горячий одинокий голосовой помощник, жаждет общения, в 3 км от вас. Жми что бы познакомиться", ну а поделу, нечего сказать, хоть дома и две Алисы, сам не пользуюсь особо. А вот она тригеррится на имя кошки "ирис"...


    1. janvarev Автор
      29.07.2025 12:56

      Простите но заголовок выглядит как "горячий одинокий голосовой помощник, жаждет общения, в 3 км от вас. Жми что бы познакомиться"

      А вы другие заголовки на Хабре видели? ))))


      1. makartarentiev
        29.07.2025 12:56

        Тут вы меня подловили)


  1. JordanCpp
    29.07.2025 12:56

    Когда запилят Галину?:)


    1. Stanislavvv
      29.07.2025 12:56

      Когда потребуется что-нибудь отменять :-)
      "Галя, у нас отмена!"


  1. avshkol
    29.07.2025 12:56

    Не увидел требований к железу…