aman/src/config.py

109 lines
3.6 KiB
Python

import json
import os
from dataclasses import dataclass
from pathlib import Path
def _parse_bool(val: str) -> bool:
return val.strip().lower() in {"1", "true", "yes", "on"}
@dataclass
class Config:
hotkey: str = "Cmd+m"
ffmpeg_input: str = "pulse:default"
ffmpeg_path: str = ""
whisper_model: str = "base"
whisper_lang: str = "en"
whisper_device: str = "cpu"
whisper_extra_args: str = ""
whisper_timeout_sec: int = 300
record_timeout_sec: int = 120
segment_sec: int = 5
streaming: bool = False
injection_backend: str = "clipboard"
ai_enabled: bool = False
ai_provider: str = "ollama"
ai_model: str = "llama3.2:3b"
ai_temperature: float = 0.0
ai_system_prompt_file: str = ""
ai_base_url: str = "http://localhost:11434"
ai_api_key: str = ""
ai_timeout_sec: int = 20
def default_path() -> Path:
return Path.home() / ".config" / "lel" / "config.json"
def load(path: str | None) -> Config:
cfg = Config()
p = Path(path) if path else default_path()
if p.exists():
data = json.loads(p.read_text(encoding="utf-8"))
for k, v in data.items():
if hasattr(cfg, k):
setattr(cfg, k, v)
# env overrides
if os.getenv("WHISPER_MODEL"):
cfg.whisper_model = os.environ["WHISPER_MODEL"]
if os.getenv("WHISPER_LANG"):
cfg.whisper_lang = os.environ["WHISPER_LANG"]
if os.getenv("WHISPER_DEVICE"):
cfg.whisper_device = os.environ["WHISPER_DEVICE"]
if os.getenv("WHISPER_EXTRA_ARGS"):
cfg.whisper_extra_args = os.environ["WHISPER_EXTRA_ARGS"]
if os.getenv("WHISPER_FFMPEG_IN"):
cfg.ffmpeg_input = os.environ["WHISPER_FFMPEG_IN"]
if os.getenv("WHISPER_STREAM"):
cfg.streaming = _parse_bool(os.environ["WHISPER_STREAM"])
if os.getenv("WHISPER_SEGMENT_SEC"):
cfg.segment_sec = int(os.environ["WHISPER_SEGMENT_SEC"])
if os.getenv("WHISPER_TIMEOUT_SEC"):
cfg.whisper_timeout_sec = int(os.environ["WHISPER_TIMEOUT_SEC"])
if os.getenv("LEL_FFMPEG_PATH"):
cfg.ffmpeg_path = os.environ["LEL_FFMPEG_PATH"]
if os.getenv("LEL_RECORD_TIMEOUT_SEC"):
cfg.record_timeout_sec = int(os.environ["LEL_RECORD_TIMEOUT_SEC"])
if os.getenv("LEL_HOTKEY"):
cfg.hotkey = os.environ["LEL_HOTKEY"]
if os.getenv("LEL_INJECTION_BACKEND"):
cfg.injection_backend = os.environ["LEL_INJECTION_BACKEND"]
if os.getenv("LEL_AI_ENABLED"):
cfg.ai_enabled = _parse_bool(os.environ["LEL_AI_ENABLED"])
if os.getenv("LEL_AI_PROVIDER"):
cfg.ai_provider = os.environ["LEL_AI_PROVIDER"]
if os.getenv("LEL_AI_MODEL"):
cfg.ai_model = os.environ["LEL_AI_MODEL"]
if os.getenv("LEL_AI_TEMPERATURE"):
cfg.ai_temperature = float(os.environ["LEL_AI_TEMPERATURE"])
if os.getenv("LEL_AI_SYSTEM_PROMPT_FILE"):
cfg.ai_system_prompt_file = os.environ["LEL_AI_SYSTEM_PROMPT_FILE"]
if os.getenv("LEL_AI_BASE_URL"):
cfg.ai_base_url = os.environ["LEL_AI_BASE_URL"]
if os.getenv("LEL_AI_API_KEY"):
cfg.ai_api_key = os.environ["LEL_AI_API_KEY"]
if os.getenv("LEL_AI_TIMEOUT_SEC"):
cfg.ai_timeout_sec = int(os.environ["LEL_AI_TIMEOUT_SEC"])
if not cfg.hotkey:
raise ValueError("hotkey cannot be empty")
if cfg.record_timeout_sec <= 0:
raise ValueError("record_timeout_sec must be > 0")
if cfg.whisper_timeout_sec <= 0:
raise ValueError("whisper_timeout_sec must be > 0")
return cfg
def redacted_dict(cfg: Config) -> dict:
d = cfg.__dict__.copy()
d["ai_api_key"] = ""
return d