Javier Montalvo
Added more providers, changed entrypoint, removed local llama for now
2a9b8d1
Raw
History Blame Contribute Delete
3 kB
from __future__ import annotations
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
from pydantic import BaseModel, Field
from .automation import AutomationDocument
from .models import ActionEvent
LOCAL_DIR = Path(".local")
CONFIG_PATH = LOCAL_DIR / "config.yaml"
AUTOMATIONS_PATH = LOCAL_DIR / "automations.json"
STATE_PATH = LOCAL_DIR / "state.json"
EVENTS_PATH = LOCAL_DIR / "events.jsonl"
class LocalConfig(BaseModel):
camera_url: str | None = None
webhook_url: str | None = None
default_classes: str | None = None
default_detector_model: str | None = None
default_device: str | None = None
default_image_size: int | None = None
default_max_detections: int | None = None
llm_provider: str | None = None
replicate_api_token: str | None = None
replicate_model: str | None = None
replicate_reasoning_effort: str | None = None
openai_api_key: str | None = None
openai_model: str | None = None
anthropic_api_key: str | None = None
anthropic_model: str | None = None
class RuntimeState(BaseModel):
last_fired: dict[str, float] = Field(default_factory=dict)
snoozed_until: dict[str, float] = Field(default_factory=dict)
def load_local_config(path: Path = CONFIG_PATH) -> LocalConfig:
if not path.exists():
return LocalConfig()
try:
import yaml
except ImportError as exc: # pragma: no cover - dependency guard
raise RuntimeError("Install PyYAML to load local config.") from exc
data = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
return LocalConfig.model_validate(data)
def load_saved_automations(path: Path = AUTOMATIONS_PATH) -> AutomationDocument | None:
if not path.exists():
return None
return AutomationDocument.model_validate(json.loads(path.read_text(encoding="utf-8")))
def save_automations(document: AutomationDocument, path: Path = AUTOMATIONS_PATH) -> None:
_ensure_parent(path)
path.write_text(document.model_dump_json(by_alias=True, indent=2), encoding="utf-8")
def load_runtime_state(path: Path = STATE_PATH) -> RuntimeState:
if not path.exists():
return RuntimeState()
return RuntimeState.model_validate(json.loads(path.read_text(encoding="utf-8")))
def save_runtime_state(state: RuntimeState, path: Path = STATE_PATH) -> None:
_ensure_parent(path)
path.write_text(state.model_dump_json(indent=2), encoding="utf-8")
def append_events(events: list[ActionEvent], path: Path = EVENTS_PATH) -> None:
if not events:
return
_ensure_parent(path)
with path.open("a", encoding="utf-8") as file:
for event in events:
payload: dict[str, Any] = event.model_dump(mode="json")
payload["recorded_at"] = datetime.now(timezone.utc).isoformat()
file.write(json.dumps(payload, ensure_ascii=False) + "\n")
def _ensure_parent(path: Path) -> None:
path.parent.mkdir(parents=True, exist_ok=True)