Files

135 lines
7.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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