"""Konfiguration aus TOML-Datei mit sinnvollen Defaults.""" import os import sys from dataclasses import dataclass from pathlib import Path import tomllib def _default_config_path() -> Path: if sys.platform == "win32": return Path(os.environ.get("APPDATA", "")) / "whisper-local" / "config.toml" return Path.home() / ".config" / "whisper-local" / "config.toml" DEFAULT_CONFIG_PATH = _default_config_path() @dataclass class Config: hotkey: str = "KEY_F12" whisper_model: str = "small" language: str = "de" compute_type: str = "int8" sample_rate: int = 16000 channels: int = 1 min_duration: float = 0.5 microphone: str = "" pause_media_during_recording: bool = True def load_config(path: Path = DEFAULT_CONFIG_PATH) -> Config: """Lädt Config aus TOML-Datei. Gibt Defaults zurück wenn Datei fehlt.""" config = Config() if not path.exists(): return config with open(path, "rb") as f: data = tomllib.load(f) hotkey_section = data.get("hotkey", {}) if "key" in hotkey_section: config.hotkey = hotkey_section["key"] whisper_section = data.get("whisper", {}) if "model" in whisper_section: config.whisper_model = whisper_section["model"] if "language" in whisper_section: config.language = whisper_section["language"] if "compute_type" in whisper_section: config.compute_type = whisper_section["compute_type"] audio_section = data.get("audio", {}) if "sample_rate" in audio_section: config.sample_rate = audio_section["sample_rate"] if "channels" in audio_section: config.channels = audio_section["channels"] if "min_duration" in audio_section: config.min_duration = audio_section["min_duration"] if "device" in audio_section: config.microphone = audio_section["device"] media_section = data.get("media", {}) if "pause_during_recording" in media_section: config.pause_media_during_recording = bool( media_section["pause_during_recording"] ) return config def _toml_str(value: str) -> str: """Escaped einen String-Wert für TOML (verhindert ungültiges TOML bei Sonderzeichen).""" return value.replace("\\", "\\\\").replace('"', '\\"') def save_config(config: Config, path: Path = DEFAULT_CONFIG_PATH) -> None: """Schreibt Config als TOML-Datei. Erstellt Verzeichnisse bei Bedarf.""" path.parent.mkdir(parents=True, exist_ok=True) pause_media_str = "true" if config.pause_media_during_recording else "false" content = ( f'[hotkey]\nkey = "{_toml_str(config.hotkey)}"\n\n' f'[whisper]\nmodel = "{_toml_str(config.whisper_model)}"\n' f'language = "{_toml_str(config.language)}"\n' f'compute_type = "{_toml_str(config.compute_type)}"\n\n' f'[audio]\nsample_rate = {config.sample_rate}\n' f'channels = {config.channels}\n' f'min_duration = {config.min_duration}\n' f'device = "{_toml_str(config.microphone)}"\n\n' f'[media]\npause_during_recording = {pause_media_str}\n' ) path.write_text(content, encoding="utf-8")