Skip to main content

Python Versions (3.8, 3.9, 3.10, 3.11, 3.12) Vosk License

VoiceTrigger

Realtime-распознаватель речи на базе Vosk: управление микрофоном, детекция уровня голоса (whisper / normal / shout), опциональное шумоподавление, декораторный API для обработки текста, ключевых слов и быстрых команд.


Содержание

  1. Установка
  2. Пример: простой голосовой помощник
  3. Управление (методы и рекомендации)
  4. Декораторы и Filter (API событий)
  5. Калибровка голоса (calibrate_voice.py)
  6. Конфиг для mode — как создать и применить
  7. Выбор микрофона вручную
  8. Режим шумоподавления (опционально)
  9. Отладка, советы и частые ошибки
  10. Структура проекта
  11. Лицензия

Установка

Установка через репозиторий

  1. Склонируйте или скопируйте проект в папку:

    git clone https://github.com/REYIL/VoiceTrigger.git
    cd VoiceTrigger
    
  2. Установите зависимости:

    pip install -r requirements.txt
    

Установка через pip

pip install VoiceTrigger

Дополнительно

  • Скачайте Vosk-модель (например, model_small) с официального сайта Vosk.
  • Укажите путь к модели в параметре model_path при использовании пакета.

Пример: простой голосовой помощник

Пример использования VoiceTrigger. В этом примере помощник «просыпается» по ключевому слову Алиса, слушает фразы, реагирует на быстрые команды (quick_words), и по длительной тишине возвращается в режим прослушивания ключевых слов.

import asyncio
import time
from pathlib import Path
from VoiceTrigger import (
    VoiceTrigger,
    Filter, TextContext,
    ColorLogger, Mode
)

rms_thresholds = {
    "whisper": -43.0,
    "normal": -15.0,
    "shout": 0.0
}

bot = VoiceTrigger(
    model_path="model_small",  # Путь к модели
    keywords=["Алиса"],  # Не обязательно, может брать автоматически с Filter
    quick_words=["стоп", "назад", "вперед"],  # Не обязательно, может брать автоматически с Filter
    # calibration_path=Path("voice_calibration.json"),
        # Путь указывать не обязательно
        # Если не указывать будет пытаться брать из "voice_calibration.json", а если файла не будет то определение будет работать по системным параметрам
    # rms_thresholds=rms_thresholds,
        # Если калибровка работает плохо, можно сделать ручную настройку
    device=None,  # Устройство ввода, если не указывать выберет сам
    logger=ColorLogger(level="debug")  # Логгер
)

state = {"active_until": 0.0}


@bot.keyword(Filter("Алиса"))
async def on_alisa(ctx: TextContext):
    bot.log.info(f"[KW] {ctx.match} mode={ctx.mode}")
    bot.start_recognition_main()
    bot.stop_recognition_keywords()
    state["active_until"] = time.time() + 10.0


@bot.quick(Filter(["стоп", "пауза"]))
async def on_quick(ctx: TextContext):
    bot.log.info(f"[QUICK] {ctx.match} mode={ctx.mode}")
    if ctx.match and ctx.match.lower() == "стоп":
        bot.stop_recognition_main()
        bot.start_recognition_keywords()
        state["active_until"] = 0.0


@bot.text()
async def on_all_text(ctx: TextContext):
    if ctx.match is None and ctx.text:
        bot.log.info(f"[TEXT] mode={ctx.mode} text='{ctx.text}'")


@bot.text(Filter(["привет", "здарова"], lv=10, mode=Mode.normal))
async def on_greeting(ctx: TextContext):
    bot.log.info(f"[GREETING] {ctx.match} text='{ctx.text}' mode={ctx.mode}")


@bot.on_silence()  # Возвращает время с последнего quick_words
async def handle_silence_main(sec: float):
    now = time.time()
    if 0 < state["active_until"] <= now and bot.active_main and sec >= 10.0:
        bot.log.info(f"[Silence] {sec:.1f}s -> back to keywords")
        bot.stop_recognition_main()
        bot.start_recognition_keywords()
        state["active_until"] = 0.0


# @bot.on_kw_silence()  # Возвращает время с последнего keywords
# async def handle_kw_silence(sec: float):
#     if sec >= 5.0:
#         bot.log.debug(f"[KW Silence] {sec:.1f}s with no keywords")


if __name__ == "__main__":
    devices = bot.list_input_devices()  # Вывод всех аудио устройств
    bot.log.debug(f"Available input devices: {devices}")
    try:
        asyncio.run(bot.run(initial_keywords_mode=True))  # Запуск с вначале включенным keywords_mode
    except KeyboardInterrupt:
        bot.log.info("Interrupted by user.")

