bruniai 0.1.14 → 0.1.16
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.
- package/dist/compare-image-to-url.d.ts.map +1 -1
- package/dist/compare-image-to-url.js +2 -7
- package/dist/compare-image-to-url.js.map +1 -1
- package/dist/compare-urls.d.ts.map +1 -1
- package/dist/compare-urls.js +2 -7
- package/dist/compare-urls.js.map +1 -1
- package/dist/runtime/utils/stagehand.d.ts +3 -0
- package/dist/runtime/utils/stagehand.d.ts.map +1 -0
- package/dist/runtime/utils/stagehand.js +102 -0
- package/dist/runtime/utils/stagehand.js.map +1 -0
- package/dist/runtime/vision/vision.d.ts.map +1 -1
- package/dist/runtime/vision/vision.js +3 -13
- package/dist/runtime/vision/vision.js.map +1 -1
- package/dist/stagehand.d.ts +4 -0
- package/dist/stagehand.d.ts.map +1 -0
- package/dist/stagehand.js +102 -0
- package/dist/stagehand.js.map +1 -0
- package/package.json +3 -2
- package/dist/compare-images.d.ts +0 -16
- package/dist/compare-images.d.ts.map +0 -1
- package/dist/compare-images.js +0 -74
- package/dist/compare-images.js.map +0 -1
- package/dist/runtime/comparison/figma-core.d.ts +0 -66
- package/dist/runtime/comparison/figma-core.d.ts.map +0 -1
- package/dist/runtime/comparison/figma-core.js +0 -116
- package/dist/runtime/comparison/figma-core.js.map +0 -1
- package/dist/runtime/vision/comparison-html.d.ts +0 -16
- package/dist/runtime/vision/comparison-html.d.ts.map +0 -1
- package/dist/runtime/vision/comparison-html.js +0 -116
- package/dist/runtime/vision/comparison-html.js.map +0 -1
- package/dist/runtime/vision/section-judge.d.ts +0 -8
- package/dist/runtime/vision/section-judge.d.ts.map +0 -1
- package/dist/runtime/vision/section-judge.js +0 -87
- package/dist/runtime/vision/section-judge.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-image-to-url.d.ts","sourceRoot":"","sources":["../src/compare-image-to-url.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compare-image-to-url.d.ts","sourceRoot":"","sources":["../src/compare-image-to-url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AA+DpB;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CAgElC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createLocalStagehand } from "./stagehand.js";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { mkdirSync, existsSync } from "fs";
|
|
4
4
|
import { tmpdir } from "os";
|
|
@@ -69,12 +69,7 @@ export async function compareImageToUrl(input) {
|
|
|
69
69
|
if (!existsSync(imagesDir)) {
|
|
70
70
|
mkdirSync(imagesDir, { recursive: true });
|
|
71
71
|
}
|
|
72
|
-
const stagehand =
|
|
73
|
-
env: "LOCAL",
|
|
74
|
-
localBrowserLaunchOptions: {
|
|
75
|
-
headless: true,
|
|
76
|
-
},
|
|
77
|
-
});
|
|
72
|
+
const stagehand = await createLocalStagehand();
|
|
78
73
|
try {
|
|
79
74
|
await stagehand.init();
|
|
80
75
|
const result = await performImageToUrlComparison({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-image-to-url.js","sourceRoot":"","sources":["../src/compare-image-to-url.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compare-image-to-url.js","sourceRoot":"","sources":["../src/compare-image-to-url.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-urls.d.ts","sourceRoot":"","sources":["../src/compare-urls.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compare-urls.d.ts","sourceRoot":"","sources":["../src/compare-urls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA0BtE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAkE5B"}
|
package/dist/compare-urls.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createLocalStagehand } from "./stagehand.js";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { mkdirSync, existsSync } from "fs";
|
|
4
4
|
import { tmpdir } from "os";
|
|
@@ -50,12 +50,7 @@ export async function compareUrls(input) {
|
|
|
50
50
|
mkdirSync(imagesDir, { recursive: true });
|
|
51
51
|
}
|
|
52
52
|
// Initialize Stagehand.
|
|
53
|
-
const stagehand =
|
|
54
|
-
env: "LOCAL",
|
|
55
|
-
localBrowserLaunchOptions: {
|
|
56
|
-
headless: true,
|
|
57
|
-
},
|
|
58
|
-
});
|
|
53
|
+
const stagehand = await createLocalStagehand();
|
|
59
54
|
try {
|
|
60
55
|
await stagehand.init();
|
|
61
56
|
// Perform the core comparison.
|
package/dist/compare-urls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-urls.js","sourceRoot":"","sources":["../src/compare-urls.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compare-urls.js","sourceRoot":"","sources":["../src/compare-urls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stagehand.d.ts","sourceRoot":"","sources":["../../src/utils/stagehand.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AA4HrD,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,SAAS,CAAC,CAM/D"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { platform } from "os";
|
|
3
|
+
import { chromium } from "playwright";
|
|
4
|
+
import { Stagehand } from "@browserbasehq/stagehand";
|
|
5
|
+
const COMMON_BROWSER_PATHS = {
|
|
6
|
+
darwin: [
|
|
7
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
8
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
9
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
|
10
|
+
],
|
|
11
|
+
linux: [
|
|
12
|
+
"/usr/bin/google-chrome-stable",
|
|
13
|
+
"/usr/bin/google-chrome",
|
|
14
|
+
"/usr/bin/chromium-browser",
|
|
15
|
+
"/usr/bin/chromium",
|
|
16
|
+
],
|
|
17
|
+
win32: [
|
|
18
|
+
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
19
|
+
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
|
20
|
+
"C:\\Program Files\\Chromium\\Application\\chrome.exe",
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
function firstExistingPath(paths) {
|
|
24
|
+
for (const candidate of paths) {
|
|
25
|
+
if (candidate && existsSync(candidate)) {
|
|
26
|
+
return candidate;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
function resolvePlaywrightExecutablePath() {
|
|
32
|
+
try {
|
|
33
|
+
const executablePath = chromium.executablePath();
|
|
34
|
+
if (executablePath && existsSync(executablePath)) {
|
|
35
|
+
return executablePath;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Fall through to system browser lookup.
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
function extractServerlessChromium(module) {
|
|
44
|
+
return module.default ?? module;
|
|
45
|
+
}
|
|
46
|
+
async function resolveServerlessChromiumLaunchOptions() {
|
|
47
|
+
if (!process.env.VERCEL) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const chromiumModule = extractServerlessChromium((await import("@sparticuz/chromium")));
|
|
52
|
+
const executablePath = await chromiumModule.executablePath?.();
|
|
53
|
+
if (!executablePath) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
headless: true,
|
|
58
|
+
executablePath,
|
|
59
|
+
args: chromiumModule.args,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function resolveChromiumExecutablePath() {
|
|
67
|
+
const envPath = firstExistingPath([
|
|
68
|
+
process.env.CHROME_PATH,
|
|
69
|
+
process.env.CHROMIUM_PATH,
|
|
70
|
+
process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH,
|
|
71
|
+
]);
|
|
72
|
+
if (envPath) {
|
|
73
|
+
return envPath;
|
|
74
|
+
}
|
|
75
|
+
const playwrightPath = resolvePlaywrightExecutablePath();
|
|
76
|
+
if (playwrightPath) {
|
|
77
|
+
return playwrightPath;
|
|
78
|
+
}
|
|
79
|
+
return firstExistingPath(COMMON_BROWSER_PATHS[platform()] || []);
|
|
80
|
+
}
|
|
81
|
+
async function getLocalBrowserLaunchOptions() {
|
|
82
|
+
const serverlessOptions = await resolveServerlessChromiumLaunchOptions();
|
|
83
|
+
if (serverlessOptions) {
|
|
84
|
+
return serverlessOptions;
|
|
85
|
+
}
|
|
86
|
+
const executablePath = resolveChromiumExecutablePath();
|
|
87
|
+
if (!executablePath) {
|
|
88
|
+
throw new Error("Unable to find a Chromium/Chrome executable. Set CHROME_PATH, install Playwright Chromium locally, or provide @sparticuz/chromium in serverless environments.");
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
headless: true,
|
|
92
|
+
executablePath,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export async function createLocalStagehand() {
|
|
96
|
+
return new Stagehand({
|
|
97
|
+
env: "LOCAL",
|
|
98
|
+
disablePino: true,
|
|
99
|
+
localBrowserLaunchOptions: await getLocalBrowserLaunchOptions(),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=stagehand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stagehand.js","sourceRoot":"","sources":["../../src/utils/stagehand.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vision.d.ts","sourceRoot":"","sources":["../../src/vision/vision.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vision.d.ts","sourceRoot":"","sources":["../../src/vision/vision.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,YAAY,CAAC;AASpB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,uBAAuB,CAC3C,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,MAAM,EAC1B,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC,CAkF/B;AAED;;;;;;GAMG;AACH,wBAAsB,gCAAgC,CACpD,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,MAAM,EAC1B,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC,CAwF/B"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Stagehand } from "@browserbasehq/stagehand";
|
|
2
1
|
import { validateAndFixEnums, generateMetadata } from "./utils.js";
|
|
2
|
+
import { createLocalStagehand } from "../utils/stagehand.js";
|
|
3
3
|
import { analyzeBaseUrlAgent, analyzePreviewUrlAgent, analyzeImagesAgent, } from "./agents.js";
|
|
4
4
|
import { combineAgentResults } from "./combiner.js";
|
|
5
5
|
/**
|
|
@@ -31,12 +31,7 @@ import { combineAgentResults } from "./combiner.js";
|
|
|
31
31
|
export async function analyzeImagesWithVision(base_screenshot, pr_screenshot, diff_image, base_url, preview_url, pr_number, repository, sections_analysis, user_id) {
|
|
32
32
|
console.log(`\n${"=".repeat(50)}\n🔍 Starting sequential agent-based analysis\n${"=".repeat(50)}`);
|
|
33
33
|
// Initialize Stagehand (shared across all agents).
|
|
34
|
-
const stagehand =
|
|
35
|
-
env: "LOCAL",
|
|
36
|
-
localBrowserLaunchOptions: {
|
|
37
|
-
headless: true,
|
|
38
|
-
},
|
|
39
|
-
});
|
|
34
|
+
const stagehand = await createLocalStagehand();
|
|
40
35
|
try {
|
|
41
36
|
await stagehand.init();
|
|
42
37
|
// Agent 1: Analyze base URL structure and sections.
|
|
@@ -84,12 +79,7 @@ export async function analyzeImagesWithVision(base_screenshot, pr_screenshot, di
|
|
|
84
79
|
export async function analyzeImagesWithVisionImageMode(base_screenshot, pr_screenshot, diff_image, base_url, preview_url, pr_number, repository, sections_analysis, user_id) {
|
|
85
80
|
console.log(`\n${"=".repeat(50)}\n🔍 Starting image-baseline visual analysis (image-based only)\n${"=".repeat(50)}`);
|
|
86
81
|
// Initialize Stagehand for image and preview URL analysis.
|
|
87
|
-
const stagehand =
|
|
88
|
-
env: "LOCAL",
|
|
89
|
-
localBrowserLaunchOptions: {
|
|
90
|
-
headless: true,
|
|
91
|
-
},
|
|
92
|
-
});
|
|
82
|
+
const stagehand = await createLocalStagehand();
|
|
93
83
|
try {
|
|
94
84
|
await stagehand.init();
|
|
95
85
|
// For image baseline mode, we create a synthetic base analysis from the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vision.js","sourceRoot":"","sources":["../../src/vision/vision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"vision.js","sourceRoot":"","sources":["../../src/vision/vision.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stagehand.d.ts","sourceRoot":"","sources":["../src/stagehand.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAqFrD,wBAAgB,6BAA6B,IAAI,MAAM,GAAG,SAAS,CAiBlE;AAsBD,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,SAAS,CAAC,CAM/D"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { platform } from "os";
|
|
3
|
+
import { chromium } from "playwright";
|
|
4
|
+
import { Stagehand } from "@browserbasehq/stagehand";
|
|
5
|
+
const COMMON_BROWSER_PATHS = {
|
|
6
|
+
darwin: [
|
|
7
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
8
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
9
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
|
10
|
+
],
|
|
11
|
+
linux: [
|
|
12
|
+
"/usr/bin/google-chrome-stable",
|
|
13
|
+
"/usr/bin/google-chrome",
|
|
14
|
+
"/usr/bin/chromium-browser",
|
|
15
|
+
"/usr/bin/chromium",
|
|
16
|
+
],
|
|
17
|
+
win32: [
|
|
18
|
+
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
19
|
+
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
|
20
|
+
"C:\\Program Files\\Chromium\\Application\\chrome.exe",
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
function firstExistingPath(paths) {
|
|
24
|
+
for (const candidate of paths) {
|
|
25
|
+
if (candidate && existsSync(candidate)) {
|
|
26
|
+
return candidate;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
function resolvePlaywrightExecutablePath() {
|
|
32
|
+
try {
|
|
33
|
+
const executablePath = chromium.executablePath();
|
|
34
|
+
if (executablePath && existsSync(executablePath)) {
|
|
35
|
+
return executablePath;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Fall through to system browser lookup.
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
function extractServerlessChromium(module) {
|
|
44
|
+
return module.default ?? module;
|
|
45
|
+
}
|
|
46
|
+
async function resolveServerlessChromiumLaunchOptions() {
|
|
47
|
+
if (!process.env.VERCEL) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const chromiumModule = extractServerlessChromium((await import("@sparticuz/chromium")));
|
|
52
|
+
const executablePath = await chromiumModule.executablePath?.();
|
|
53
|
+
if (!executablePath) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
headless: true,
|
|
58
|
+
executablePath,
|
|
59
|
+
args: chromiumModule.args,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function resolveChromiumExecutablePath() {
|
|
67
|
+
const envPath = firstExistingPath([
|
|
68
|
+
process.env.CHROME_PATH,
|
|
69
|
+
process.env.CHROMIUM_PATH,
|
|
70
|
+
process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH,
|
|
71
|
+
]);
|
|
72
|
+
if (envPath) {
|
|
73
|
+
return envPath;
|
|
74
|
+
}
|
|
75
|
+
const playwrightPath = resolvePlaywrightExecutablePath();
|
|
76
|
+
if (playwrightPath) {
|
|
77
|
+
return playwrightPath;
|
|
78
|
+
}
|
|
79
|
+
return firstExistingPath(COMMON_BROWSER_PATHS[platform()] || []);
|
|
80
|
+
}
|
|
81
|
+
async function getLocalBrowserLaunchOptions() {
|
|
82
|
+
const serverlessOptions = await resolveServerlessChromiumLaunchOptions();
|
|
83
|
+
if (serverlessOptions) {
|
|
84
|
+
return serverlessOptions;
|
|
85
|
+
}
|
|
86
|
+
const executablePath = resolveChromiumExecutablePath();
|
|
87
|
+
if (!executablePath) {
|
|
88
|
+
throw new Error("Unable to find a Chromium/Chrome executable. Set CHROME_PATH, install Playwright Chromium locally, or provide @sparticuz/chromium in serverless environments.");
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
headless: true,
|
|
92
|
+
executablePath,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export async function createLocalStagehand() {
|
|
96
|
+
return new Stagehand({
|
|
97
|
+
env: "LOCAL",
|
|
98
|
+
disablePino: true,
|
|
99
|
+
localBrowserLaunchOptions: await getLocalBrowserLaunchOptions(),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=stagehand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stagehand.js","sourceRoot":"","sources":["../src/stagehand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAsB,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,MAAM,oBAAoB,GAA6B;IACrD,MAAM,EAAE;QACN,8DAA8D;QAC9D,oDAAoD;QACpD,8DAA8D;KAC/D;IACD,KAAK,EAAE;QACL,+BAA+B;QAC/B,wBAAwB;QACxB,2BAA2B;QAC3B,mBAAmB;KACpB;IACD,KAAK,EAAE;QACL,4DAA4D;QAC5D,kEAAkE;QAClE,sDAAsD;KACvD;CACF,CAAC;AAEF,SAAS,iBAAiB,CAAC,KAAgC;IACzD,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;QAC9B,IAAI,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,+BAA+B;IACtC,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,QAAQ,CAAC,cAAc,EAAE,CAAC;QACjD,IAAI,cAAc,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACjD,OAAO,cAAc,CAAC;QACxB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yCAAyC;IAC3C,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAaD,SAAS,yBAAyB,CAChC,MAAgC;IAEhC,OAAO,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC;AAClC,CAAC;AAED,KAAK,UAAU,sCAAsC;IACnD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,yBAAyB,CAC9C,CAAC,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAA6B,CAClE,CAAC;QACF,MAAM,cAAc,GAAG,MAAM,cAAc,CAAC,cAAc,EAAE,EAAE,CAAC;QAC/D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,cAAc;YACd,IAAI,EAAE,cAAc,CAAC,IAAI;SAC1B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,6BAA6B;IAC3C,MAAM,OAAO,GAAG,iBAAiB,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,WAAW;QACvB,OAAO,CAAC,GAAG,CAAC,aAAa;QACzB,OAAO,CAAC,GAAG,CAAC,mCAAmC;KAChD,CAAC,CAAC;IAEH,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,cAAc,GAAG,+BAA+B,EAAE,CAAC;IACzD,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,OAAO,iBAAiB,CAAC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,KAAK,UAAU,4BAA4B;IACzC,MAAM,iBAAiB,GAAG,MAAM,sCAAsC,EAAE,CAAC;IACzE,IAAI,iBAAiB,EAAE,CAAC;QACtB,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,MAAM,cAAc,GAAG,6BAA6B,EAAE,CAAC;IAEvD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,+JAA+J,CAChK,CAAC;IACJ,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,IAAI;QACd,cAAc;KACf,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,OAAO,IAAI,SAAS,CAAC;QACnB,GAAG,EAAE,OAAO;QACZ,WAAW,EAAE,IAAI;QACjB,yBAAyB,EAAE,MAAM,4BAA4B,EAAE;KAChE,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bruniai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI-powered visual regression testing tool - core comparison library",
|
|
6
6
|
"author": "Joao Garin",
|
|
@@ -18,10 +18,11 @@
|
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"build": "npm --prefix ../.. run build && tsc && node ./scripts/prepare-runtime.mjs",
|
|
21
|
+
"build": "rm -rf dist tsconfig.tsbuildinfo && npm --prefix ../.. run build && tsc && node ./scripts/prepare-runtime.mjs",
|
|
22
22
|
"dev": "tsx src/index.ts"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"@sparticuz/chromium": "^138.0.2",
|
|
25
26
|
"@browserbasehq/stagehand": "^3.0.1",
|
|
26
27
|
"dotenv": "^16.0.0",
|
|
27
28
|
"pixelmatch": "^7.1.0",
|
package/dist/compare-images.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { CompareImagesInput, CompareImagesOutput } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Compare two images visually and return analysis results.
|
|
4
|
-
*
|
|
5
|
-
* This function performs a complete image-native comparison workflow:
|
|
6
|
-
* - Creates a temporary directory for images
|
|
7
|
-
* - Normalizes both inputs into PNG images
|
|
8
|
-
* - Trims margins and generates a diff image
|
|
9
|
-
* - Matches sections deterministically
|
|
10
|
-
* - Produces structured analysis output
|
|
11
|
-
*
|
|
12
|
-
* @param input - Comparison input parameters
|
|
13
|
-
* @returns Complete analysis results with image paths
|
|
14
|
-
*/
|
|
15
|
-
export declare function compareImages(input: CompareImagesInput): Promise<CompareImagesOutput>;
|
|
16
|
-
//# sourceMappingURL=compare-images.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compare-images.d.ts","sourceRoot":"","sources":["../src/compare-images.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAsCpB;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CA2C9B"}
|
package/dist/compare-images.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { join } from "path";
|
|
2
|
-
import { mkdirSync, existsSync } from "fs";
|
|
3
|
-
import { tmpdir } from "os";
|
|
4
|
-
const imageToImageComparisonModulePromise = import.meta.url.includes("/packages/bruniai/src/")
|
|
5
|
-
? import("../../../dist/comparison/image-image-core.js")
|
|
6
|
-
: import("./runtime/comparison/image-image-core.js");
|
|
7
|
-
function isSupportedImageInput(input) {
|
|
8
|
-
if (!input) {
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
if (input.startsWith("data:image/")) {
|
|
12
|
-
return true;
|
|
13
|
-
}
|
|
14
|
-
try {
|
|
15
|
-
const parsed = new URL(input);
|
|
16
|
-
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function assertSupportedImageInput(input, fieldName) {
|
|
23
|
-
if (!isSupportedImageInput(input)) {
|
|
24
|
-
throw new Error(`${fieldName} must be an HTTP(S) image URL or data:image/... string`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Compare two images visually and return analysis results.
|
|
29
|
-
*
|
|
30
|
-
* This function performs a complete image-native comparison workflow:
|
|
31
|
-
* - Creates a temporary directory for images
|
|
32
|
-
* - Normalizes both inputs into PNG images
|
|
33
|
-
* - Trims margins and generates a diff image
|
|
34
|
-
* - Matches sections deterministically
|
|
35
|
-
* - Produces structured analysis output
|
|
36
|
-
*
|
|
37
|
-
* @param input - Comparison input parameters
|
|
38
|
-
* @returns Complete analysis results with image paths
|
|
39
|
-
*/
|
|
40
|
-
export async function compareImages(input) {
|
|
41
|
-
const { baseImage, previewImage } = input;
|
|
42
|
-
assertSupportedImageInput(baseImage, "baseImage");
|
|
43
|
-
assertSupportedImageInput(previewImage, "previewImage");
|
|
44
|
-
const { performImageToImageComparison } = await imageToImageComparisonModulePromise;
|
|
45
|
-
const imagesDir = join(tmpdir(), `bruniai-${Date.now()}`);
|
|
46
|
-
if (!existsSync(imagesDir)) {
|
|
47
|
-
mkdirSync(imagesDir, { recursive: true });
|
|
48
|
-
}
|
|
49
|
-
const result = await performImageToImageComparison({
|
|
50
|
-
baseImageUrl: baseImage,
|
|
51
|
-
previewImageUrl: previewImage,
|
|
52
|
-
imagesDir,
|
|
53
|
-
});
|
|
54
|
-
const status = result.visual_analysis.status === "none"
|
|
55
|
-
? "pass"
|
|
56
|
-
: result.visual_analysis.status;
|
|
57
|
-
return {
|
|
58
|
-
status,
|
|
59
|
-
visual_analysis: result.visual_analysis,
|
|
60
|
-
sections_analysis: result.sections_analysis,
|
|
61
|
-
images: {
|
|
62
|
-
base_screenshot: result.base_screenshot,
|
|
63
|
-
preview_screenshot: result.preview_screenshot,
|
|
64
|
-
diff_image: result.diff_image,
|
|
65
|
-
section_screenshots: Object.keys(result.section_screenshots).length > 0
|
|
66
|
-
? Object.fromEntries(Object.entries(result.section_screenshots).map(([key, value]) => [
|
|
67
|
-
key,
|
|
68
|
-
{ base: value.base, preview: value.preview },
|
|
69
|
-
]))
|
|
70
|
-
: undefined,
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
//# sourceMappingURL=compare-images.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compare-images.js","sourceRoot":"","sources":["../src/compare-images.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Figma-to-URL comparison core functionality.
|
|
3
|
-
*
|
|
4
|
-
* This module provides the workflow for comparing Figma prototype
|
|
5
|
-
* screenshots against live website URLs using visual AI-based section
|
|
6
|
-
* detection.
|
|
7
|
-
*/
|
|
8
|
-
import type { Stagehand } from "@browserbasehq/stagehand";
|
|
9
|
-
import type { VisualAnalysisResult } from "../vision/types.js";
|
|
10
|
-
/**
|
|
11
|
-
* Options for performing a Figma-to-URL comparison.
|
|
12
|
-
*/
|
|
13
|
-
export interface FigmaComparisonOptions {
|
|
14
|
-
/** Stagehand instance to use for browser automation. */
|
|
15
|
-
stagehand: Stagehand;
|
|
16
|
-
/** Figma prototype URL (base/reference). */
|
|
17
|
-
figmaUrl: string;
|
|
18
|
-
/** Preview/live URL to compare against. */
|
|
19
|
-
previewUrl: string;
|
|
20
|
-
/** Page path for the comparison (used for file naming). */
|
|
21
|
-
page: string;
|
|
22
|
-
/** Directory where images should be saved. */
|
|
23
|
-
imagesDir: string;
|
|
24
|
-
/** Optional PR number for metadata. */
|
|
25
|
-
prNumber?: string;
|
|
26
|
-
/** Optional repository name for metadata. */
|
|
27
|
-
repository?: string;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Result of a Figma-to-URL comparison.
|
|
31
|
-
*/
|
|
32
|
-
export interface FigmaComparisonResult {
|
|
33
|
-
/** Visual analysis result from AI. */
|
|
34
|
-
visual_analysis: VisualAnalysisResult;
|
|
35
|
-
/** Formatted sections analysis text (AI-detected). */
|
|
36
|
-
sections_analysis: string;
|
|
37
|
-
/** Path to Figma screenshot (base). */
|
|
38
|
-
base_screenshot: string;
|
|
39
|
-
/** Path to preview URL screenshot. */
|
|
40
|
-
preview_screenshot: string;
|
|
41
|
-
/** Path to diff image. */
|
|
42
|
-
diff_image: string;
|
|
43
|
-
/** Section screenshots keyed by section ID. */
|
|
44
|
-
section_screenshots: Record<string, {
|
|
45
|
-
base: string;
|
|
46
|
-
preview: string;
|
|
47
|
-
}>;
|
|
48
|
-
/** Comparison mode indicator. */
|
|
49
|
-
mode: "figma-to-url";
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Perform visual comparison between a Figma prototype and a live URL.
|
|
53
|
-
*
|
|
54
|
-
* This function performs the Figma-to-URL comparison workflow:
|
|
55
|
-
* 1. Takes screenshot of Figma prototype (canvas only)
|
|
56
|
-
* 2. Takes screenshot of preview URL
|
|
57
|
-
* 3. Generates diff image
|
|
58
|
-
* 4. Extracts visual sections using AI
|
|
59
|
-
* 5. Captures section screenshots
|
|
60
|
-
* 6. Performs visual analysis with AI
|
|
61
|
-
*
|
|
62
|
-
* @param options - Figma comparison options.
|
|
63
|
-
* @returns Complete comparison results with image paths.
|
|
64
|
-
*/
|
|
65
|
-
export declare function performFigmaComparison(options: FigmaComparisonOptions): Promise<FigmaComparisonResult>;
|
|
66
|
-
//# sourceMappingURL=figma-core.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"figma-core.d.ts","sourceRoot":"","sources":["../../src/comparison/figma-core.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAU1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAK/D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,wDAAwD;IACxD,SAAS,EAAE,SAAS,CAAC;IACrB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,eAAe,EAAE,oBAAoB,CAAC;IACtC,sDAAsD;IACtD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uCAAuC;IACvC,eAAe,EAAE,MAAM,CAAC;IACxB,sCAAsC;IACtC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvE,iCAAiC;IACjC,IAAI,EAAE,cAAc,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAiKhC"}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Figma-to-URL comparison core functionality.
|
|
3
|
-
*
|
|
4
|
-
* This module provides the workflow for comparing Figma prototype
|
|
5
|
-
* screenshots against live website URLs using visual AI-based section
|
|
6
|
-
* detection.
|
|
7
|
-
*/
|
|
8
|
-
import { generateDiffImage } from "../diff/diff.js";
|
|
9
|
-
import { screenshotFigmaPrototype, extractVisualSections, formatVisualSectionsAsAnalysis, takeSectionScreenshotsFromVisualBounds, } from "../figma/index.js";
|
|
10
|
-
import { analyzeImagesWithVisionFigmaMode } from "../vision/index.js";
|
|
11
|
-
import { ensureViewportSize } from "../utils/window.js";
|
|
12
|
-
import { join } from "path";
|
|
13
|
-
import { writeFileSync } from "fs";
|
|
14
|
-
import sharp from "sharp";
|
|
15
|
-
/**
|
|
16
|
-
* Perform visual comparison between a Figma prototype and a live URL.
|
|
17
|
-
*
|
|
18
|
-
* This function performs the Figma-to-URL comparison workflow:
|
|
19
|
-
* 1. Takes screenshot of Figma prototype (canvas only)
|
|
20
|
-
* 2. Takes screenshot of preview URL
|
|
21
|
-
* 3. Generates diff image
|
|
22
|
-
* 4. Extracts visual sections using AI
|
|
23
|
-
* 5. Captures section screenshots
|
|
24
|
-
* 6. Performs visual analysis with AI
|
|
25
|
-
*
|
|
26
|
-
* @param options - Figma comparison options.
|
|
27
|
-
* @returns Complete comparison results with image paths.
|
|
28
|
-
*/
|
|
29
|
-
export async function performFigmaComparison(options) {
|
|
30
|
-
const { stagehand, figmaUrl, previewUrl, page, imagesDir, prNumber = "", repository = "", } = options;
|
|
31
|
-
console.log(`\n${"=".repeat(50)}\n🎨 Starting Figma-to-URL Comparison\n${"=".repeat(50)}`);
|
|
32
|
-
console.log(`Figma URL: ${figmaUrl}`);
|
|
33
|
-
console.log(`Preview URL: ${previewUrl}`);
|
|
34
|
-
// Generate page suffix for file naming.
|
|
35
|
-
let pageSuffix = page.replace(/\//g, "_");
|
|
36
|
-
pageSuffix = pageSuffix === "_" ? "home" : pageSuffix;
|
|
37
|
-
// Step 1: Take screenshot of Figma prototype.
|
|
38
|
-
console.log("\n📸 Step 1: Capturing Figma prototype screenshot...");
|
|
39
|
-
const baseScreenshotPath = join(imagesDir, `base_screenshot_${pageSuffix}.png`);
|
|
40
|
-
const figmaResult = await screenshotFigmaPrototype(stagehand, figmaUrl, baseScreenshotPath);
|
|
41
|
-
if (!figmaResult.success) {
|
|
42
|
-
throw new Error(`Failed to capture Figma screenshot: ${figmaResult.error || "Unknown error"}`);
|
|
43
|
-
}
|
|
44
|
-
console.log(`Figma screenshot saved: ${baseScreenshotPath}`);
|
|
45
|
-
console.log(`Canvas bounds: ${JSON.stringify(figmaResult.canvasBounds)}`);
|
|
46
|
-
// Step 2: Take screenshot of preview URL.
|
|
47
|
-
console.log("\n📸 Step 2: Capturing preview URL screenshot...");
|
|
48
|
-
const initialPage = stagehand.context.pages()[0];
|
|
49
|
-
await ensureViewportSize(initialPage, previewUrl);
|
|
50
|
-
const previewScreenshot = await initialPage.screenshot({
|
|
51
|
-
fullPage: true,
|
|
52
|
-
});
|
|
53
|
-
const previewScreenshotPath = join(imagesDir, `preview_screenshot_${pageSuffix}.png`);
|
|
54
|
-
writeFileSync(previewScreenshotPath, previewScreenshot);
|
|
55
|
-
console.log(`Preview screenshot saved: ${previewScreenshotPath}`);
|
|
56
|
-
// Step 3: Generate diff image.
|
|
57
|
-
console.log("\n🔍 Step 3: Generating diff image...");
|
|
58
|
-
const diffImagePath = join(imagesDir, `diff_${pageSuffix}.png`);
|
|
59
|
-
await generateDiffImage(baseScreenshotPath, previewScreenshotPath, diffImagePath);
|
|
60
|
-
console.log(`Diff image saved: ${diffImagePath}`);
|
|
61
|
-
// Step 4: Extract visual sections from Figma screenshot using AI.
|
|
62
|
-
console.log("\n🤖 Step 4: Extracting visual sections using AI...");
|
|
63
|
-
const visualSectionsResult = await extractVisualSections(stagehand, baseScreenshotPath);
|
|
64
|
-
// Format sections analysis for compatibility with existing workflow.
|
|
65
|
-
const sectionsAnalysis = formatVisualSectionsAsAnalysis(visualSectionsResult);
|
|
66
|
-
console.log(`\n${"=".repeat(50)}\n🗺️ Visual Sections Analysis:\n${sectionsAnalysis}\n${"=".repeat(50)}`);
|
|
67
|
-
// Step 5: Capture section screenshots.
|
|
68
|
-
console.log("\n📷 Step 5: Capturing section screenshots...");
|
|
69
|
-
const sectionScreenshots = {};
|
|
70
|
-
// Take section screenshots from preview URL using visual bounds.
|
|
71
|
-
const previewSectionScreenshots = await takeSectionScreenshotsFromVisualBounds(stagehand, previewUrl, visualSectionsResult.sections, imagesDir, pageSuffix);
|
|
72
|
-
// For Figma sections, we use the visual bounds to clip from the base screenshot.
|
|
73
|
-
for (const section of visualSectionsResult.sections) {
|
|
74
|
-
const sectionId = section.sectionId;
|
|
75
|
-
const baseSectionPath = join(imagesDir, `base_screenshot_${pageSuffix}_section_${sectionId}.png`);
|
|
76
|
-
try {
|
|
77
|
-
// Crop directly from the stitched base screenshot.
|
|
78
|
-
// This works even when the section is below the first viewport.
|
|
79
|
-
const baseSectionScreenshot = await sharp(baseScreenshotPath)
|
|
80
|
-
.extract({
|
|
81
|
-
left: Math.max(0, Math.round(section.boundingBox.x)),
|
|
82
|
-
top: Math.max(0, Math.round(section.boundingBox.y)),
|
|
83
|
-
width: Math.max(1, Math.round(section.boundingBox.width)),
|
|
84
|
-
height: Math.max(1, Math.round(section.boundingBox.height)),
|
|
85
|
-
})
|
|
86
|
-
.png()
|
|
87
|
-
.toBuffer();
|
|
88
|
-
writeFileSync(baseSectionPath, baseSectionScreenshot);
|
|
89
|
-
// Only add to result if both screenshots exist.
|
|
90
|
-
if (previewSectionScreenshots[sectionId]) {
|
|
91
|
-
sectionScreenshots[sectionId] = {
|
|
92
|
-
base: baseSectionPath,
|
|
93
|
-
preview: previewSectionScreenshots[sectionId],
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
catch (error) {
|
|
98
|
-
console.warn(`Failed to capture Figma section ${sectionId}: ${error}`);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
console.log(`Captured ${Object.keys(sectionScreenshots).length} section screenshot pairs`);
|
|
102
|
-
// Step 6: Perform visual analysis with AI (Figma mode - skips URL navigation).
|
|
103
|
-
console.log("\n🧠 Step 6: Performing visual analysis (Figma mode)...");
|
|
104
|
-
const visualAnalysis = await analyzeImagesWithVisionFigmaMode(baseScreenshotPath, previewScreenshotPath, diffImagePath, figmaUrl, previewUrl, prNumber, repository, sectionsAnalysis);
|
|
105
|
-
console.log(`Visual analysis completed: ${visualAnalysis.status}`);
|
|
106
|
-
return {
|
|
107
|
-
visual_analysis: visualAnalysis,
|
|
108
|
-
sections_analysis: sectionsAnalysis,
|
|
109
|
-
base_screenshot: baseScreenshotPath,
|
|
110
|
-
preview_screenshot: previewScreenshotPath,
|
|
111
|
-
diff_image: diffImagePath,
|
|
112
|
-
section_screenshots: sectionScreenshots,
|
|
113
|
-
mode: "figma-to-url",
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
//# sourceMappingURL=figma-core.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"figma-core.js","sourceRoot":"","sources":["../../src/comparison/figma-core.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,8BAA8B,EAC9B,sCAAsC,GACvC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gCAAgC,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACnC,OAAO,KAAK,MAAM,OAAO,CAAC;AA0C1B;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAA+B;IAE/B,MAAM,EACJ,SAAS,EACT,QAAQ,EACR,UAAU,EACV,IAAI,EACJ,SAAS,EACT,QAAQ,GAAG,EAAE,EACb,UAAU,GAAG,EAAE,GAChB,GAAG,OAAO,CAAC;IAEZ,OAAO,CAAC,GAAG,CACT,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,0CAA0C,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAC9E,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,cAAc,QAAQ,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAC;IAE1C,wCAAwC;IACxC,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC1C,UAAU,GAAG,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;IAEtD,8CAA8C;IAC9C,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;IACpE,MAAM,kBAAkB,GAAG,IAAI,CAC7B,SAAS,EACT,mBAAmB,UAAU,MAAM,CACpC,CAAC;IAEF,MAAM,WAAW,GAAG,MAAM,wBAAwB,CAChD,SAAS,EACT,QAAQ,EACR,kBAAkB,CACnB,CAAC;IAEF,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,uCAAuC,WAAW,CAAC,KAAK,IAAI,eAAe,EAAE,CAC9E,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,2BAA2B,kBAAkB,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAE1E,0CAA0C;IAC1C,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;IAChE,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,kBAAkB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAElD,MAAM,iBAAiB,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC;QACrD,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,MAAM,qBAAqB,GAAG,IAAI,CAChC,SAAS,EACT,sBAAsB,UAAU,MAAM,CACvC,CAAC;IACF,aAAa,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,6BAA6B,qBAAqB,EAAE,CAAC,CAAC;IAElE,+BAA+B;IAC/B,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,UAAU,MAAM,CAAC,CAAC;IAChE,MAAM,iBAAiB,CACrB,kBAAkB,EAClB,qBAAqB,EACrB,aAAa,CACd,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,qBAAqB,aAAa,EAAE,CAAC,CAAC;IAElD,kEAAkE;IAClE,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;IACnE,MAAM,oBAAoB,GAAG,MAAM,qBAAqB,CACtD,SAAS,EACT,kBAAkB,CACnB,CAAC;IAEF,qEAAqE;IACrE,MAAM,gBAAgB,GAAG,8BAA8B,CAAC,oBAAoB,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CACT,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,oCAAoC,gBAAgB,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAC7F,CAAC;IAEF,uCAAuC;IACvC,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,MAAM,kBAAkB,GACtB,EAAE,CAAC;IAEL,iEAAiE;IACjE,MAAM,yBAAyB,GAAG,MAAM,sCAAsC,CAC5E,SAAS,EACT,UAAU,EACV,oBAAoB,CAAC,QAAQ,EAC7B,SAAS,EACT,UAAU,CACX,CAAC;IAEF,iFAAiF;IACjF,KAAK,MAAM,OAAO,IAAI,oBAAoB,CAAC,QAAQ,EAAE,CAAC;QACpD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACpC,MAAM,eAAe,GAAG,IAAI,CAC1B,SAAS,EACT,mBAAmB,UAAU,YAAY,SAAS,MAAM,CACzD,CAAC;QAEF,IAAI,CAAC;YACH,mDAAmD;YACnD,gEAAgE;YAChE,MAAM,qBAAqB,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC;iBAC1D,OAAO,CAAC;gBACP,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;gBACpD,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;gBACnD,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;gBACzD,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;aAC5D,CAAC;iBACD,GAAG,EAAE;iBACL,QAAQ,EAAE,CAAC;YAEd,aAAa,CAAC,eAAe,EAAE,qBAAqB,CAAC,CAAC;YAEtD,gDAAgD;YAChD,IAAI,yBAAyB,CAAC,SAAS,CAAC,EAAE,CAAC;gBACzC,kBAAkB,CAAC,SAAS,CAAC,GAAG;oBAC9B,IAAI,EAAE,eAAe;oBACrB,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC;iBAC9C,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CACV,mCAAmC,SAAS,KAAK,KAAK,EAAE,CACzD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CACT,YAAY,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAM,2BAA2B,CAC9E,CAAC;IAEF,+EAA+E;IAC/E,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACvE,MAAM,cAAc,GAAG,MAAM,gCAAgC,CAC3D,kBAAkB,EAClB,qBAAqB,EACrB,aAAa,EACb,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,UAAU,EACV,gBAAgB,CACjB,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,8BAA8B,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;IAEnE,OAAO;QACL,eAAe,EAAE,cAAc;QAC/B,iBAAiB,EAAE,gBAAgB;QACnC,eAAe,EAAE,kBAAkB;QACnC,kBAAkB,EAAE,qBAAqB;QACzC,UAAU,EAAE,aAAa;QACzB,mBAAmB,EAAE,kBAAkB;QACvC,IAAI,EAAE,cAAc;KACrB,CAAC;AACJ,CAAC"}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Create HTML comparison page with base64-encoded images.
|
|
3
|
-
*
|
|
4
|
-
* This function reads screenshot images from disk, converts them to base64
|
|
5
|
-
* data URLs, and generates an HTML page that displays them side-by-side for
|
|
6
|
-
* visual comparison analysis.
|
|
7
|
-
*
|
|
8
|
-
* @param base_screenshot - Path to the base/reference screenshot
|
|
9
|
-
* @param pr_screenshot - Path to the PR/changed screenshot
|
|
10
|
-
* @param diff_image - Path to the diff image highlighting differences
|
|
11
|
-
* @param base_url - Base URL being tested
|
|
12
|
-
* @param preview_url - Preview URL for the PR
|
|
13
|
-
* @returns Complete HTML string for the comparison page
|
|
14
|
-
*/
|
|
15
|
-
export declare function createComparisonHtml(base_screenshot: string, pr_screenshot: string, diff_image: string, base_url: string, preview_url: string): string;
|
|
16
|
-
//# sourceMappingURL=comparison-html.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"comparison-html.d.ts","sourceRoot":"","sources":["../../src/vision/comparison-html.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,MAAM,CA4FR"}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
2
|
-
/**
|
|
3
|
-
* Determine MIME type from image file extension.
|
|
4
|
-
*
|
|
5
|
-
* @param path - File path to analyze
|
|
6
|
-
* @returns MIME type string (image/png or image/jpeg)
|
|
7
|
-
*/
|
|
8
|
-
function getImageMimeType(path) {
|
|
9
|
-
const ext = path.toLowerCase().split(".").pop();
|
|
10
|
-
return ext === "png" ? "image/png" : "image/jpeg";
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Create HTML comparison page with base64-encoded images.
|
|
14
|
-
*
|
|
15
|
-
* This function reads screenshot images from disk, converts them to base64
|
|
16
|
-
* data URLs, and generates an HTML page that displays them side-by-side for
|
|
17
|
-
* visual comparison analysis.
|
|
18
|
-
*
|
|
19
|
-
* @param base_screenshot - Path to the base/reference screenshot
|
|
20
|
-
* @param pr_screenshot - Path to the PR/changed screenshot
|
|
21
|
-
* @param diff_image - Path to the diff image highlighting differences
|
|
22
|
-
* @param base_url - Base URL being tested
|
|
23
|
-
* @param preview_url - Preview URL for the PR
|
|
24
|
-
* @returns Complete HTML string for the comparison page
|
|
25
|
-
*/
|
|
26
|
-
export function createComparisonHtml(base_screenshot, pr_screenshot, diff_image, base_url, preview_url) {
|
|
27
|
-
// Read image files and convert to base64 data URLs.
|
|
28
|
-
const baseImageData = readFileSync(base_screenshot);
|
|
29
|
-
const prImageData = readFileSync(pr_screenshot);
|
|
30
|
-
const diffImageData = readFileSync(diff_image);
|
|
31
|
-
const base64Base = baseImageData.toString("base64");
|
|
32
|
-
const base64Pr = prImageData.toString("base64");
|
|
33
|
-
const base64Diff = diffImageData.toString("base64");
|
|
34
|
-
// Determine image format from file extension.
|
|
35
|
-
const baseMimeType = getImageMimeType(base_screenshot);
|
|
36
|
-
const prMimeType = getImageMimeType(pr_screenshot);
|
|
37
|
-
const diffMimeType = getImageMimeType(diff_image);
|
|
38
|
-
// Create HTML comparison page with the images.
|
|
39
|
-
return `
|
|
40
|
-
<!DOCTYPE html>
|
|
41
|
-
<html lang="en">
|
|
42
|
-
<head>
|
|
43
|
-
<meta charset="UTF-8">
|
|
44
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
45
|
-
<title>Visual Comparison</title>
|
|
46
|
-
<style>
|
|
47
|
-
body {
|
|
48
|
-
margin: 0;
|
|
49
|
-
padding: 20px;
|
|
50
|
-
font-family: Arial, sans-serif;
|
|
51
|
-
background: #f5f5f5;
|
|
52
|
-
}
|
|
53
|
-
.container {
|
|
54
|
-
max-width: 100%;
|
|
55
|
-
margin: 0 auto;
|
|
56
|
-
}
|
|
57
|
-
.header {
|
|
58
|
-
text-align: center;
|
|
59
|
-
margin-bottom: 20px;
|
|
60
|
-
}
|
|
61
|
-
.comparison-grid {
|
|
62
|
-
display: grid;
|
|
63
|
-
grid-template-columns: repeat(3, 1fr);
|
|
64
|
-
gap: 20px;
|
|
65
|
-
margin-bottom: 20px;
|
|
66
|
-
}
|
|
67
|
-
.image-panel {
|
|
68
|
-
background: white;
|
|
69
|
-
padding: 10px;
|
|
70
|
-
border-radius: 8px;
|
|
71
|
-
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
72
|
-
}
|
|
73
|
-
.image-panel h3 {
|
|
74
|
-
margin-top: 0;
|
|
75
|
-
text-align: center;
|
|
76
|
-
color: #333;
|
|
77
|
-
}
|
|
78
|
-
.image-panel img {
|
|
79
|
-
width: 100%;
|
|
80
|
-
height: auto;
|
|
81
|
-
display: block;
|
|
82
|
-
border: 1px solid #ddd;
|
|
83
|
-
}
|
|
84
|
-
@media (max-width: 1200px) {
|
|
85
|
-
.comparison-grid {
|
|
86
|
-
grid-template-columns: 1fr;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
</style>
|
|
90
|
-
</head>
|
|
91
|
-
<body>
|
|
92
|
-
<div class="container">
|
|
93
|
-
<div class="header">
|
|
94
|
-
<h1>Visual Comparison Analysis</h1>
|
|
95
|
-
<p><strong>Base URL:</strong> ${base_url}</p>
|
|
96
|
-
<p><strong>Preview URL:</strong> ${preview_url}</p>
|
|
97
|
-
</div>
|
|
98
|
-
<div class="comparison-grid">
|
|
99
|
-
<div class="image-panel base-image">
|
|
100
|
-
<h3>Base Screenshot</h3>
|
|
101
|
-
<img src="data:${baseMimeType};base64,${base64Base}" alt="Base Screenshot" />
|
|
102
|
-
</div>
|
|
103
|
-
<div class="image-panel pr-image">
|
|
104
|
-
<h3>PR Screenshot</h3>
|
|
105
|
-
<img src="data:${prMimeType};base64,${base64Pr}" alt="PR Screenshot" />
|
|
106
|
-
</div>
|
|
107
|
-
<div class="image-panel diff-image">
|
|
108
|
-
<h3>Diff Image</h3>
|
|
109
|
-
<img src="data:${diffMimeType};base64,${base64Diff}" alt="Diff Image" />
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
</body>
|
|
114
|
-
</html>`;
|
|
115
|
-
}
|
|
116
|
-
//# sourceMappingURL=comparison-html.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"comparison-html.js","sourceRoot":"","sources":["../../src/vision/comparison-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAElC;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IAChD,OAAO,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAClC,eAAuB,EACvB,aAAqB,EACrB,UAAkB,EAClB,QAAgB,EAChB,WAAmB;IAEnB,oDAAoD;IACpD,MAAM,aAAa,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IAE/C,MAAM,UAAU,GAAG,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEpD,8CAA8C;IAC9C,MAAM,YAAY,GAAG,gBAAgB,CAAC,eAAe,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,gBAAgB,CAAC,aAAa,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAElD,+CAA+C;IAC/C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CAwDmC,QAAQ;+CACL,WAAW;;;;;iCAKzB,YAAY,WAAW,UAAU;;;;iCAIjC,UAAU,WAAW,QAAQ;;;;iCAI7B,YAAY,WAAW,UAAU;;;;;QAK1D,CAAC;AACT,CAAC"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export type SectionCropSuggestion = "expand_up" | "expand_down" | "shift_up" | "shift_down" | "unknown";
|
|
2
|
-
export interface SectionCropJudgeResult {
|
|
3
|
-
ok: boolean;
|
|
4
|
-
reason: string;
|
|
5
|
-
suggestion: SectionCropSuggestion;
|
|
6
|
-
}
|
|
7
|
-
export declare function judgeSectionCrop(imageBuffer: Buffer, sectionName: string, sectionDescription: string): Promise<SectionCropJudgeResult>;
|
|
8
|
-
//# sourceMappingURL=section-judge.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"section-judge.d.ts","sourceRoot":"","sources":["../../src/vision/section-judge.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,qBAAqB,GAC7B,WAAW,GACX,aAAa,GACb,UAAU,GACV,YAAY,GACZ,SAAS,CAAC;AAEd,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,qBAAqB,CAAC;CACnC;AAeD,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAAC,sBAAsB,CAAC,CA6EjC"}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import OpenAI from "openai";
|
|
2
|
-
function extractJsonFromResponse(response) {
|
|
3
|
-
let jsonString = response.trim();
|
|
4
|
-
const jsonMatch = jsonString.match(/```(?:json)?\s*(\{[\s\S]*\})\s*```/);
|
|
5
|
-
if (jsonMatch) {
|
|
6
|
-
return jsonMatch[1];
|
|
7
|
-
}
|
|
8
|
-
const jsonObjectMatch = jsonString.match(/\{[\s\S]*\}/);
|
|
9
|
-
if (jsonObjectMatch) {
|
|
10
|
-
return jsonObjectMatch[0];
|
|
11
|
-
}
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
export async function judgeSectionCrop(imageBuffer, sectionName, sectionDescription) {
|
|
15
|
-
const apiKey = process.env.OPENAI_API_KEY;
|
|
16
|
-
if (!apiKey) {
|
|
17
|
-
return {
|
|
18
|
-
ok: true,
|
|
19
|
-
reason: "OPENAI_API_KEY not set.",
|
|
20
|
-
suggestion: "unknown",
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
const model = process.env.OPENAI_SECTION_JUDGE_MODEL || "gpt-4o-mini";
|
|
24
|
-
const openai = new OpenAI({ apiKey });
|
|
25
|
-
const base64 = imageBuffer.toString("base64");
|
|
26
|
-
const systemPrompt = "You are a strict visual judge. Determine whether the crop matches the " +
|
|
27
|
-
"given section name and description. Respond with JSON only.";
|
|
28
|
-
const userPrompt = `
|
|
29
|
-
Section name: ${sectionName}
|
|
30
|
-
Section description: ${sectionDescription}
|
|
31
|
-
|
|
32
|
-
Decide if the crop content matches this section. If it does not, provide a
|
|
33
|
-
suggestion for how to adjust the crop: "expand_up", "expand_down", "shift_up",
|
|
34
|
-
"shift_down", or "unknown".
|
|
35
|
-
|
|
36
|
-
Return JSON only with this exact structure:
|
|
37
|
-
{
|
|
38
|
-
"ok": true | false,
|
|
39
|
-
"reason": "Short reason",
|
|
40
|
-
"suggestion": "expand_up" | "expand_down" | "shift_up" | "shift_down" | "unknown"
|
|
41
|
-
}
|
|
42
|
-
`;
|
|
43
|
-
const completion = await openai.chat.completions.create({
|
|
44
|
-
model,
|
|
45
|
-
messages: [
|
|
46
|
-
{ role: "system", content: systemPrompt },
|
|
47
|
-
{
|
|
48
|
-
role: "user",
|
|
49
|
-
content: [
|
|
50
|
-
{ type: "text", text: userPrompt },
|
|
51
|
-
{
|
|
52
|
-
type: "image_url",
|
|
53
|
-
image_url: {
|
|
54
|
-
url: `data:image/png;base64,${base64}`,
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
max_tokens: 512,
|
|
61
|
-
});
|
|
62
|
-
const content = completion.choices[0]?.message?.content || "";
|
|
63
|
-
const jsonString = extractJsonFromResponse(content);
|
|
64
|
-
if (!jsonString) {
|
|
65
|
-
return {
|
|
66
|
-
ok: true,
|
|
67
|
-
reason: "Judge response missing JSON.",
|
|
68
|
-
suggestion: "unknown",
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
try {
|
|
72
|
-
const parsed = JSON.parse(jsonString);
|
|
73
|
-
return {
|
|
74
|
-
ok: Boolean(parsed.ok),
|
|
75
|
-
reason: parsed.reason || "",
|
|
76
|
-
suggestion: parsed.suggestion || "unknown",
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
return {
|
|
81
|
-
ok: true,
|
|
82
|
-
reason: "Judge response invalid JSON.",
|
|
83
|
-
suggestion: "unknown",
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
//# sourceMappingURL=section-judge.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"section-judge.js","sourceRoot":"","sources":["../../src/vision/section-judge.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAe5B,SAAS,uBAAuB,CAAC,QAAgB;IAC/C,IAAI,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjC,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACzE,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,MAAM,eAAe,GAAG,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACxD,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,WAAmB,EACnB,WAAmB,EACnB,kBAA0B;IAE1B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,yBAAyB;YACjC,UAAU,EAAE,SAAS;SACtB,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,aAAa,CAAC;IACtE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAE9C,MAAM,YAAY,GAChB,wEAAwE;QACxE,6DAA6D,CAAC;IAChE,MAAM,UAAU,GAAG;gBACL,WAAW;uBACJ,kBAAkB;;;;;;;;;;;;CAYxC,CAAC;IAEA,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;QACtD,KAAK;QACL,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;YACzC;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE;oBAClC;wBACE,IAAI,EAAE,WAAW;wBACjB,SAAS,EAAE;4BACT,GAAG,EAAE,yBAAyB,MAAM,EAAE;yBACvC;qBACF;iBACF;aACF;SACF;QACD,UAAU,EAAE,GAAG;KAChB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;IAC9D,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,8BAA8B;YACtC,UAAU,EAAE,SAAS;SACtB,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAA2B,CAAC;QAChE,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;YAC3B,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,SAAS;SAC3C,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,8BAA8B;YACtC,UAAU,EAAE,SAAS;SACtB,CAAC;IACJ,CAAC;AACH,CAAC"}
|