QUELLCODE / PY

config.py

src/hardware_box/config.py

1# OpenAss: nur privater, experimenteller Gebrauch; auf eigene Verantwortung.2# Niemals Unternehmensrechner, Produktivsysteme, Industrieanlagen oder3# sicherheitskritische Systeme anschließen oder bedienen.4# Haftungshinweis und gesetzliche Grenzen: ../../DISCLAIMER.txt.5import os6import tomllib7from pathlib import Path8from typing import Literal910from pydantic import BaseModel, ConfigDict, Field, field_validator111213class Settings(BaseModel):14    model_config = ConfigDict(extra="forbid", validate_assignment=True)15    demo: bool = True16    model: str = "gpt-6-astra"17    capture_device: str = "/dev/video0"18    capture_width: int = Field(1920, ge=320, le=4096)19    capture_height: int = Field(1080, ge=240, le=2160)20    capture_fps: int = Field(60, ge=60, le=120)21    capture_format: Literal["YUYV", "MJPG", "RGB3"] = "YUYV"22    screenshot_width: int = Field(1920, ge=320, le=4096)23    screenshot_height: int = Field(1080, ge=240, le=2160)24    target_width: int = Field(3840, ge=320, le=8192)25    target_height: int = Field(2160, ge=240, le=8192)26    serial_port: str = "/dev/ttyAMA0"27    keyboard_layout: Literal["us", "de", "at"] = "de"28    calibration_confirmed: bool = False29    allow_screenshot_upload: bool = False30    session_seconds: int = Field(600, ge=10, le=3600)31    max_actions: int = Field(150, ge=1, le=1000)32    max_api_calls: int = Field(40, ge=1, le=200)33    max_total_tokens: int = Field(200000, ge=1000, le=2000000)34    max_actions_per_second: float = Field(4, ge=0.2, le=10)35    approval_timeout_seconds: int = Field(60, ge=5, le=120)36    max_text_chars: int = Field(250, ge=1, le=1000)37    extra_denied_keypresses: list[list[str]] = Field(default_factory=list, max_length=32)38    allowed_keypresses: list[list[str]] = Field(default_factory=list, max_length=32)39    settle_seconds: float = Field(0.35, ge=0.1, le=3)40    log_dir: str = "data/sessions"41    log_screenshots: bool = False42    log_api_responses: bool = False4344    @field_validator("extra_denied_keypresses", "allowed_keypresses")45    @classmethod46    def valid_combinations(cls, value):47        if any(not 1 <= len(combo) <= 6 or any(not key.strip() for key in combo) for combo in value):48            raise ValueError("Key combinations must contain 1..6 nonempty key names")49        return value505152def load_settings() -> Settings:53    path = Path(os.environ.get("BOX_CONFIG", "config/local.toml"))54    return Settings(**tomllib.loads(path.read_text())) if path.is_file() else Settings()