Realtime-распознаватель речи на базе Vosk: управление микрофоном, детекция уровня голоса (whisper / normal / shout), опциональное шумоподавление, декораторный API для обработки текста, ключевых слов и быстрых команд.
Project description
VoiceTrigger
Realtime-распознаватель речи на базе Vosk: управление микрофоном, детекция уровня голоса (whisper / normal / shout), опциональное шумоподавление, декораторный API для обработки текста, ключевых слов и быстрых команд.
Содержание
- Установка
- Пример: простой голосовой помощник
- Управление (методы и рекомендации)
- Декораторы и
Filter(API событий) - Калибровка голоса (calibrate_voice.py)
- Конфиг для mode — как создать и применить
- Выбор микрофона вручную
- Режим шумоподавления (опционально)
- Отладка, советы и частые ошибки
- Структура проекта
- Лицензия
Установка
Установка через репозиторий
-
Склонируйте или скопируйте проект в папку:
git clone https://github.com/REYIL/VoiceTrigger.git cd VoiceTrigger
-
Установите зависимости:
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 попытается перезапустить поток (может потребоваться освобождение устройства системой).
Режим шумоподавления (опционально)
Можно включить встроенное шумоподавление для микрофона. Для этого необходимо:
-
Установить зависимости:
pip install noisereduce scipy
-
Включить режим в коде:
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b141c9d0d40e43c433d64f53ff99c93e030c64ac8f56cf8509383d6398cc089
|
|
| MD5 |
e2ad8650a7ad81e43660adf037af1700
|
|
| BLAKE2b-256 |
df8ffff790706fb8b639cb222c938c3701eb45f634a36c6c442a271b27ac9b40
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0edf59a87e6a77e5497d6f364800bca8cc5cf770ff490c8bca169d17a4fe0259
|
|
| MD5 |
585ae50039803f53fec7f19380e988e5
|
|
| BLAKE2b-256 |
24a3758195e57bc6a623e8d5dfed7a00e40affa7af9203b3a86df05f099e66e3
|