Initial commit
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
# vosk_stt.py
|
||||
import json
|
||||
import yaml
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from vosk import Model, KaldiRecognizer
|
||||
|
||||
class VoskSTT:
|
||||
def __init__(self, model_path="/home/sirmrak/models/vosk-model-small-ru-0.22", commands_file="/mnt/Project/my_speaker/commands/commands.yaml", sample_rate=16000):
|
||||
"""
|
||||
Инициализирует Vosk STT с моделью и словарем команд из YAML файла.
|
||||
|
||||
:param model_path: Путь к модели Vosk (vosk-model-small-ru-0.22)
|
||||
:param commands_file: Путь к файлу commands.yaml
|
||||
:param sample_rate: Частота дискретизации аудио (по умолчанию 16000)
|
||||
"""
|
||||
self.model_path = model_path
|
||||
self.commands_file = commands_file
|
||||
self.sample_rate = sample_rate
|
||||
self.model = None
|
||||
self.recognizer = None
|
||||
self._load_model()
|
||||
self._load_commands()
|
||||
|
||||
def _load_model(self):
|
||||
"""Загружает модель Vosk."""
|
||||
logger = logging.getLogger('VADApp')
|
||||
try:
|
||||
self.model = Model(self.model_path)
|
||||
logger.info(f"Модель Vosk загружена: {self.model_path}")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка загрузки модели: {e}")
|
||||
raise
|
||||
|
||||
def _load_commands(self):
|
||||
"""Формирует словарь (список фраз) из commands.yaml и инициализирует recognizer."""
|
||||
logger = logging.getLogger('VADApp')
|
||||
try:
|
||||
with open(self.commands_file, 'r', encoding='utf-8') as f:
|
||||
commands = yaml.safe_load(f)
|
||||
|
||||
phrases = []
|
||||
|
||||
# Собираем все фразы из всех разделов
|
||||
for section, content in commands.items():
|
||||
if section in ['Wakewords', 'Session']:
|
||||
# Обрабатываем списки с вложенными phrases
|
||||
for item in content:
|
||||
if isinstance(item, dict) and 'phrases' in item:
|
||||
phrases.extend(item['phrases'])
|
||||
elif section == 'Volume':
|
||||
# Обрабатываем новую структуру Volume с приоритетом
|
||||
for item in content:
|
||||
if isinstance(item, dict) and 'commands' in item:
|
||||
phrases.extend(list(item['commands'].keys()))
|
||||
elif section == 'Text':
|
||||
# Обрабатываем новую структуру Text с приоритетом
|
||||
for item in content:
|
||||
if isinstance(item, dict) and 'commands' in item:
|
||||
phrases.extend(list(item['commands'].keys()))
|
||||
|
||||
# Удаляем дубликаты и сортируем
|
||||
phrases = sorted(set(phrases))
|
||||
|
||||
# Инициализируем recognizer с грамматикой (списком фраз)
|
||||
grammar = json.dumps(phrases, ensure_ascii=False)
|
||||
self.recognizer = KaldiRecognizer(self.model, self.sample_rate, grammar)
|
||||
|
||||
logger.info(f"Словарь команд загружен: {len(phrases)} фраз")
|
||||
logger.debug(f"Фразы: {phrases}")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка загрузки команд: {e}")
|
||||
raise
|
||||
|
||||
def recognize(self, audio_data):
|
||||
"""
|
||||
Распознает речь из аудио данных (bytes).
|
||||
|
||||
:param audio_data: Bytes аудио (16-bit PCM, mono)
|
||||
:return: Распознанный текст или None если ничего не распознано
|
||||
"""
|
||||
logger = logging.getLogger('VADApp')
|
||||
try:
|
||||
if not self.recognizer.AcceptWaveform(audio_data):
|
||||
# Частичный результат (если нужно, но для коротких команд используем Final)
|
||||
partial = json.loads(self.recognizer.PartialResult()).get("partial", "")
|
||||
if partial:
|
||||
logger.debug(f"Частичный результат: {partial}")
|
||||
result = json.loads(self.recognizer.FinalResult()).get("text", "")
|
||||
if result:
|
||||
logger.info(f"Распознанная команда: {result}")
|
||||
return result
|
||||
else:
|
||||
logger.info("Ничего не распознано")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка распознавания: {e}")
|
||||
return None
|
||||
|
||||
def reload_commands(self):
|
||||
"""Перезагружает словарь команд из файла."""
|
||||
self._load_commands()
|
||||
Reference in New Issue
Block a user