135 lines
7.0 KiB
Python
135 lines
7.0 KiB
Python
# app/core/vad.py
|
||
from fastapi import Request
|
||
import os
|
||
from app.core.config import get_settings
|
||
from typing import Tuple, Dict, Any, Optional
|
||
import logging
|
||
from app.core.status import status_tracker, SystemStatus # Добавлено
|
||
from app.core.history import add_recognized_phrase
|
||
logger = logging.getLogger('VADApp')
|
||
|
||
def get_vad_instance(request: Request):
|
||
"""Получение экземпляра VAD из состояния приложения"""
|
||
return getattr(request.app.state, 'vad_instance', None)
|
||
|
||
def get_stt_instance(request: Request):
|
||
"""Получение экземпляра STT из состояния приложения"""
|
||
return getattr(request.app.state, 'stt_instance', None)
|
||
|
||
def get_commands(request: Request):
|
||
"""Получение команд из состояния приложения"""
|
||
return getattr(request.app.state, 'commands', None)
|
||
|
||
def init_vad_and_stt(request: Request = None) -> Tuple[Any, Any, Dict[str, Any], Any]:
|
||
"""Инициализация VAD и STT"""
|
||
logger.debug("Инициализация VAD и STT")
|
||
status_tracker.set_status(SystemStatus.INITIALIZATION) # Добавлено
|
||
try:
|
||
# Импортируем здесь, чтобы избежать циклических импортов
|
||
from vad_core import VADPolling
|
||
from vosk_local_STT import VoskSTT # Исправлено с vosk_stt на vosk_local_STT
|
||
from commands import handle_command
|
||
from session_manager import SessionManager
|
||
from volume import set_volume
|
||
|
||
config = get_settings()
|
||
commands = {}
|
||
|
||
# Инициализация громкости аудиоустройств
|
||
try:
|
||
# Устанавливаем громкость для устройства воспроизведения
|
||
set_volume(config.audio_settings.playback_device, config.audio_settings.playback_volume, mixer_type='Playback')
|
||
# Устанавливаем громкость для устройства записи
|
||
set_volume(config.audio_settings.capture_device, config.audio_settings.capture_volume, mixer_type='Capture')
|
||
logger.info(f"Громкость устройств инициализирована: воспроизведение={config.audio_settings.playback_volume}%, запись={config.audio_settings.capture_volume}%")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при инициализации громкости: {e}")
|
||
|
||
# Загружаем команды из файла
|
||
if config.commands.commands_file and os.path.exists(config.commands.commands_file):
|
||
from ruamel.yaml import YAML
|
||
yaml = YAML()
|
||
with open(config.commands.commands_file, 'r', encoding='utf-8') as f:
|
||
commands = yaml.load(f) or {}
|
||
|
||
# Инициализируем SessionManager
|
||
session_manager = SessionManager(config.session.session_timeout_seconds)
|
||
logger.info(f"SessionManager инициализирован с таймаутом {config.session.session_timeout_seconds} секунд")
|
||
|
||
# Инициализируем STT
|
||
stt_instance = VoskSTT(
|
||
model_path=config.stt.model_path,
|
||
commands_file=config.commands.commands_file,
|
||
sample_rate=config.vad.sample_rate
|
||
)
|
||
|
||
# Функция обработки распознанной речи
|
||
def process_speech(audio_data, sample_rate):
|
||
try:
|
||
status_tracker.set_status(SystemStatus.RECOGNITION) # Добавлено
|
||
recognized = stt_instance.recognize(audio_data)
|
||
if recognized:
|
||
logger.info(f"Команда распознана: {recognized}")
|
||
status_tracker.set_status(SystemStatus.COMMAND_PROCESSING) # Добавлено
|
||
action = handle_command(recognized, commands, session_manager)
|
||
status_tracker.set_status(SystemStatus.RESPONSE) # Добавлено (предполагая, что здесь происходит ответ; если нет, удалите)
|
||
|
||
# Добавляем распознанную фразу в историю
|
||
|
||
if action:
|
||
add_recognized_phrase(recognized, action=action)
|
||
except Exception as e:
|
||
logger.error(f"Ошибка обработки речи: {e}")
|
||
status_tracker.set_status(SystemStatus.LISTENING) # Добавлено (возврат к прослушиванию)
|
||
|
||
# Инициализируем VAD
|
||
vad_config = config.vad.dict()
|
||
vad_config['polling_interval_ms'] = config.system.polling_interval_ms
|
||
vad_config['history_maxlen'] = config.system.history_maxlen
|
||
vad_instance = VADPolling(vad_config, on_speech_end_callback=process_speech)
|
||
|
||
logger.info("VAD и STT инициализированы")
|
||
status_tracker.set_status(SystemStatus.LISTENING) # Добавлено
|
||
return vad_instance, stt_instance, commands, session_manager
|
||
except Exception as e:
|
||
logger.error(f"Ошибка инициализации VAD/STT: {e}", exc_info=True)
|
||
raise
|
||
|
||
def cleanup_vad_and_stt(vad_instance, stt_instance):
|
||
"""Завершение работы VAD и STT"""
|
||
logger.debug("Завершение работы VAD и STT")
|
||
try:
|
||
if vad_instance:
|
||
logger.info("Завершаем VAD...")
|
||
vad_instance.close()
|
||
if stt_instance:
|
||
logger.info("Завершаем STT...")
|
||
stt_instance = None
|
||
logger.info("VAD и STT завершены")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка завершения VAD/STT: {e}")
|
||
|
||
def restart_vad_and_stt(request: Request):
|
||
"""Перезапуск VAD и STT с новыми настройками"""
|
||
logger.info("Перезапуск VAD и STT")
|
||
status_tracker.set_status(SystemStatus.INITIALIZATION) # Добавлено
|
||
try:
|
||
# Завершаем текущие экземпляры
|
||
vad_instance = get_vad_instance(request)
|
||
stt_instance = get_stt_instance(request)
|
||
cleanup_vad_and_stt(vad_instance, stt_instance)
|
||
|
||
# Инициализируем новые экземпляры
|
||
vad_instance, stt_instance, commands = init_vad_and_stt()
|
||
|
||
# Обновляем состояние приложения
|
||
request.app.state.vad_instance = vad_instance
|
||
request.app.state.stt_instance = stt_instance
|
||
request.app.state.commands = commands
|
||
|
||
logger.info("VAD и STT перезапущены")
|
||
status_tracker.set_status(SystemStatus.LISTENING) # Добавлено
|
||
return True
|
||
except Exception as e:
|
||
logger.error(f"Ошибка перезапуска VAD/STT: {e}", exc_info=True)
|
||
raise |