Spaces:
Running
Running
v2: ground-up rebuild β emotion-library reactions, attention detection (motion + optional VLM), break timer, persistence, React control panel on a shared library. Sound off by default.
8ce2c44 verified | """Pluggable detection layer β shared across all robot apps. | |
| A `Detector` turns a camera frame into an `AttentionResult` (is a person | |
| present, are they engaged, how sure). Apps pick a detector by config and never | |
| care about the implementation, the same way Cardinal's agent picks a `Brain`. | |
| Concrete detectors live alongside this file (motion.py, vlm.py); apps add their | |
| own by implementing the protocol. | |
| This is deliberately separate from `vision/detector.py`'s object/bbox | |
| detection β that answers "what objects are in frame", this answers "is the user | |
| present and engaged". An app can use both. | |
| """ | |
| from __future__ import annotations | |
| from dataclasses import dataclass, field | |
| from typing import Any, Protocol, runtime_checkable | |
| import numpy as np | |
| class AttentionResult: | |
| """A detector's read on the user, normalized across implementations.""" | |
| present: bool # is a person at the desk at all | |
| engaged: bool # are they attending to their work (vs looked away) | |
| confidence: float = 0.5 # 0..1 β how sure the detector is | |
| source: str = "" # detector name, for UI/telemetry | |
| detail: str = "" # short human label ("typing", "looked away", "no face") | |
| extra: dict[str, Any] = field(default_factory=dict) | |
| def focused(self) -> bool: | |
| """Convenience: present AND engaged.""" | |
| return self.present and self.engaged | |
| class Detector(Protocol): | |
| """Frame -> AttentionResult. Stateful detectors keep history internally.""" | |
| name: str | |
| def detect(self, frame: np.ndarray) -> AttentionResult: | |
| """Analyze one BGR frame.""" | |
| ... | |
| def reset(self) -> None: | |
| """Clear any internal state (called on session start).""" | |
| ... | |
| def release(self) -> None: | |
| """Free resources (models, buffers).""" | |
| ... | |
| class BaseDetector: | |
| """Optional base with no-op lifecycle, so detectors only implement detect().""" | |
| name: str = "base" | |
| def reset(self) -> None: # noqa: D102 | |
| pass | |
| def release(self) -> None: # noqa: D102 | |
| pass | |