benchmark-collector 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const collector_1 = require("../src/collector");
5
+ const args = process.argv.slice(2);
6
+ function getArg(name, defaultValue) {
7
+ const idx = args.indexOf(`--${name}`);
8
+ return idx >= 0 && args[idx + 1] ? args[idx + 1] : defaultValue;
9
+ }
10
+ const task = getArg('task', '未命名任务');
11
+ const url = getArg('url', 'https://www.example.com');
12
+ console.log(`Benchmark 数据采集器`);
13
+ console.log(` 任务: ${task}`);
14
+ console.log(` URL: ${url}`);
15
+ const collector = new collector_1.BenchmarkCollector(task, url);
16
+ collector.start().catch((err) => {
17
+ console.error('采集出错:', err);
18
+ process.exit(1);
19
+ });
20
+ //# sourceMappingURL=collect.js.map
@@ -0,0 +1,48 @@
1
+ import { BrowserContext, Page } from 'playwright-core';
2
+ import { StepRecord } from './types';
3
+ export declare class BenchmarkCollector {
4
+ private task;
5
+ private startUrl;
6
+ private session;
7
+ private outputDir;
8
+ private stepsDir;
9
+ private stepCounter;
10
+ private allCodeLines;
11
+ private context;
12
+ private activePage;
13
+ private stopped;
14
+ private cdpSessionMap;
15
+ private captureQueue;
16
+ private processing;
17
+ private queueDone;
18
+ private queueDoneResolve;
19
+ constructor(task: string, startUrl: string, outputBase?: string);
20
+ get sessionId(): string;
21
+ get outputPath(): string;
22
+ get steps(): StepRecord[];
23
+ start(): Promise<void>;
24
+ /** 非交互式模式,用于测试 */
25
+ startHeadless(options?: {
26
+ headless?: boolean;
27
+ }): Promise<{
28
+ browser: import("playwright-core").Browser;
29
+ context: BrowserContext;
30
+ page: Page;
31
+ }>;
32
+ /** 手动触发一次采集 */
33
+ manualCapture(actionName: string, detail?: string): Promise<void>;
34
+ private setupRecording;
35
+ private enqueueCapture;
36
+ private processQueue;
37
+ private waitForQueueDrain;
38
+ /** 获取或创建页面的 CDP session */
39
+ private getCDP;
40
+ /** CDP 截图,强制 scale:1 保证像素=CSS坐标 */
41
+ private takeScreenshotCDP;
42
+ /** 通过 CDP 执行 JS(不触发 codegen 钩子,零闪烁) */
43
+ private cdpEval;
44
+ private captureStep;
45
+ private saveSessionSync;
46
+ stop(): Promise<void>;
47
+ }
48
+ //# sourceMappingURL=collector.d.ts.map
@@ -0,0 +1,373 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.BenchmarkCollector = void 0;
37
+ const playwright_core_1 = require("playwright-core");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const dom_capture_1 = require("./dom-capture");
41
+ const som_annotator_1 = require("./som-annotator");
42
+ class BenchmarkCollector {
43
+ constructor(task, startUrl, outputBase = 'output') {
44
+ this.task = task;
45
+ this.startUrl = startUrl;
46
+ this.stepCounter = 0;
47
+ this.allCodeLines = [];
48
+ this.stopped = false;
49
+ // CDP session 缓存
50
+ this.cdpSessionMap = new Map();
51
+ // 采集任务队列:保证不丢失任何 action,按顺序处理
52
+ this.captureQueue = [];
53
+ this.processing = false;
54
+ this.queueDone = Promise.resolve();
55
+ this.queueDoneResolve = null;
56
+ const safeName = task.replace(/[^\w\u4e00-\u9fff-]/g, '_').replace(/_+/g, '_').substring(0, 50);
57
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
58
+ const sessionId = `${safeName}_${timestamp}`;
59
+ this.outputDir = path.resolve(outputBase, sessionId);
60
+ this.stepsDir = path.join(this.outputDir, 'steps');
61
+ fs.mkdirSync(this.stepsDir, { recursive: true });
62
+ this.session = {
63
+ sessionId,
64
+ task,
65
+ startUrl,
66
+ startTime: new Date().toISOString(),
67
+ steps: [],
68
+ codegenScript: '',
69
+ traceFile: '',
70
+ };
71
+ }
72
+ get sessionId() { return this.session.sessionId; }
73
+ get outputPath() { return this.outputDir; }
74
+ get steps() { return this.session.steps; }
75
+ async start() {
76
+ let sigintResolve = null;
77
+ const sigintHandler = () => {
78
+ console.log('\n⏳ 收到退出信号,正在保存数据...');
79
+ if (sigintResolve)
80
+ sigintResolve();
81
+ };
82
+ process.on('SIGINT', sigintHandler);
83
+ const exitHandler = () => { try {
84
+ this.saveSessionSync();
85
+ }
86
+ catch (_) { } };
87
+ process.on('exit', exitHandler);
88
+ const browser = await playwright_core_1.chromium.launch({ headless: false });
89
+ this.context = await browser.newContext({
90
+ viewport: { width: 1280, height: 720 },
91
+ });
92
+ await this.context.tracing.start({ screenshots: true, snapshots: true });
93
+ this.activePage = await this.context.newPage();
94
+ await this.setupRecording();
95
+ try {
96
+ await this.activePage.goto(this.startUrl, { waitUntil: 'domcontentloaded', timeout: 30000 });
97
+ }
98
+ catch (e) {
99
+ console.log(`\n⚠️ 导航失败: ${e.message?.split('\n')[0]}`);
100
+ console.log(` 浏览器已打开,请手动导航到目标页面`);
101
+ }
102
+ await this.activePage.waitForTimeout(500);
103
+ this.enqueueCapture({
104
+ page: this.activePage,
105
+ action: { name: 'initial_state', url: this.activePage.url() },
106
+ codegenCode: `// Initial state: ${this.activePage.url()}`,
107
+ timestamp: Date.now(),
108
+ });
109
+ await this.waitForQueueDrain();
110
+ console.log(`\n✅ 采集已启动,请在浏览器中操作`);
111
+ console.log(` 任务: ${this.task}`);
112
+ console.log(` 按 Ctrl+C 结束采集\n`);
113
+ await new Promise((resolve) => {
114
+ sigintResolve = resolve;
115
+ browser.on('disconnected', () => resolve());
116
+ });
117
+ await this.stop();
118
+ process.removeListener('SIGINT', sigintHandler);
119
+ process.removeListener('exit', exitHandler);
120
+ await browser.close().catch(() => { });
121
+ console.log('👋 采集结束');
122
+ process.exit(0);
123
+ }
124
+ /** 非交互式模式,用于测试 */
125
+ async startHeadless(options) {
126
+ const browser = await playwright_core_1.chromium.launch({ headless: options?.headless ?? true });
127
+ this.context = await browser.newContext({
128
+ viewport: { width: 1280, height: 720 },
129
+ });
130
+ await this.context.tracing.start({ screenshots: true, snapshots: true });
131
+ this.activePage = await this.context.newPage();
132
+ await this.setupRecording();
133
+ return { browser, context: this.context, page: this.activePage };
134
+ }
135
+ /** 手动触发一次采集 */
136
+ async manualCapture(actionName, detail) {
137
+ this.enqueueCapture({
138
+ page: this.activePage,
139
+ action: { name: actionName, url: detail },
140
+ codegenCode: `// Manual: ${actionName} ${detail || ''}`,
141
+ timestamp: Date.now(),
142
+ });
143
+ await this.waitForQueueDrain();
144
+ }
145
+ // ========== 录制设置 ==========
146
+ async setupRecording() {
147
+ // 1. Codegen API — 与 codegen 完全一致的操作记录
148
+ await this.context._enableRecorder({ language: 'javascript', mode: 'recording', recorderMode: 'api' }, {
149
+ actionAdded: (page, data, code) => {
150
+ if (this.stopped)
151
+ return;
152
+ if (page)
153
+ this.activePage = page;
154
+ this.allCodeLines.push(code);
155
+ this.enqueueCapture({
156
+ page: page || this.activePage,
157
+ action: data.action,
158
+ codegenCode: code,
159
+ timestamp: Date.now(),
160
+ });
161
+ },
162
+ actionUpdated: (page, data, code) => {
163
+ if (this.stopped)
164
+ return;
165
+ if (page)
166
+ this.activePage = page;
167
+ if (this.session.steps.length > 0) {
168
+ const lastStep = this.session.steps[this.session.steps.length - 1];
169
+ lastStep.action = {
170
+ name: data.action.name,
171
+ selector: data.action.selector,
172
+ text: data.action.text,
173
+ url: data.action.url,
174
+ position: data.action.position,
175
+ modifiers: data.action.modifiers,
176
+ };
177
+ lastStep.codegenCode = code;
178
+ this.allCodeLines[this.allCodeLines.length - 1] = code;
179
+ this.saveSessionSync();
180
+ }
181
+ },
182
+ signalAdded: (_page, data) => {
183
+ console.log(` [Signal] ${data.name || JSON.stringify(data)}`);
184
+ },
185
+ });
186
+ // 2. 页面跳转记录
187
+ const trackNavigation = (p) => {
188
+ let lastUrl = p.url();
189
+ p.on('framenavigated', (frame) => {
190
+ if (this.stopped || frame !== p.mainFrame())
191
+ return;
192
+ const newUrl = p.url();
193
+ if (newUrl && newUrl !== lastUrl && newUrl !== 'about:blank') {
194
+ const code = `await page.goto('${newUrl}');`;
195
+ this.allCodeLines.push(code);
196
+ this.enqueueCapture({
197
+ page: p,
198
+ action: { name: 'navigate', url: newUrl },
199
+ codegenCode: code,
200
+ timestamp: Date.now(),
201
+ });
202
+ lastUrl = newUrl;
203
+ }
204
+ });
205
+ };
206
+ trackNavigation(this.activePage);
207
+ // 3. 新页面跟踪(popup 等)
208
+ this.context.on('page', (newPage) => {
209
+ const url = newPage.url();
210
+ console.log(` [Page] 新页面打开: ${url}`);
211
+ // 记录新 tab 打开事件
212
+ const code = `// New page opened: ${url}`;
213
+ this.allCodeLines.push(code);
214
+ this.enqueueCapture({
215
+ page: newPage,
216
+ action: { name: 'new_page', url },
217
+ codegenCode: code,
218
+ timestamp: Date.now(),
219
+ });
220
+ trackNavigation(newPage);
221
+ });
222
+ }
223
+ // ========== 采集任务队列 ==========
224
+ enqueueCapture(task) {
225
+ this.captureQueue.push(task);
226
+ if (!this.processing) {
227
+ this.queueDone = new Promise((resolve) => { this.queueDoneResolve = resolve; });
228
+ this.processQueue();
229
+ }
230
+ }
231
+ async processQueue() {
232
+ this.processing = true;
233
+ while (this.captureQueue.length > 0) {
234
+ const task = this.captureQueue.shift();
235
+ if (!this.stopped) {
236
+ await this.captureStep(task).catch((e) => {
237
+ console.error(` [Error] 采集失败: ${e.message?.split('\n')[0] || e}`);
238
+ });
239
+ }
240
+ }
241
+ this.processing = false;
242
+ if (this.queueDoneResolve) {
243
+ this.queueDoneResolve();
244
+ this.queueDoneResolve = null;
245
+ }
246
+ }
247
+ async waitForQueueDrain() {
248
+ await this.queueDone;
249
+ }
250
+ // ========== CDP 工具方法 ==========
251
+ /** 获取或创建页面的 CDP session */
252
+ async getCDP(page) {
253
+ let cdp = this.cdpSessionMap.get(page);
254
+ if (!cdp) {
255
+ cdp = await page.context().newCDPSession(page);
256
+ this.cdpSessionMap.set(page, cdp);
257
+ }
258
+ return cdp;
259
+ }
260
+ /** CDP 截图,强制 scale:1 保证像素=CSS坐标 */
261
+ async takeScreenshotCDP(cdp) {
262
+ // 先尝试带 clip.scale=1(精确控制分辨率)
263
+ try {
264
+ const metrics = await cdp.send('Page.getLayoutMetrics');
265
+ const vp = metrics.cssLayoutViewport || metrics.layoutViewport;
266
+ if (vp && vp.width > 0 && vp.height > 0) {
267
+ const result = await cdp.send('Page.captureScreenshot', {
268
+ format: 'png',
269
+ clip: { x: 0, y: 0, width: vp.width, height: vp.height, scale: 1 },
270
+ });
271
+ return result.data;
272
+ }
273
+ }
274
+ catch (_) { }
275
+ // 回退:captureBeyondViewport=false,再用 JS 查 dpr 做后处理
276
+ // 实际上对 about:blank 等简单页面直接截即可
277
+ const result = await cdp.send('Page.captureScreenshot', { format: 'png' });
278
+ return result.data;
279
+ }
280
+ /** 通过 CDP 执行 JS(不触发 codegen 钩子,零闪烁) */
281
+ async cdpEval(cdp, expression) {
282
+ const result = await cdp.send('Runtime.evaluate', {
283
+ expression,
284
+ returnByValue: true,
285
+ awaitPromise: true,
286
+ });
287
+ if (result.exceptionDetails) {
288
+ throw new Error(result.exceptionDetails.text || 'CDP eval error');
289
+ }
290
+ return result.result.value;
291
+ }
292
+ // ========== 核心采集(全部走 CDP,零闪烁) ==========
293
+ async captureStep(task) {
294
+ const { page, action, codegenCode, timestamp } = task;
295
+ const stepId = this.stepCounter++;
296
+ const prefix = String(stepId).padStart(4, '0');
297
+ const cdp = await this.getCDP(page);
298
+ // 等待页面稳定(CDP 方式,不走 Playwright)
299
+ await new Promise(r => setTimeout(r, 200));
300
+ // ① 纯净截图(CDP, scale:1 保证截图像素=CSS像素)
301
+ const cleanPath = `${prefix}_clean.png`;
302
+ const screenshotResult = await this.takeScreenshotCDP(cdp);
303
+ const cleanBuffer = Buffer.from(screenshotResult, 'base64');
304
+ fs.writeFileSync(path.join(this.stepsDir, cleanPath), cleanBuffer);
305
+ // ② DOM(CDP)
306
+ const htmlPath = `${prefix}_dom.html`;
307
+ const html = await this.cdpEval(cdp, 'document.documentElement.outerHTML');
308
+ fs.writeFileSync(path.join(this.stepsDir, htmlPath), html);
309
+ // ③ 可交互元素(CDP)
310
+ const elementsPath = `${prefix}_elements.json`;
311
+ const elementsJson = await this.cdpEval(cdp, (0, dom_capture_1.getCollectScript)());
312
+ const elements = JSON.parse(elementsJson);
313
+ fs.writeFileSync(path.join(this.stepsDir, elementsPath), JSON.stringify(elements, null, 2));
314
+ // ④ SoM 标注截图(CDP Canvas 合成)
315
+ const somPath = `${prefix}_som.png`;
316
+ const somScript = (0, som_annotator_1.getSoMRenderScript)(screenshotResult, elements);
317
+ const somBase64 = await this.cdpEval(cdp, somScript);
318
+ const somBuffer = Buffer.from(somBase64, 'base64');
319
+ fs.writeFileSync(path.join(this.stepsDir, somPath), somBuffer);
320
+ // ④ 记录
321
+ const step = {
322
+ stepId,
323
+ action: {
324
+ name: action.name,
325
+ selector: action.selector,
326
+ text: action.text,
327
+ url: action.url,
328
+ position: action.position,
329
+ modifiers: action.modifiers,
330
+ },
331
+ codegenCode,
332
+ timestamp,
333
+ pageUrl: page.url(),
334
+ screenshots: { clean: cleanPath, som: somPath },
335
+ dom: { html: htmlPath, interactiveElements: elementsPath },
336
+ };
337
+ this.session.steps.push(step);
338
+ this.saveSessionSync();
339
+ console.log(`[Step ${stepId}] ${step.action.name}` +
340
+ `${step.action.selector ? ' → ' + step.action.selector : ''}` +
341
+ `${step.action.text ? ' "' + step.action.text + '"' : ''}`);
342
+ }
343
+ // ========== 数据保存 ==========
344
+ saveSessionSync() {
345
+ try {
346
+ this.session.codegenScript = this.allCodeLines.join('\n');
347
+ fs.writeFileSync(path.join(this.outputDir, 'session.json'), JSON.stringify(this.session, null, 2));
348
+ fs.writeFileSync(path.join(this.outputDir, 'recorded-script.js'), this.session.codegenScript);
349
+ }
350
+ catch (_) { }
351
+ }
352
+ async stop() {
353
+ await this.waitForQueueDrain();
354
+ this.stopped = true;
355
+ this.session.endTime = new Date().toISOString();
356
+ for (const cdp of this.cdpSessionMap.values()) {
357
+ await cdp.detach().catch(() => { });
358
+ }
359
+ this.cdpSessionMap.clear();
360
+ this.session.traceFile = 'trace.zip';
361
+ try {
362
+ await this.context.tracing.stop({ path: path.join(this.outputDir, 'trace.zip') });
363
+ }
364
+ catch (_) { }
365
+ await this.context._disableRecorder().catch(() => { });
366
+ this.saveSessionSync();
367
+ console.log(`\n✅ 采集完成`);
368
+ console.log(` 共 ${this.session.steps.length} 步操作`);
369
+ console.log(` 数据目录: ${this.outputDir}/`);
370
+ }
371
+ }
372
+ exports.BenchmarkCollector = BenchmarkCollector;
373
+ //# sourceMappingURL=collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/collector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Page } from 'playwright-core';
2
+ import { SoMElement } from './types';
3
+ /** 通过 page.evaluate 采集(用于测试等非 codegen 场景) */
4
+ export declare function collectInteractiveElements(page: Page): Promise<SoMElement[]>;
5
+ /** 返回可通过 CDP Runtime.evaluate 执行的采集脚本 */
6
+ export declare function getCollectScript(): string;
7
+ //# sourceMappingURL=dom-capture.d.ts.map
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.collectInteractiveElements = collectInteractiveElements;
4
+ exports.getCollectScript = getCollectScript;
5
+ const INTERACTIVE_SELECTORS = [
6
+ 'a[href]', 'button', 'input', 'select', 'textarea',
7
+ '[role="button"]', '[role="link"]', '[role="menuitem"]',
8
+ '[role="tab"]', '[role="checkbox"]', '[role="radio"]',
9
+ '[role="combobox"]', '[role="textbox"]', '[role="option"]',
10
+ '[tabindex]:not([tabindex="-1"])',
11
+ '[onclick]', '[contenteditable="true"]',
12
+ ].join(', ');
13
+ /** 采集脚本(纯字符串,可通过 CDP Runtime.evaluate 执行) */
14
+ const COLLECT_SCRIPT = `(() => {
15
+ const selector = ${JSON.stringify(INTERACTIVE_SELECTORS)};
16
+ const ATTR_WHITELIST = ['id','class','name','type','placeholder','aria-label','role','href','value','title','alt'];
17
+ function collect(root, results) {
18
+ const elements = root.querySelectorAll(selector);
19
+ elements.forEach(el => {
20
+ const rect = el.getBoundingClientRect();
21
+ if (rect.width < 2 || rect.height < 2) return;
22
+ if (rect.bottom < 0 || rect.top > window.innerHeight) return;
23
+ if (rect.right < 0 || rect.left > window.innerWidth) return;
24
+ const attrs = {};
25
+ for (const a of el.attributes) {
26
+ if (ATTR_WHITELIST.includes(a.name)) attrs[a.name] = a.value;
27
+ }
28
+ results.push({
29
+ index: results.length,
30
+ tag: el.tagName.toLowerCase(),
31
+ role: el.getAttribute('role') || undefined,
32
+ text: (el.textContent || '').trim().substring(0, 200),
33
+ bbox: { x: Math.round(rect.x), y: Math.round(rect.y), width: Math.round(rect.width), height: Math.round(rect.height) },
34
+ attributes: attrs,
35
+ });
36
+ });
37
+ root.querySelectorAll('*').forEach(el => {
38
+ if (el.shadowRoot) collect(el.shadowRoot, results);
39
+ });
40
+ }
41
+ const results = [];
42
+ collect(document.documentElement, results);
43
+ return JSON.stringify(results);
44
+ })()`;
45
+ /** 通过 page.evaluate 采集(用于测试等非 codegen 场景) */
46
+ async function collectInteractiveElements(page) {
47
+ return await page.evaluate((selector) => {
48
+ const ATTR_WHITELIST = [
49
+ 'id', 'class', 'name', 'type', 'placeholder', 'aria-label',
50
+ 'role', 'href', 'value', 'title', 'alt',
51
+ ];
52
+ function collect(root, results) {
53
+ const elements = root.querySelectorAll(selector);
54
+ elements.forEach((el) => {
55
+ const rect = el.getBoundingClientRect();
56
+ if (rect.width < 2 || rect.height < 2)
57
+ return;
58
+ if (rect.bottom < 0 || rect.top > window.innerHeight)
59
+ return;
60
+ if (rect.right < 0 || rect.left > window.innerWidth)
61
+ return;
62
+ const attrs = {};
63
+ for (const a of Array.from(el.attributes)) {
64
+ if (ATTR_WHITELIST.includes(a.name)) {
65
+ attrs[a.name] = a.value;
66
+ }
67
+ }
68
+ results.push({
69
+ index: results.length,
70
+ tag: el.tagName.toLowerCase(),
71
+ role: el.getAttribute('role') || undefined,
72
+ text: (el.textContent || '').trim().substring(0, 200),
73
+ bbox: {
74
+ x: Math.round(rect.x),
75
+ y: Math.round(rect.y),
76
+ width: Math.round(rect.width),
77
+ height: Math.round(rect.height),
78
+ },
79
+ attributes: attrs,
80
+ });
81
+ });
82
+ root.querySelectorAll('*').forEach((el) => {
83
+ if (el.shadowRoot)
84
+ collect(el.shadowRoot, results);
85
+ });
86
+ }
87
+ const results = [];
88
+ collect(document.documentElement, results);
89
+ return results;
90
+ }, INTERACTIVE_SELECTORS);
91
+ }
92
+ /** 返回可通过 CDP Runtime.evaluate 执行的采集脚本 */
93
+ function getCollectScript() {
94
+ return COLLECT_SCRIPT;
95
+ }
96
+ //# sourceMappingURL=dom-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-capture.js","sourceRoot":"","sources":["../../src/dom-capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { BenchmarkCollector } from './collector';
2
+ export { collectInteractiveElements, getCollectScript } from './dom-capture';
3
+ export { renderSoMScreenshot, getSoMRenderScript } from './som-annotator';
4
+ export type { SoMElement, StepRecord, SessionRecord } from './types';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSoMRenderScript = exports.renderSoMScreenshot = exports.getCollectScript = exports.collectInteractiveElements = exports.BenchmarkCollector = void 0;
4
+ var collector_1 = require("./collector");
5
+ Object.defineProperty(exports, "BenchmarkCollector", { enumerable: true, get: function () { return collector_1.BenchmarkCollector; } });
6
+ var dom_capture_1 = require("./dom-capture");
7
+ Object.defineProperty(exports, "collectInteractiveElements", { enumerable: true, get: function () { return dom_capture_1.collectInteractiveElements; } });
8
+ Object.defineProperty(exports, "getCollectScript", { enumerable: true, get: function () { return dom_capture_1.getCollectScript; } });
9
+ var som_annotator_1 = require("./som-annotator");
10
+ Object.defineProperty(exports, "renderSoMScreenshot", { enumerable: true, get: function () { return som_annotator_1.renderSoMScreenshot; } });
11
+ Object.defineProperty(exports, "getSoMRenderScript", { enumerable: true, get: function () { return som_annotator_1.getSoMRenderScript; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAAiD;AAAxC,+GAAA,kBAAkB,OAAA;AAC3B,6CAA6E;AAApE,yHAAA,0BAA0B,OAAA;AAAE,+GAAA,gBAAgB,OAAA;AACrD,iDAA0E;AAAjE,oHAAA,mBAAmB,OAAA;AAAE,mHAAA,kBAAkB,OAAA"}
@@ -0,0 +1,9 @@
1
+ import { Page } from 'playwright-core';
2
+ import { SoMElement } from './types';
3
+ /** 生成 SoM 渲染脚本(纯字符串,可通过 CDP Runtime.evaluate 执行) */
4
+ export declare function getSoMRenderScript(imgBase64: string, elements: SoMElement[]): string;
5
+ /**
6
+ * 通过 page.evaluate 生成 SoM 截图(用于测试等非 codegen 场景)
7
+ */
8
+ export declare function renderSoMScreenshot(page: Page, cleanScreenshot: Buffer, elements: SoMElement[]): Promise<Buffer>;
9
+ //# sourceMappingURL=som-annotator.d.ts.map
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSoMRenderScript = getSoMRenderScript;
4
+ exports.renderSoMScreenshot = renderSoMScreenshot;
5
+ const COLORS = [
6
+ '#E6194B', '#3CB44B', '#FFE119', '#4363D8', '#F58231',
7
+ '#911EB4', '#42D4F4', '#F032E6', '#BFEF45', '#FABED4',
8
+ '#469990', '#DCBEFF', '#9A6324', '#FFFAC8', '#800000',
9
+ '#AAFFC3', '#808000', '#FFD8B1', '#000075', '#A9A9A9',
10
+ ];
11
+ /** 生成 SoM 渲染脚本(纯字符串,可通过 CDP Runtime.evaluate 执行) */
12
+ function getSoMRenderScript(imgBase64, elements) {
13
+ return `new Promise((resolve, reject) => {
14
+ const colors = ${JSON.stringify(COLORS)};
15
+ const elems = ${JSON.stringify(elements)};
16
+ const img = new Image();
17
+ img.onload = () => {
18
+ const canvas = document.createElement('canvas');
19
+ canvas.width = img.width;
20
+ canvas.height = img.height;
21
+ const ctx = canvas.getContext('2d');
22
+ if (!ctx) { reject('no canvas context'); return; }
23
+ ctx.drawImage(img, 0, 0);
24
+ // 计算缩放比:截图实际像素 / CSS视口像素
25
+ // 无论截图是 1x 还是 2x,都能正确对齐
26
+ const scaleX = img.width / window.innerWidth;
27
+ const scaleY = img.height / window.innerHeight;
28
+ elems.forEach(el => {
29
+ const color = colors[el.index % colors.length];
30
+ const sx = el.bbox.x * scaleX;
31
+ const sy = el.bbox.y * scaleY;
32
+ const sw = el.bbox.width * scaleX;
33
+ const sh = el.bbox.height * scaleY;
34
+ ctx.fillStyle = color + '20';
35
+ ctx.fillRect(sx, sy, sw, sh);
36
+ ctx.strokeStyle = color;
37
+ ctx.lineWidth = 2;
38
+ ctx.strokeRect(sx, sy, sw, sh);
39
+ const labelText = String(el.index);
40
+ const fontSize = Math.max(10, 10 * scaleX);
41
+ ctx.font = 'bold ' + fontSize + 'px monospace';
42
+ const tw = ctx.measureText(labelText).width;
43
+ const lx = sx, ly = Math.max(0, sy - 16 * scaleY);
44
+ ctx.fillStyle = color;
45
+ ctx.fillRect(lx, ly, tw + 6 * scaleX, 14 * scaleY);
46
+ ctx.fillStyle = 'white';
47
+ ctx.textBaseline = 'top';
48
+ ctx.fillText(labelText, lx + 3 * scaleX, ly + 1 * scaleY);
49
+ });
50
+ resolve(canvas.toDataURL('image/png').split(',')[1]);
51
+ };
52
+ img.onerror = () => reject('failed to load image');
53
+ img.src = 'data:image/png;base64,${imgBase64}';
54
+ })`;
55
+ }
56
+ /**
57
+ * 通过 page.evaluate 生成 SoM 截图(用于测试等非 codegen 场景)
58
+ */
59
+ async function renderSoMScreenshot(page, cleanScreenshot, elements) {
60
+ const cleanBase64 = cleanScreenshot.toString('base64');
61
+ const somBase64 = await page.evaluate(async ({ imgBase64, elems, colors }) => {
62
+ return new Promise((resolve, reject) => {
63
+ const img = new Image();
64
+ img.onload = () => {
65
+ const canvas = document.createElement('canvas');
66
+ canvas.width = img.width;
67
+ canvas.height = img.height;
68
+ const ctx = canvas.getContext('2d');
69
+ if (!ctx) {
70
+ reject('no canvas context');
71
+ return;
72
+ }
73
+ ctx.drawImage(img, 0, 0);
74
+ // 计算缩放比:截图实际像素 / CSS视口像素
75
+ const scaleX = img.width / window.innerWidth;
76
+ const scaleY = img.height / window.innerHeight;
77
+ elems.forEach((el) => {
78
+ const color = colors[el.index % colors.length];
79
+ const sx = el.bbox.x * scaleX;
80
+ const sy = el.bbox.y * scaleY;
81
+ const sw = el.bbox.width * scaleX;
82
+ const sh = el.bbox.height * scaleY;
83
+ ctx.fillStyle = color + '20';
84
+ ctx.fillRect(sx, sy, sw, sh);
85
+ ctx.strokeStyle = color;
86
+ ctx.lineWidth = 2;
87
+ ctx.strokeRect(sx, sy, sw, sh);
88
+ const labelText = String(el.index);
89
+ const fontSize = Math.max(10, 10 * scaleX);
90
+ ctx.font = 'bold ' + fontSize + 'px monospace';
91
+ const textWidth = ctx.measureText(labelText).width;
92
+ const labelX = sx;
93
+ const labelY = Math.max(0, sy - 16 * scaleY);
94
+ ctx.fillStyle = color;
95
+ ctx.fillRect(labelX, labelY, textWidth + 6 * scaleX, 14 * scaleY);
96
+ ctx.fillStyle = 'white';
97
+ ctx.textBaseline = 'top';
98
+ ctx.fillText(labelText, labelX + 3 * scaleX, labelY + 1 * scaleY);
99
+ });
100
+ resolve(canvas.toDataURL('image/png').split(',')[1]);
101
+ };
102
+ img.onerror = () => reject('failed to load screenshot into canvas');
103
+ img.src = 'data:image/png;base64,' + imgBase64;
104
+ });
105
+ }, { imgBase64: cleanBase64, elems: elements, colors: COLORS });
106
+ return Buffer.from(somBase64, 'base64');
107
+ }
108
+ //# sourceMappingURL=som-annotator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"som-annotator.js","sourceRoot":"","sources":["../../src/som-annotator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /** SoM 可交互元素 */
2
+ export interface SoMElement {
3
+ index: number;
4
+ tag: string;
5
+ role?: string;
6
+ text: string;
7
+ bbox: {
8
+ x: number;
9
+ y: number;
10
+ width: number;
11
+ height: number;
12
+ };
13
+ attributes: Record<string, string>;
14
+ }
15
+ /** 单步操作记录 */
16
+ export interface StepRecord {
17
+ stepId: number;
18
+ action: {
19
+ name: string;
20
+ selector?: string;
21
+ text?: string;
22
+ url?: string;
23
+ position?: {
24
+ x: number;
25
+ y: number;
26
+ };
27
+ modifiers?: string[];
28
+ };
29
+ codegenCode: string;
30
+ timestamp: number;
31
+ pageUrl: string;
32
+ screenshots: {
33
+ clean: string;
34
+ som: string;
35
+ };
36
+ dom: {
37
+ html: string;
38
+ interactiveElements: string;
39
+ };
40
+ }
41
+ /** 采集会话记录 */
42
+ export interface SessionRecord {
43
+ sessionId: string;
44
+ task: string;
45
+ startUrl: string;
46
+ startTime: string;
47
+ endTime?: string;
48
+ steps: StepRecord[];
49
+ codegenScript: string;
50
+ traceFile: string;
51
+ }
52
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "benchmark-collector",
3
+ "version": "1.0.0",
4
+ "description": "Playwright-based benchmark data collector for web agent training",
5
+ "main": "dist/src/index.js",
6
+ "types": "dist/src/index.d.ts",
7
+ "bin": {
8
+ "benchmark-collect": "dist/scripts/collect.js"
9
+ },
10
+ "files": [
11
+ "dist/src/**/*.js",
12
+ "dist/src/**/*.d.ts",
13
+ "dist/src/**/*.js.map",
14
+ "dist/scripts/**/*.js"
15
+ ],
16
+ "scripts": {
17
+ "collect": "ts-node scripts/collect.ts",
18
+ "build": "tsc",
19
+ "prepublishOnly": "npm run build",
20
+ "postinstall": "npx playwright-core install chromium",
21
+ "test": "npx playwright test"
22
+ },
23
+ "keywords": ["benchmark", "playwright", "web-agent", "data-collection", "som"],
24
+ "author": "",
25
+ "license": "ISC",
26
+ "devDependencies": {
27
+ "@playwright/test": "^1.58.2",
28
+ "@types/node": "^25.5.0",
29
+ "ts-node": "^10.9.2",
30
+ "typescript": "^5.7.0"
31
+ },
32
+ "dependencies": {
33
+ "playwright-core": "1.58.2"
34
+ }
35
+ }