Управление (методы и рекомендации)

Основные методы:

  • start_recognition_main() — включить основной режим распознавания (continuous).
  • stop_recognition_main() — выключить основной режим.
  • start_recognition_keywords() — включить режим прослушивания ключевых слов.
  • stop_recognition_keywords() — выключить режим ключевых слов.
  • reload_model(new_model_path=None) — перезагрузить Vosk-модель (опционально указать новый путь).
  • list_input_devices() — вернуть список доступных входных устройств (index, name, max_input_channels).
  • set_input_device(device, restart_stream=False) — установить устройство ввода (индекс или имя). restart_stream=True попытается перезапустить поток.

Рекомендации:

  • Не рекомендуется включать одновременно main и keywords. Эти режимы имеют разные цели — keywords оптимизирован для обнаружения wake-word, main — для непрерывной речи.
  • Если нужна быстрая реакция на короткие команды, используйте quick_words совместно с main — quick-обработчики работают параллельно с основным распознаванием и оптимизированы под короткие команды.
  • keyword-режим хорош для «пробуждения» (wake word). Обычно вы запускаете keywords по умолчанию, а при обнаружении wake-word временно переключаетесь в main.

Декораторы и Filter (API событий)

Декораторы:

  • @bot.text(FILTER?) — обработчики общего текста (по умолчанию wildcard). Аргумент — TextContext.
  • @bot.keyword(FILTER?) — обработчики ключевых слов; указанные фразы добавляются в список keywords.
  • @bot.quick(FILTER?) — быстрые команды (короткие слова/фразы).
  • @bot.on_silence() — обработчики тишины для main (параметр — количество секунд молчания).
  • @bot.on_kw_silence() — обработчики тишины для keywords.

Filter:

Filter(phrases=None | "слово" | ["а","б"], lv=10, mode=Mode.normal|whisper|shout)
  • phrases — список фраз; пустой список / None → wildcard (обработчик принимает все тексты).
  • lv — процент допуска ошибок для Levenshtein (число 0..100). Чем больше — тем сильнее допускаются отличия при сравнении.
  • mode — (Mode.whisper, Mode.normal, Mode.shout) — если указан, обработчик вызовется только при совпадении голосового режима.

Контекст обработчика (TextContext):

  • text — распознанный текст (final/partial).
  • mode — строка: "whisper" | "normal" | "shout".
  • match — совпавшая фраза из Filter или None (для wildcard).
  • timestamp — время события (epoch).

Калибровка голоса

В проекте есть модуль VoiceCalibrator, она собирает статистику по трём уровням речи (quiet, normal, loud) и сохраняет voice_calibration.json. Этот файл используется VoiceTrigger для адаптивной настройки порогов RMS/HF и порога тишины.

Запуск калибровки:

from pathlib import Path

from VoiceTrigger import VoiceCalibrator

CALIBRATION_PATH = Path(__file__).parent / "voice_calibration.json"

VoiceCalibrator.calibrate(calibration_path=CALIBRATION_PATH)  # Путь указывать не обязательно

Скрипт попросит записать несколько фрагментов для каждого уровня и сохранит средние значения в voice_calibration.json.

Почему калибровка полезна:

  • Подстраивает пороги под конкретный микрофон, акустику комнаты и расстояние до источника.
  • Повышает корректность определения whisper/normal/shout.

Минусы калибровки:

  • Требует аккуратного прохождения процедуры пользователем — если человек говорит слишком громко или тихо, результаты могут быть некорректными.
  • Чувствительна к положению микрофона: смена расстояния или угла может сильно изменить RMS и HF, что исказит пороги.
  • Автопороги могут оказаться слишком близко друг к другу, особенно если различие между whisper, normal и shout маленькое — классификация становится менее надёжной.
  • Плохие условия записи (шум, эхо, фоновые источники) могут «засорить» калибровку.
  • При многократной смене среды/оборудования нужна новая калибровка, иначе точность падает.

Конфиг для mode — как создать и применить

Можно задать пороги вручную через JSON-конфиг, либо использовать voice_calibration.json, полученный через calibrate_voice.py.

Пример mode_config.json:

{
  "rms_thresholds": {
    "whisper": -45.0,
    "normal": -18.0,
    "shout": -1.0
  },
  "hf_ratio_threshold": 1.5,
  "silence_db": -46.0
}

Применение конфигурации в коде:

import json
from pathlib import Path
from VoiceTrigger import VoiceTrigger

