Разбираем баг распознавания речи в Python: почему Catbot не слышал своё имя и как мы исправили это через грамматику Vosk. Практические советы внутри!
Представьте: вы создали десктоп-питомца, который должен реагировать на голосовые команды, но он упорно называет вас «kappa» и спорит, что его зовут Catbot, а не «cat bought». Знакомо? В этой статье я расскажу, как я столкнулся с такой проблемой и что помогло её решить. Вы узнаете, как работает распознавание речи на примере Vosk, почему стандартные модели не понимают выдуманные слова и как использовать грамматику для точного управления.
Мой десктоп-питомец Catbot использовал веб-камеру в качестве микрофона. Она улавливала все звуки в комнате, из-за чего Catbot часто перебивал меня или неправильно распознавал слова. Я увеличил паузу тишины с 0.5 до 1.5 секунд, чтобы он дослушивал фразу до конца, но главная беда осталась: Catbot не понимал своё имя. Он слышал «catfight», «cat bought» и даже «Lawrence». После долгих экспериментов я понял: дело не только в железе, но и в модели распознавания.
Vosk использует модель на основе Kaldi, которая декодирует аудио через конечный автомат HCLG. Этот автомат состоит из четырёх слоёв: H, C, L и G. Слой G — это грамматика, которая определяет, какие последовательности слов возможны. В модели vosk-model-en-us-0.22 граф уже заморожен, и туда нельзя добавить новые слова. Поэтому слово «Catbot» (которого нет в словаре) заменяется на ближайшее по звучанию — «kappa». Это классическая ошибка: модель выбирает наиболее вероятное слово, даже если оно не то, что вы сказали.
Я нашёл модель vosk-model-en-us-0.22-lgraph, которая поддерживает динамическую грамматику. Это значит, что можно задать список разрешённых фраз, и модель будет распознавать только их. Я создал второй распознаватель, который слушает только команды для Catbot: «cat bot engage», «wake up» и т.д. Если фраза не подходит, возвращается [unk] (неизвестно). Так Catbot стал чётко реагировать на своё имя, а не на «kappa».
Вот фрагмент кода, который строит грамматику:
import json
from pathlib import Path
# Список вариантов произношения имени
WAKE_NAME_FORMS = ["cat bot", "cat pot", "cat bought"]
# Что может следовать за именем
GRAMMAR_TAILS = ["", "engage", "wake up", "sleep"]
def build_grammar(model):
"""Строит JSON-список фраз, отфильтровывая слова вне словаря."""
phrases = set()
for lead in ("", "hey"):
for name in WAKE_NAME_FORMS:
for tail in GRAMMAR_TAILS:
phrases.add(f"{lead} {name} {tail}".strip())
# Проверяем, что каждое слово есть в модели
kept = []
for phrase in sorted(phrases):
words = phrase.split()
if all(model.find_word(w) >= 0 for w in words):
kept.append(phrase)
# Добавляем [unk] как запасной вариант
kept.append("[unk]")
return json.dumps(kept)Этот код создаёт список фраз, которые модель может распознать. Важно, что все слова должны быть в словаре модели. Если слово отсутствует (например, «catbot»), его нужно разбить на части, которые есть в словаре: «cat bot».
Если вы сталкиваетесь с проблемами распознавания речи, попробуйте следующее:
-lgraph).Эти шаги помогут вам избежать ошибок, подобных моей, и сделать голосовое управление надёжным. Попробуйте прямо сейчас настройте свою модель и проверьте, как она реагирует на ваши команды!
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →