# app/api/settings.py from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from typing import Dict, Any, Optional from app.core.security import require_auth from app.core.config import get_settings, save_settings from app.core.vad import restart_vad_and_stt router = APIRouter(prefix="/api/settings", tags=["settings"]) class VADSettings(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 SystemSettings(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 STTSettings(BaseModel): model_path: str = "" class CommandsSettings(BaseModel): commands_file: str = "" class AuthSettings(BaseModel): username: str = "admin" password: str = "admin" class TTSSettings(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 AudioSettings(BaseModel): playback_device: int = 2 capture_device: int = 2 playback_volume: int = 0 capture_volume: int = 90 class AllSettings(BaseModel): vad: VADSettings system: SystemSettings stt: STTSettings commands: CommandsSettings auth: AuthSettings tts: TTSSettings audio_settings: AudioSettings @router.get("", response_model=AllSettings) async def get_all_settings(token: str = Depends(require_auth)): """Получение всех настроек""" try: config = get_settings() return AllSettings( vad=VADSettings(**config.vad.dict()), system=SystemSettings(**config.system.dict()), stt=STTSettings(**config.stt.dict()), commands=CommandsSettings(**config.commands.dict()), auth=AuthSettings(**config.auth.dict()), tts=TTSSettings(**config.tts.dict()), audio_settings=AudioSettings(**config.audio_settings.dict()) ) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.put("/vad", response_model=VADSettings) async def update_vad_settings(settings: VADSettings, token: str = Depends(require_auth)): """Обновление настроек VAD""" try: config = get_settings() settings_dict = settings.dict() for key, value in settings_dict.items(): setattr(config.vad, key, value) save_settings(config) return VADSettings(**config.vad.dict()) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.put("/system", response_model=SystemSettings) async def update_system_settings(settings: SystemSettings, token: str = Depends(require_auth)): """Обновление системных настроек""" try: config = get_settings() settings_dict = settings.dict() for key, value in settings_dict.items(): setattr(config.system, key, value) save_settings(config) return SystemSettings(**config.system.dict()) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.put("/stt", response_model=STTSettings) async def update_stt_settings(settings: STTSettings, token: str = Depends(require_auth)): """Обновление настроек STT""" try: config = get_settings() settings_dict = settings.dict() for key, value in settings_dict.items(): setattr(config.stt, key, value) save_settings(config) return STTSettings(**config.stt.dict()) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.put("/commands", response_model=CommandsSettings) async def update_commands_settings(settings: CommandsSettings, token: str = Depends(require_auth)): """Обновление настроек команд""" try: config = get_settings() settings_dict = settings.dict() for key, value in settings_dict.items(): setattr(config.commands, key, value) save_settings(config) return CommandsSettings(**config.commands.dict()) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.put("/auth", response_model=AuthSettings) async def update_auth_settings(settings: AuthSettings, token: str = Depends(require_auth)): """Обновление настроек авторизации""" try: config = get_settings() settings_dict = settings.dict() for key, value in settings_dict.items(): setattr(config.auth, key, value) save_settings(config) return AuthSettings(**config.auth.dict()) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.put("/tts", response_model=TTSSettings) async def update_tts_settings(settings: TTSSettings, token: str = Depends(require_auth)): """Обновление настроек TTS""" try: config = get_settings() settings_dict = settings.dict() for key, value in settings_dict.items(): setattr(config.tts, key, value) save_settings(config) return TTSSettings(**config.tts.dict()) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.put("/audio_settings", response_model=AudioSettings) async def update_audio_settings(settings: AudioSettings, token: str = Depends(require_auth)): """Обновление настроек аудио""" try: from volume import set_volume config = get_settings() old_settings = config.audio_settings.dict() settings_dict = settings.dict() # Обновляем настройки в конфигурации for key, value in settings_dict.items(): setattr(config.audio_settings, key, value) # Применяем настройки громкости, если они изменились if old_settings['playback_volume'] != settings_dict['playback_volume']: set_volume(settings_dict['playback_device'], settings_dict['playback_volume'], mixer_type='Playback') if old_settings['capture_volume'] != settings_dict['capture_volume']: set_volume(settings_dict['capture_device'], settings_dict['capture_volume'], mixer_type='Capture') save_settings(config) return AudioSettings(**config.audio_settings.dict()) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.post("/restart") async def restart_vad(request: Request, token: str = Depends(require_auth)): """Перезапуск VAD и STT с новыми настройками""" try: restart_vad_and_stt(request) return {"status": "success", "message": "VAD и STT перезапущены"} except Exception as e: raise HTTPException(status_code=500, detail=str(e))