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

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. Склонируйте/скопируйте проект в папку.
  2. Установите зависимости:
pip install -r requirements.txt

Через pip

pip install VoiceTrigger

Также скачайте Vosk-модель (например, model_small) и укажите путь в 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.1.tar.gz (25.5 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.1-py3-none-any.whl (22.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: voicetrigger-1.0.1.tar.gz
  • Upload date:
  • Size: 25.5 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.1.tar.gz
Algorithm Hash digest
SHA256 a5935cfeb3293a57c1514fea9bb6af76bc602db8dcb9f338d5f9d0004f772858
MD5 eef0d452f71da814696c3f0358deb34b
BLAKE2b-256 df5ef2030584c936fb03ca902ebf79609cb899bd8abba0e57eb5b0ec3279718e

See more details on using hashes here.

File details

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

File metadata

  • Download URL: voicetrigger-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 22.5 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5b1c8677376aaacbe3ecdb939f10badc0a7eec8195f9ada9e81a9b784d2e6c5e
MD5 a827b1dd9883c0c46cc698b9598ca674
BLAKE2b-256 bf37eacb1a3ca9058bd864abdebd810fecb4af05ba3c9d29c0b1435e94f6fef2

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