Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions openadapt_capture/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
compare_video_to_images,
plot_comparison,
)
from openadapt_capture.config import RecordingConfig
from openadapt_capture.db.models import (
ActionEvent as DBActionEvent,
)
Expand Down Expand Up @@ -117,6 +118,7 @@
"__version__",
# High-level APIs
"Recorder",
"RecordingConfig",
"Capture",
"CaptureSession",
"Action",
Expand Down
26 changes: 22 additions & 4 deletions openadapt_capture/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,45 @@
def record(
output_dir: str,
description: str | None = None,
video: bool = True,
audio: bool = False,
images: bool = False,
) -> None:
"""Record GUI interactions.

Args:
output_dir: Directory to save capture.
description: Optional task description.
video: Capture video (default: True).
audio: Capture audio (default: False).
images: Save screenshots as PNGs (default: False).
"""
from openadapt_capture.recorder import record as do_record
import time

from openadapt_capture.recorder import Recorder

output_dir = str(Path(output_dir).resolve())

print(f"Recording to: {output_dir}")
print("Press Ctrl+C or type stop sequence to stop recording...")
print()

do_record(
with Recorder(
output_dir,
task_description=description or "",
capture_dir=output_dir,
)
capture_video=video,
capture_audio=audio,
capture_images=images,
) as recorder:
recorder.wait_for_ready()
try:
while recorder.is_recording:
time.sleep(1)
except KeyboardInterrupt:
pass

print()
print(f"Recorded {recorder.event_count} events")
print(f"Saved to: {output_dir}")


Expand Down
60 changes: 60 additions & 0 deletions openadapt_capture/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

from __future__ import annotations

from contextlib import contextmanager
from dataclasses import dataclass, fields

from pydantic_settings import BaseSettings

STOP_STRS = [
Expand Down Expand Up @@ -67,3 +70,60 @@ class Settings(BaseSettings):
config = Settings()
# Keep backward-compatible alias
settings = config


# ---------------------------------------------------------------------------
# RecordingConfig: user-facing overrides for Recorder constructor
# ---------------------------------------------------------------------------

# Mapping from RecordingConfig field names to Settings attribute names
_FIELD_TO_CONFIG_ATTR = {
"capture_video": "RECORD_VIDEO",
"capture_audio": "RECORD_AUDIO",
"capture_images": "RECORD_IMAGES",
"capture_window_data": "RECORD_WINDOW_DATA",
"capture_browser_events": "RECORD_BROWSER_EVENTS",
"capture_full_video": "RECORD_FULL_VIDEO",
"video_encoding": "VIDEO_ENCODING",
"video_pixel_format": "VIDEO_PIXEL_FORMAT",
"stop_sequences": "STOP_SEQUENCES",
"log_memory": "LOG_MEMORY",
"plot_performance": "PLOT_PERFORMANCE",
}


@dataclass
class RecordingConfig:
"""User-facing recording options. ``None`` means 'use default from config'."""

capture_video: bool | None = None
capture_audio: bool | None = None
capture_images: bool | None = None
capture_window_data: bool | None = None
capture_browser_events: bool | None = None
capture_full_video: bool | None = None
video_encoding: str | None = None
video_pixel_format: str | None = None
stop_sequences: list[list[str]] | None = None
log_memory: bool | None = None
plot_performance: bool | None = None


@contextmanager
def config_override(recording_config: RecordingConfig):
"""Temporarily override config settings from a RecordingConfig.

Saves original values, applies non-None overrides, yields, then restores.
"""
originals: dict[str, object] = {}
for field in fields(recording_config):
value = getattr(recording_config, field.name)
if value is not None:
config_attr = _FIELD_TO_CONFIG_ATTR[field.name]
originals[config_attr] = getattr(config, config_attr)
object.__setattr__(config, config_attr, value)
try:
yield
finally:
for config_attr, original_value in originals.items():
object.__setattr__(config, config_attr, original_value)
Loading