cfg = json.loads(Path("mode_config.json").read_text(encoding="utf-8"))
bot = VoiceTrigger(...)

bot.voice_detector.rms_thresholds = cfg.get("rms_thresholds", bot.voice_detector.rms_thresholds)
bot.voice_detector.hf_ratio_threshold = cfg.get("hf_ratio_threshold", bot.voice_detector.hf_ratio_threshold)
bot.voice_detector.silence_db = cfg.get("silence_db", bot.voice_detector.silence_db)

Или положите результаты калибровки в voice_calibration.json — VoiceTrigger автоматически прочитает его при создании VoiceTrigger (если файл доступен).

А также можно использовать rms_thresholds

from VoiceTrigger import VoiceTrigger, ColorLogger

rms_thresholds = {
    "whisper": -43.0,
    "normal": -15.0,
    "shout": 0.0
}

bot = VoiceTrigger(
    model_path="model_small",
    quick_words=["стоп", "назад", "вперед", "какая погода"],
    logger=ColorLogger(level="debug"),
    rms_thresholds=rms_thresholds
)

Выбор микрофона вручную

Список устройств:

devices = VoiceTrigger.list_input_devices()
# или через экземпляр:
devices = bot.list_input_devices()

Установка устройства:

  • При инициализации:
bot = VoiceTrigger(..., device=2)  # индекс
# или
bot = VoiceTrigger(..., device="USB Microphone")  # имя устройства
  • Во время работы:
bot.set_input_device(2, restart_stream=True)

restart_stream=True попытается перезапустить поток (может потребоваться освобождение устройства системой).


Режим шумоподавления (опционально)

Можно включить встроенное шумоподавление для микрофона. Для этого необходимо:

  1. Установить зависимости:

    pip install noisereduce scipy
    
  2. Включить режим в коде:

    bot = VoiceTrigger(..., noise_reduction=True)
    

Когда использовать:

  • если в помещении много фонового шума (ПК-вентиляторы, улица, кондиционер),
  • при записи на встроенные микрофоны ноутбука,
  • если нужно повысить точность распознавания.

Отладка, советы и частые ошибки

  • Включите подробный логгер:
logger = ColorLogger(level="debug")
bot = VoiceTrigger(..., logger=logger)
  • Если модель не загружается — проверьте model_path и файлы модели.

  • Если нет звука или пустые результаты — проверьте sounddevice.query_devices() и системные права доступа к микрофону.

  • Если плохое распознавание:

    • проверьте sample rate (обычно 16000),
    • расположение микрофона,
    • при необходимости запустите calibrate_voice.py,
    • попробуйте включить noise_reduction (если установлен noisereduce).
  • Для коротких команд используйте quick_words (работают быстрее и подходят для single-word commands).


Структура проекта

.
├── model_small # vosk
├── voicetrigger
│   ├── core
│   │   ├── asmanager.py
│   │   ├── decorators.py
│   │   ├── speechr.py
│   │   └── vldetector.py
│   ├── services
│   │   └── calibration.py
│   ├── utils
│   │   ├── filter.py
│   │   ├── levenshtein.py
│   │   └── logger.py
│   └── __init__.py
├── main.py
└── requirements.txt

Лицензия

MIT License — свободно используйте и модифицируйте.

Metadata

Release files for VoiceTrigger 1.0.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for VoiceTrigger 1.0.4
File Size Uploaded
voicetrigger-1.0.4.tar.gz 25.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for VoiceTrigger 1.0.4
File Interpreter ABI Platform
voicetrigger-1.0.4-py3-none-any.whl Python 3 none any Details

Total release size: 48.6 kB

Release files / voicetrigger-1.0.4.tar.gz

Download URL voicetrigger-1.0.4.tar.gz
Size 25.9 kB
Tags Source
SHA-256 checksum
How to use checksums
2b141c9d0d40e43c433d64f53ff99c93e030c64ac8f56cf8509383d6398cc089
BLAKE2b-256 checksum
How to use checksums
df8ffff790706fb8b639cb222c938c3701eb45f634a36c6c442a271b27ac9b40
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release files / voicetrigger-1.0.4-py3-none-any.whl

Download URL voicetrigger-1.0.4-py3-none-any.whl
Size 22.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0edf59a87e6a77e5497d6f364800bca8cc5cf770ff490c8bca169d17a4fe0259
BLAKE2b-256 checksum
How to use checksums
24a3758195e57bc6a623e8d5dfed7a00e40affa7af9203b3a86df05f099e66e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release history Release notifications | RSS feed

This release

1.0.4 This release

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page