Skip to content

Commit 1f9ee88

Browse files
committed
Add Set-of-Marks overlay for VLM element grounding
1 parent d06a7e4 commit 1f9ee88

15 files changed

Lines changed: 422 additions & 1 deletion

File tree

‎README.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
## Table of Contents
1515

16+
- [What's new (2026-06-19) — Set-of-Marks Overlay](#whats-new-2026-06-19--set-of-marks-overlay)
1617
- [What's new (2026-06-19) — Checkpoint & Resume](#whats-new-2026-06-19--checkpoint--resume)
1718
- [What's new (2026-06-19) — i18n / l10n Testing](#whats-new-2026-06-19--i18n--l10n-testing)
1819
- [What's new (2026-06-19) — Data Quality](#whats-new-2026-06-19--data-quality)
@@ -74,6 +75,13 @@
7475

7576
---
7677

78+
## What's new (2026-06-19) — Set-of-Marks Overlay
79+
80+
The standard VLM-grounding format, full stack. Full reference: [`docs/source/Eng/doc/new_features/v22_features_doc.rst`](docs/source/Eng/doc/new_features/v22_features_doc.rst).
81+
82+
- **Number elements** — `mark_elements` / `render_marks` / `resolve_mark` (pure + Pillow): assign `1..N` to interactable elements (with centre/role/text), draw numbered red boxes on a screenshot, and map a chosen number back to its element — so a VLM picks a *number* instead of guessing pixels (directly strengthens the existing VLM locator).
83+
- **Mark-then-click loop** — `mark_screen(render_path=...)` / `mark_click(n)` (`AC_mark_screen` / `AC_mark_click`, `ac_*`): number the live a11y tree (+ optional overlay screenshot), feed marks+image to a model, then click mark `n`.
84+
7785
## What's new (2026-06-19) — Checkpoint & Resume
7886

7987
Durable execution for long flows + a `py.typed` marker, full stack. Full reference: [`docs/source/Eng/doc/new_features/v21_features_doc.rst`](docs/source/Eng/doc/new_features/v21_features_doc.rst).

‎README/README_zh-CN.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目录
1414

15+
- [本次更新 (2026-06-19) — Set-of-Marks 叠图](#本次更新-2026-06-19--set-of-marks-叠图)
1516
- [本次更新 (2026-06-19) — 检查点与续跑](#本次更新-2026-06-19--检查点与续跑)
1617
- [本次更新 (2026-06-19) — i18n / l10n 测试](#本次更新-2026-06-19--i18n--l10n-测试)
1718
- [本次更新 (2026-06-19) — 数据质量](#本次更新-2026-06-19--数据质量)
@@ -73,6 +74,13 @@
7374

7475
---
7576

77+
## 本次更新 (2026-06-19) — Set-of-Marks 叠图
78+
79+
VLM 定位的标准格式,走完整五层。完整参考:[`docs/source/Zh/doc/new_features/v22_features_doc.rst`](../docs/source/Zh/doc/new_features/v22_features_doc.rst)。
80+
81+
- **元素标号** — `mark_elements` / `render_marks` / `resolve_mark`(纯函数 + Pillow):为可交互元素指派 `1..N`(含中心/role/text),在截图上画编号红框,并把选到的编号对应回元素——让 VLM 挑*编号*而非猜像素(直接强化既有 VLM locator)。
82+
- **标号后点击循环** — `mark_screen(render_path=...)` / `mark_click(n)`(`AC_mark_screen` / `AC_mark_click`、`ac_*`):为实时 a11y 树标号(+可选叠图截图),把 marks+图像喂给模型,再点击第 `n` 号。
83+
7684
## 本次更新 (2026-06-19) — 检查点与续跑
7785

7886
长流程的耐久执行 + `py.typed` 标记,走完整五层。完整参考:[`docs/source/Zh/doc/new_features/v21_features_doc.rst`](../docs/source/Zh/doc/new_features/v21_features_doc.rst)。

‎README/README_zh-TW.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目錄
1414

15+
- [本次更新 (2026-06-19) — Set-of-Marks 疊圖](#本次更新-2026-06-19--set-of-marks-疊圖)
1516
- [本次更新 (2026-06-19) — 檢查點與續跑](#本次更新-2026-06-19--檢查點與續跑)
1617
- [本次更新 (2026-06-19) — i18n / l10n 測試](#本次更新-2026-06-19--i18n--l10n-測試)
1718
- [本次更新 (2026-06-19) — 資料品質](#本次更新-2026-06-19--資料品質)
@@ -73,6 +74,13 @@
7374

7475
---
7576

77+
## 本次更新 (2026-06-19) — Set-of-Marks 疊圖
78+
79+
VLM 定位的標準格式,走完整五層。完整參考:[`docs/source/Zh/doc/new_features/v22_features_doc.rst`](../docs/source/Zh/doc/new_features/v22_features_doc.rst)。
80+
81+
- **元素標號** — `mark_elements` / `render_marks` / `resolve_mark`(純函式 + Pillow):為可互動元素指派 `1..N`(含中心/role/text),在截圖上畫編號紅框,並把選到的編號對應回元素——讓 VLM 挑*編號*而非猜像素(直接強化既有 VLM locator)。
82+
- **標號後點擊迴圈** — `mark_screen(render_path=...)` / `mark_click(n)`(`AC_mark_screen` / `AC_mark_click`、`ac_*`):為即時 a11y 樹標號(+可選疊圖截圖),把 marks+影像餵給模型,再點擊第 `n` 號。
83+
7684
## 本次更新 (2026-06-19) — 檢查點與續跑
7785

7886
長流程的耐久執行 + `py.typed` 標記,走完整五層。完整參考:[`docs/source/Zh/doc/new_features/v21_features_doc.rst`](../docs/source/Zh/doc/new_features/v21_features_doc.rst)。
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
==================================================
2+
New Features (2026-06-19) — Set-of-Marks Overlay
3+
==================================================
4+
5+
Modern GUI agents ground far more reliably when shown a screenshot with
6+
**numbered boxes** over the interactable elements plus an ``id -> bbox``
7+
legend ("Set-of-Marks" prompting): the model picks a *number* instead of
8+
guessing pixel coordinates. This turns AutoControl's existing element
9+
sources into that two-stage "mark then pick a number" loop and resolves the
10+
chosen number back to a click. Pure standard library + Pillow (already a
11+
dependency); wired through the full stack.
12+
13+
.. contents::
14+
:local:
15+
:depth: 2
16+
17+
18+
Numbering and the legend
19+
=======================
20+
21+
::
22+
23+
from je_auto_control import mark_elements, render_marks, resolve_mark
24+
25+
marks = mark_elements(elements) # [{id, bbox, center, role, text}, ...]
26+
legend = [(m["id"], m["text"]) for m in marks]
27+
annotated_png = render_marks(screenshot_png_bytes, marks)
28+
chosen = resolve_mark(marks, 3) # the element the model picked
29+
30+
``mark_elements`` assigns ``1..N`` to every element with a valid bounds and
31+
records its centre; ``render_marks`` draws numbered red boxes on a PNG;
32+
``resolve_mark`` maps a number back to its mark. These are pure and
33+
unit-testable with synthetic elements.
34+
35+
36+
Live "mark then click" loop
37+
==========================
38+
39+
::
40+
41+
from je_auto_control import mark_screen, mark_click
42+
43+
result = mark_screen(render_path="marked.png") # numbers the live a11y tree
44+
# ... feed result["marks"] + marked.png to a VLM, get back a number ...
45+
mark_click(3) # click mark #3
46+
47+
``mark_screen`` numbers the live accessibility elements (and optionally
48+
saves a numbered-box overlay screenshot), caching the marks; ``mark_click``
49+
resolves a number from that cache and clicks the element's centre. Exposed
50+
as ``AC_mark_screen`` / ``AC_mark_click`` (and ``ac_mark_screen`` /
51+
``ac_mark_click``).

‎docs/source/Eng/eng_index.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Comprehensive guides for all AutoControl features.
4444
doc/new_features/v19_features_doc
4545
doc/new_features/v20_features_doc
4646
doc/new_features/v21_features_doc
47+
doc/new_features/v22_features_doc
4748
doc/ocr_backends/ocr_backends_doc
4849
doc/observability/observability_doc
4950
doc/operations_layer/operations_layer_doc
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
==========================================
2+
新功能 (2026-06-19) — Set-of-Marks 疊圖
3+
==========================================
4+
5+
現代 GUI agent 在看到「畫上**編號方框**的截圖 + ``id -> bbox`` 圖例」時
6+
定位會可靠得多(Set-of-Marks prompting):模型挑一個*編號*,而不是猜
7+
像素座標。本功能把 AutoControl 既有的元素來源轉成這種「先標號、再挑號」
8+
的兩階段流程,並把選到的編號解析回一次點擊。純標準庫 + Pillow(已是相依);
9+
走完整五層。
10+
11+
.. contents::
12+
:local:
13+
:depth: 2
14+
15+
16+
標號與圖例
17+
==========
18+
19+
::
20+
21+
from je_auto_control import mark_elements, render_marks, resolve_mark
22+
23+
marks = mark_elements(elements) # [{id, bbox, center, role, text}, ...]
24+
legend = [(m["id"], m["text"]) for m in marks]
25+
annotated_png = render_marks(screenshot_png_bytes, marks)
26+
chosen = resolve_mark(marks, 3) # 模型挑中的元素
27+
28+
``mark_elements`` 會為每個有有效 bounds 的元素指派 ``1..N`` 並記錄中心點;
29+
``render_marks`` 在 PNG 上畫出編號紅框;``resolve_mark`` 把編號對應回該
30+
標記。這些都是純函式,可用合成元素做單元測試。
31+
32+
33+
即時「標號後點擊」迴圈
34+
======================
35+
36+
::
37+
38+
from je_auto_control import mark_screen, mark_click
39+
40+
result = mark_screen(render_path="marked.png") # 為即時 a11y 樹標號
41+
# ... 把 result["marks"] + marked.png 餵給 VLM,取回一個編號 ...
42+
mark_click(3) # 點擊第 3 號標記
43+
44+
``mark_screen`` 為即時 accessibility 元素標號(並可另存編號方框疊圖截圖),
45+
並快取這些標記;``mark_click`` 從快取解析編號並點擊該元素中心。對應
46+
``AC_mark_screen`` / ``AC_mark_click``(以及 ``ac_mark_screen`` /
47+
``ac_mark_click``)。

‎docs/source/Zh/zh_index.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ AutoControl 所有功能的完整使用指南。
4444
doc/new_features/v19_features_doc
4545
doc/new_features/v20_features_doc
4646
doc/new_features/v21_features_doc
47+
doc/new_features/v22_features_doc
4748
doc/ocr_backends/ocr_backends_doc
4849
doc/observability/observability_doc
4950
doc/operations_layer/operations_layer_doc

‎je_auto_control/__init__.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@
165165
from je_auto_control.utils.checkpoint import (
166166
Checkpoint, CheckpointStore, run_resumable,
167167
)
168+
# Set-of-Marks overlay (number elements for VLM grounding)
169+
from je_auto_control.utils.set_of_marks import (
170+
mark_click, mark_elements, mark_screen, render_marks, resolve_mark,
171+
)
168172
# Background popup/interrupt watchdog (unattended automation)
169173
from je_auto_control.utils.watchdog import (
170174
PopupWatchdog, WatchdogRule, default_popup_watchdog,
@@ -588,6 +592,8 @@ def start_autocontrol_gui(*args, **kwargs):
588592
"check_catalog", "check_overflow", "pseudo_localize",
589593
"pseudo_localize_catalog",
590594
"Checkpoint", "CheckpointStore", "run_resumable",
595+
"mark_click", "mark_elements", "mark_screen", "render_marks",
596+
"resolve_mark",
591597
# MCP server
592598
"AuditLogger", "HttpMCPServer", "MCPContent", "MCPPrompt",
593599
"MCPPromptArgument", "MCPResource", "MCPServer", "MCPTool",

‎je_auto_control/gui/script_builder/command_schema.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,24 @@ def _add_misc_specs(specs: List[CommandSpec]) -> None:
661661
_add_data_quality_specs(specs)
662662
_add_i18n_specs(specs)
663663
_add_checkpoint_specs(specs)
664+
_add_set_of_marks_specs(specs)
665+
666+
667+
def _add_set_of_marks_specs(specs: List[CommandSpec]) -> None:
668+
specs.append(CommandSpec(
669+
"AC_mark_screen", "Native UI", "Set-of-Marks: Number Elements",
670+
fields=(
671+
FieldSpec("app_name", FieldType.STRING, optional=True),
672+
FieldSpec("render_path", FieldType.FILE_PATH, optional=True),
673+
),
674+
description="Number live UI elements (id->bbox legend) for VLM "
675+
"grounding; optional numbered-box overlay screenshot.",
676+
))
677+
specs.append(CommandSpec(
678+
"AC_mark_click", "Native UI", "Set-of-Marks: Click Number",
679+
fields=(FieldSpec("mark_id", FieldType.INT),),
680+
description="Click the element behind a numbered mark.",
681+
))
664682

665683

666684
def _add_checkpoint_specs(specs: List[CommandSpec]) -> None:

‎je_auto_control/utils/executor/action_executor.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2743,6 +2743,19 @@ def _checkpoint_clear(run_id: str, db: str) -> Dict[str, Any]:
27432743
return {"cleared": CheckpointStore(db).clear(run_id)}
27442744

27452745

2746+
def _mark_screen(app_name: Optional[str] = None,
2747+
render_path: Optional[str] = None) -> Dict[str, Any]:
2748+
"""Adapter: number live UI elements (Set-of-Marks) for VLM grounding."""
2749+
from je_auto_control.utils.set_of_marks import mark_screen
2750+
return mark_screen(app_name=app_name, render_path=render_path)
2751+
2752+
2753+
def _mark_click(mark_id: int) -> Dict[str, Any]:
2754+
"""Adapter: click the element behind a numbered mark."""
2755+
from je_auto_control.utils.set_of_marks import mark_click
2756+
return {"clicked": mark_click(int(mark_id))}
2757+
2758+
27462759
class Executor:
27472760
"""
27482761
Executor
@@ -2953,6 +2966,8 @@ def __init__(self):
29532966
"AC_run_resumable": _run_resumable,
29542967
"AC_checkpoint_status": _checkpoint_status,
29552968
"AC_checkpoint_clear": _checkpoint_clear,
2969+
"AC_mark_screen": _mark_screen,
2970+
"AC_mark_click": _mark_click,
29562971
"AC_a11y_record_start": _a11y_record_start,
29572972
"AC_a11y_record_stop": _a11y_record_stop,
29582973
"AC_a11y_record_events": _a11y_record_events,

0 commit comments

Comments
 (0)