Skip to main content

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

Project description

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.jsonVoiceTrigger автоматически прочитает его при создании 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 — свободно используйте и модифицируйте.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

voicetrigger-1.0.4.tar.gz (25.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

voicetrigger-1.0.4-py3-none-any.whl (22.7 kB view details)

Uploaded Python 3

File details

Details for the file voicetrigger-1.0.4.tar.gz.

File metadata

  • Download URL: voicetrigger-1.0.4.tar.gz
  • Upload date:
  • Size: 25.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for voicetrigger-1.0.4.tar.gz
Algorithm Hash digest
SHA256 2b141c9d0d40e43c433d64f53ff99c93e030c64ac8f56cf8509383d6398cc089
MD5 e2ad8650a7ad81e43660adf037af1700
BLAKE2b-256 df8ffff790706fb8b639cb222c938c3701eb45f634a36c6c442a271b27ac9b40

See more details on using hashes here.

File details

Details for the file voicetrigger-1.0.4-py3-none-any.whl.

File metadata

  • Download URL: voicetrigger-1.0.4-py3-none-any.whl
  • Upload date:
  • Size: 22.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for voicetrigger-1.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 0edf59a87e6a77e5497d6f364800bca8cc5cf770ff490c8bca169d17a4fe0259
MD5 585ae50039803f53fec7f19380e988e5
BLAKE2b-256 24a3758195e57bc6a623e8d5dfed7a00e40affa7af9203b3a86df05f099e66e3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page