181 lines
7.1 KiB
Python
181 lines
7.1 KiB
Python
# app/core/config.py
|
|
import os
|
|
import logging
|
|
from typing import Dict, Any, Optional
|
|
from pydantic import BaseModel, Field
|
|
from ruamel.yaml import YAML
|
|
from functools import lru_cache
|
|
|
|
# Инициализация логгера
|
|
logger = logging.getLogger('VADApp')
|
|
|
|
# Путь к файлу конфигурации
|
|
CONFIG_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'config.yaml')
|
|
class AuthConfig(BaseModel):
|
|
username: str = "admin"
|
|
password: str = "admin"
|
|
|
|
class VADConfig(BaseModel):
|
|
mode: int = 1
|
|
sample_rate: int = 16000
|
|
frame_duration_ms: int = 30
|
|
ring_buffer_size: int = 20
|
|
speech_threshold: float = 0.5
|
|
energy_threshold: int = 1000
|
|
min_speech_duration_ms: int = 300
|
|
record_stop_delay_sec: float = 1.0
|
|
prebuffer_duration_sec: float = 1.0
|
|
max_record_duration_sec: float = 5.0
|
|
target_rms: float = 2000.0
|
|
max_gain: float = 5.0
|
|
noise_reduction_factor: float = 1.5
|
|
noise_update_alpha: float = 0.05
|
|
min_rms_threshold_factor: float = 2.0
|
|
gain_smoothing_alpha: float = 0.1
|
|
adaptive_energy_std_factor: float = 2.5
|
|
adaptive_energy: bool = True
|
|
noise_reduction_enabled: bool = True
|
|
auto_gain_enabled: bool = True
|
|
record_on_speech: bool = True
|
|
|
|
class SystemConfig(BaseModel):
|
|
history_maxlen: int = 100
|
|
polling_interval_ms: int = 500
|
|
logging_level: str = "INFO"
|
|
log_file: str = "logs/app.log"
|
|
log_save_file: bool = True
|
|
|
|
class STTConfig(BaseModel):
|
|
model_path: str = ""
|
|
|
|
class CommandsConfig(BaseModel):
|
|
commands_file: str = ""
|
|
|
|
class SessionConfig(BaseModel):
|
|
session_timeout_seconds: int = 30
|
|
|
|
class TTSConfig(BaseModel):
|
|
host: str = "192.168.200.81"
|
|
port: int = 10200
|
|
timeout: int = 30
|
|
pause_duration: float = 0.5
|
|
post_stop_wait: float = 1.0
|
|
voice: str = "ru_RU-ruslan-medium"
|
|
save_TTS_files: bool = False
|
|
|
|
class AudioSettingsConfig(BaseModel):
|
|
playback_device: int = 0
|
|
capture_device: int = 0
|
|
playback_volume: int = 80
|
|
capture_volume: int = 90
|
|
|
|
class Settings(BaseModel):
|
|
auth: AuthConfig = Field(default_factory=AuthConfig)
|
|
vad: VADConfig = Field(default_factory=VADConfig)
|
|
system: SystemConfig = Field(default_factory=SystemConfig)
|
|
stt: STTConfig = Field(default_factory=STTConfig)
|
|
commands: CommandsConfig = Field(default_factory=CommandsConfig)
|
|
session: SessionConfig = Field(default_factory=SessionConfig)
|
|
tts: TTSConfig = Field(default_factory=TTSConfig)
|
|
audio_settings: AudioSettingsConfig = Field(default_factory=AudioSettingsConfig)
|
|
|
|
def setup_logging(logging_level='INFO'):
|
|
"""Настройка уровня логирования"""
|
|
logger.debug(f"Установка уровня логирования: {logging_level}")
|
|
try:
|
|
logger.setLevel(getattr(logging, logging_level.upper(), logging.INFO))
|
|
logger.info(f"Уровень логирования установлен: {logging_level}")
|
|
except Exception as e:
|
|
logger.error(f"Ошибка настройки логирования: {e}", exc_info=True)
|
|
raise
|
|
|
|
def load_yaml_config() -> Dict[str, Any]:
|
|
"""Загрузка конфигурации из YAML файла"""
|
|
logger.debug("Загрузка конфигурации из YAML")
|
|
try:
|
|
yaml = YAML()
|
|
yaml.preserve_quotes = True
|
|
if not os.path.exists(CONFIG_PATH):
|
|
logger.error(f"Файл конфигурации не найден: {CONFIG_PATH}")
|
|
raise FileNotFoundError(f"Файл конфигурации не найден: {CONFIG_PATH}")
|
|
with open(CONFIG_PATH, 'r', encoding='utf-8') as f:
|
|
config = yaml.load(f) or {}
|
|
|
|
# Проверяем и адаптируем пути для текущей ОС
|
|
if 'commands' in config and 'commands_file' in config['commands']:
|
|
commands_file = config['commands']['commands_file']
|
|
# Преобразуем путь для текущей ОС, если необходимо
|
|
commands_file = os.path.normpath(commands_file)
|
|
config['commands']['commands_file'] = commands_file
|
|
logger.debug(f"Путь к файлу команд: {commands_file}")
|
|
|
|
if 'stt' in config and 'model_path' in config['stt']:
|
|
model_path = config['stt']['model_path']
|
|
# Преобразуем путь для текущей ОС, если необходимо
|
|
model_path = os.path.normpath(model_path)
|
|
config['stt']['model_path'] = model_path
|
|
logger.debug(f"Путь к модели STT: {model_path}")
|
|
|
|
return config
|
|
except Exception as e:
|
|
logger.error(f"Ошибка загрузки конфигурации: {e}", exc_info=True)
|
|
raise
|
|
|
|
@lru_cache()
|
|
def get_settings() -> Settings:
|
|
"""Получение настроек приложения (кэшируется)"""
|
|
config = load_yaml_config()
|
|
|
|
# Создаем объект настроек
|
|
settings = Settings(
|
|
auth=AuthConfig(**config.get('auth', {})),
|
|
vad=VADConfig(**config.get('vad', {})),
|
|
system=SystemConfig(**config.get('system', {})),
|
|
stt=STTConfig(**config.get('stt', {})),
|
|
commands=CommandsConfig(**config.get('commands', {})),
|
|
tts=TTSConfig(**config.get('tts', {})),
|
|
audio_settings=AudioSettingsConfig(**config.get('audio_settings', {}))
|
|
)
|
|
|
|
# Настраиваем логирование
|
|
setup_logging(settings.system.logging_level)
|
|
|
|
return settings
|
|
|
|
def save_settings(settings: Settings) -> bool:
|
|
"""Сохранение настроек в YAML файл"""
|
|
logger.debug("Сохранение конфигурации")
|
|
try:
|
|
# Загружаем текущую конфигурацию
|
|
yaml = YAML()
|
|
yaml.indent(mapping=2, sequence=4, offset=2)
|
|
yaml.preserve_quotes = True
|
|
|
|
if not os.path.exists(CONFIG_PATH):
|
|
logger.error(f"Файл конфигурации не найден: {CONFIG_PATH}")
|
|
raise FileNotFoundError(f"Файл конфигурации не найден: {CONFIG_PATH}")
|
|
|
|
with open(CONFIG_PATH, 'r', encoding='utf-8') as f:
|
|
config = yaml.load(f) or {}
|
|
|
|
# Обновляем конфигурацию
|
|
config['auth'] = settings.auth.dict()
|
|
config['vad'] = settings.vad.dict()
|
|
config['system'] = settings.system.dict()
|
|
config['stt'] = settings.stt.dict()
|
|
config['commands'] = settings.commands.dict()
|
|
config['tts'] = settings.tts.dict()
|
|
config['audio_settings'] = settings.audio_settings.dict()
|
|
|
|
# Сохраняем обновленную конфигурацию
|
|
with open(CONFIG_PATH, 'w', encoding='utf-8') as f:
|
|
yaml.dump(config, f)
|
|
|
|
# Сбрасываем кэш настроек
|
|
get_settings.cache_clear()
|
|
|
|
logger.info("Конфигурация сохранена")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"Ошибка сохранения конфигурации: {e}", exc_info=True)
|
|
return False |