|
4 | 4 |
|
5 | 5 | from typing import Any |
6 | 6 |
|
7 | | -from .browser import SentienceBrowser |
| 7 | +from .browser import AsyncSentienceBrowser, SentienceBrowser |
8 | 8 | from .models import Element, Snapshot |
9 | 9 |
|
10 | 10 |
|
@@ -113,3 +113,110 @@ def clear_overlay(browser: SentienceBrowser) -> None: |
113 | 113 | } |
114 | 114 | """ |
115 | 115 | ) |
| 116 | + |
| 117 | + |
| 118 | +async def show_overlay_async( |
| 119 | + browser: AsyncSentienceBrowser, |
| 120 | + elements: list[Element] | list[dict[str, Any]] | Snapshot, |
| 121 | + target_element_id: int | None = None, |
| 122 | +) -> None: |
| 123 | + """ |
| 124 | + Display visual overlay highlighting elements in the browser (async) |
| 125 | +
|
| 126 | + This function shows a Shadow DOM overlay with color-coded borders around |
| 127 | + detected elements. Useful for debugging, learning, and validating element detection. |
| 128 | +
|
| 129 | + Args: |
| 130 | + browser: AsyncSentienceBrowser instance |
| 131 | + elements: Can be: |
| 132 | + - List of Element objects (from snapshot.elements) |
| 133 | + - List of raw element dicts (from snapshot result or API response) |
| 134 | + - Snapshot object (will use snapshot.elements) |
| 135 | + target_element_id: Optional ID of element to highlight in red (default: None) |
| 136 | +
|
| 137 | + Color Coding: |
| 138 | + - Red: Target element (when target_element_id is specified) |
| 139 | + - Blue: Primary elements (is_primary=true) |
| 140 | + - Green: Regular interactive elements |
| 141 | +
|
| 142 | + Visual Indicators: |
| 143 | + - Border thickness and opacity scale with importance score |
| 144 | + - Semi-transparent fill for better visibility |
| 145 | + - Importance badges showing scores |
| 146 | + - Star icon for primary elements |
| 147 | + - Target emoji for the target element |
| 148 | +
|
| 149 | + Auto-clear: Overlay automatically disappears after 5 seconds |
| 150 | +
|
| 151 | + Example: |
| 152 | + # Show overlay from snapshot |
| 153 | + snap = await snapshot_async(browser) |
| 154 | + await show_overlay_async(browser, snap) |
| 155 | +
|
| 156 | + # Show overlay with custom elements |
| 157 | + elements = [{"id": 1, "bbox": {"x": 100, "y": 100, "width": 200, "height": 50}, ...}] |
| 158 | + await show_overlay_async(browser, elements) |
| 159 | +
|
| 160 | + # Show overlay with target element highlighted in red |
| 161 | + await show_overlay_async(browser, snap, target_element_id=42) |
| 162 | +
|
| 163 | + # Clear overlay manually before 5 seconds |
| 164 | + await clear_overlay_async(browser) |
| 165 | + """ |
| 166 | + if not browser.page: |
| 167 | + raise RuntimeError("Browser not started. Call await browser.start() first.") |
| 168 | + |
| 169 | + # Handle different input types |
| 170 | + if isinstance(elements, Snapshot): |
| 171 | + # Extract elements from Snapshot object |
| 172 | + elements_list = [el.model_dump() for el in elements.elements] |
| 173 | + elif isinstance(elements, list) and len(elements) > 0: |
| 174 | + # Check if it's a list of Element objects or dicts |
| 175 | + if hasattr(elements[0], "model_dump"): |
| 176 | + # List of Element objects |
| 177 | + elements_list = [el.model_dump() for el in elements] |
| 178 | + else: |
| 179 | + # Already a list of dicts |
| 180 | + elements_list = elements |
| 181 | + else: |
| 182 | + raise ValueError("elements must be a Snapshot, list of Element objects, or list of dicts") |
| 183 | + |
| 184 | + # Call extension API |
| 185 | + await browser.page.evaluate( |
| 186 | + """ |
| 187 | + (args) => { |
| 188 | + if (window.sentience && window.sentience.showOverlay) { |
| 189 | + window.sentience.showOverlay(args.elements, args.targetId); |
| 190 | + } else { |
| 191 | + console.warn('[Sentience SDK] showOverlay not available - is extension loaded?'); |
| 192 | + } |
| 193 | + } |
| 194 | + """, |
| 195 | + {"elements": elements_list, "targetId": target_element_id}, |
| 196 | + ) |
| 197 | + |
| 198 | + |
| 199 | +async def clear_overlay_async(browser: AsyncSentienceBrowser) -> None: |
| 200 | + """ |
| 201 | + Clear the visual overlay manually (before 5-second auto-clear) (async) |
| 202 | +
|
| 203 | + Args: |
| 204 | + browser: AsyncSentienceBrowser instance |
| 205 | +
|
| 206 | + Example: |
| 207 | + await show_overlay_async(browser, snap) |
| 208 | + # ... inspect overlay ... |
| 209 | + await clear_overlay_async(browser) # Remove immediately |
| 210 | + """ |
| 211 | + if not browser.page: |
| 212 | + raise RuntimeError("Browser not started. Call await browser.start() first.") |
| 213 | + |
| 214 | + await browser.page.evaluate( |
| 215 | + """ |
| 216 | + () => { |
| 217 | + if (window.sentience && window.sentience.clearOverlay) { |
| 218 | + window.sentience.clearOverlay(); |
| 219 | + } |
| 220 | + } |
| 221 | + """ |
| 222 | + ) |
0 commit comments