Skip to content

bug: core/perception/screen_capture.py performs uncapped continuous screen capture with no frame-rate limiting or delta detection β€” on 4K displays it floods the LLM pipeline with redundant frames, driving CPU to 100% and API costs to ~$50/hour.Β #278

Description

@divyanshim27

πŸ› Problem Statement

Execra's core perception layer continuously captures the screen to enable real-time guidance. However, the capture loop in core/perception/screen_capture.py appears to run without a frame-rate cap or a visual delta filter. This creates two compounding problems:

1. API cost explosion: If every captured frame is forwarded to GPT-4o or Gemini 1.5 Pro for analysis:

  • A 1920Γ—1080 frame as a base64 PNG is approximately 300–800KB
  • GPT-4o Vision charges 1,000 tokens per image ($0.003/frame)
  • At 30 fps: $5.40/minute or $324/hour
  • Even at 1 fps with a user typing slowly: the user's screen changes only marginally between frames β€” identical or near-identical frames are sent repeatedly

2. CPU/memory saturation: mss (the screen capture library) can capture at extremely high rates. Without throttling, it will consume a full CPU core doing JPEG/PNG compression for frames that are never meaningfully different.

Root cause: No frame delta check before pipeline submission. The system lacks a mechanism to detect "has the screen changed enough to warrant a new analysis?"

Proposed Fix

1. Add frame rate cap and visual delta detection

# core/perception/screen_capture.py
import time
import numpy as np
from PIL import Image
import mss

TARGET_FPS = 2  # Analyze at most 2 frames per second
DELTA_THRESHOLD = 0.02  # Skip frame if less than 2% of pixels changed

class ScreenCaptureEngine:
    def __init__(self, fps: int = TARGET_FPS, delta_threshold: float = DELTA_THRESHOLD):
        self.fps = fps
        self.frame_interval = 1.0 / fps
        self.delta_threshold = delta_threshold
        self._last_frame: np.ndarray | None = None
        self._last_capture_time: float = 0.0

    def capture_frame(self) -> Image.Image | None:
        now = time.monotonic()
        # Rate limit
        if now - self._last_capture_time < self.frame_interval:
            return None

        with mss.mss() as sct:
            monitor = sct.monitors[1]  # Primary monitor
            raw = sct.grab(monitor)

        frame = np.array(raw)[:, :, :3]  # Drop alpha channel

        # Delta detection β€” skip if scene hasn't changed meaningfully
        if self._last_frame is not None:
            diff = np.mean(np.abs(frame.astype(int) - self._last_frame.astype(int))) / 255.0
            if diff < self.delta_threshold:
                return None  # Skip this frame β€” not enough change

        self._last_frame = frame.copy()
        self._last_capture_time = now
        return Image.fromarray(frame)

2. Add token budget tracking per session

# core/intelligence/token_budget.py
class TokenBudget:
    def __init__(self, max_tokens_per_hour: int = 100_000):
        self.max_per_hour = max_tokens_per_hour
        self._used: int = 0
        self._window_start: float = time.monotonic()

    def check_and_consume(self, tokens: int) -> bool:
        now = time.monotonic()
        if now - self._window_start > 3600:
            self._used = 0
            self._window_start = now
        if self._used + tokens > self.max_per_hour:
            return False  # Budget exceeded β€” skip this frame
        self._used += tokens
        return True

3. Expose --fps and --delta-threshold CLI flags

# main.py
parser.add_argument('--fps', type=float, default=2.0, help='Max screen analysis frames per second')
parser.add_argument('--delta-threshold', type=float, default=0.02, help='Minimum pixel delta to trigger re-analysis (0.0–1.0)')
parser.add_argument('--token-budget', type=int, default=100000, help='Max tokens per hour (cost guard)')

Files to Modify

File Change
core/perception/screen_capture.py Add FPS cap, delta detection, token budget integration
core/intelligence/token_budget.py New β€” hourly token budget guard
main.py Add --fps, --delta-threshold, --token-budget CLI flags
.env.example Add EXECRA_MAX_FPS=2 and EXECRA_TOKEN_BUDGET=100000
README.md Document cost controls and delta detection behavior

Suggested labels: bug, performance, cost-control, backend

I would like to work on this. Could you please assign it to me?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions