from __future__ import annotations from dataclasses import dataclass from pathlib import Path from typing import Any, Optional import yaml @dataclass(frozen=True) class AppConfig: umi_ocr_url: str prefer_mss: bool = True default_region: Optional[tuple[int, int, int, int]] = None # left, top, width, height click_pause: float = 0.05 def load_config(path: str | Path) -> AppConfig: p = Path(path) data: dict[str, Any] = yaml.safe_load(p.read_text(encoding="utf-8")) or {} umi_ocr = data.get("umi_ocr", {}) or {} screenshot = data.get("screenshot", {}) or {} click = data.get("click", {}) or {} region = screenshot.get("default_region") default_region: Optional[tuple[int, int, int, int]] if region is None: default_region = None else: if not (isinstance(region, (list, tuple)) and len(region) == 4): raise ValueError("config.yaml screenshot.default_region 必须是 null 或 [left, top, width, height]") default_region = (int(region[0]), int(region[1]), int(region[2]), int(region[3])) return AppConfig( umi_ocr_url=str(umi_ocr.get("url", "http://127.0.0.1:1224/api/ocr")), prefer_mss=bool(screenshot.get("prefer_mss", True)), default_region=default_region, click_pause=float(click.get("pause", 0.05)), )