2024-09-05 20:05:19 +08:00
|
|
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
2024-08-04 08:28:19 +08:00
|
|
|
import path from 'node:path';
|
2024-08-21 17:24:32 +08:00
|
|
|
import type { WebPage } from '@/common/page';
|
2024-09-05 20:05:19 +08:00
|
|
|
import type { ElementInfo } from '@/extractor';
|
2024-08-26 18:50:33 +08:00
|
|
|
import { NodeType } from '@/extractor/constants';
|
|
|
|
import {
|
|
|
|
processImageElementInfo,
|
|
|
|
resizeImg,
|
|
|
|
saveBase64Image,
|
|
|
|
} from '@midscene/shared/img';
|
2024-07-23 16:25:11 +08:00
|
|
|
|
2024-08-22 18:12:01 +08:00
|
|
|
export async function generateExtractData(
|
2024-08-21 17:24:32 +08:00
|
|
|
page: WebPage,
|
2024-08-04 08:28:19 +08:00
|
|
|
targetDir: string,
|
2024-08-21 17:24:32 +08:00
|
|
|
saveImgType?: {
|
|
|
|
disableInputImage: boolean;
|
|
|
|
disableOutputImage: boolean;
|
|
|
|
disableOutputWithoutTextImg: boolean;
|
|
|
|
disableResizeOutputImg: boolean;
|
|
|
|
disableSnapshot: boolean;
|
|
|
|
},
|
2024-08-04 08:28:19 +08:00
|
|
|
) {
|
2024-09-23 10:57:19 +08:00
|
|
|
const file = await page.screenshot();
|
2024-09-05 20:05:19 +08:00
|
|
|
const screenshotBuffer = readFileSync(file);
|
|
|
|
|
|
|
|
const inputImgBase64 = screenshotBuffer.toString('base64');
|
2024-08-22 18:12:01 +08:00
|
|
|
|
2024-08-04 08:28:19 +08:00
|
|
|
const {
|
|
|
|
elementsPositionInfo,
|
|
|
|
captureElementSnapshot,
|
|
|
|
elementsPositionInfoWithoutText,
|
|
|
|
} = await getElementInfos(page);
|
2024-07-23 16:25:11 +08:00
|
|
|
|
|
|
|
const inputImagePath = path.join(targetDir, 'input.png');
|
|
|
|
const outputImagePath = path.join(targetDir, 'output.png');
|
2024-08-04 08:28:19 +08:00
|
|
|
const outputWithoutTextImgPath = path.join(
|
|
|
|
targetDir,
|
|
|
|
'output_without_text.png',
|
|
|
|
);
|
2024-07-23 16:25:11 +08:00
|
|
|
const resizeOutputImgPath = path.join(targetDir, 'resize-output.png');
|
|
|
|
const snapshotJsonPath = path.join(targetDir, 'element-snapshot.json');
|
|
|
|
|
2024-08-04 08:28:19 +08:00
|
|
|
const {
|
|
|
|
compositeElementInfoImgBase64,
|
|
|
|
compositeElementInfoImgWithoutTextBase64,
|
|
|
|
} = await processImageElementInfo({
|
|
|
|
elementsPositionInfo,
|
|
|
|
elementsPositionInfoWithoutText,
|
|
|
|
inputImgBase64,
|
|
|
|
});
|
2024-07-23 16:25:11 +08:00
|
|
|
|
2024-09-05 20:05:19 +08:00
|
|
|
const resizeImgBase64 = (await resizeImg(inputImgBase64)) as string;
|
2024-07-23 16:25:11 +08:00
|
|
|
|
2024-08-21 17:24:32 +08:00
|
|
|
if (!saveImgType?.disableSnapshot) {
|
|
|
|
writeFileSyncWithDir(
|
|
|
|
snapshotJsonPath,
|
|
|
|
JSON.stringify(captureElementSnapshot, null, 2),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (!saveImgType?.disableInputImage) {
|
|
|
|
await saveBase64Image({
|
|
|
|
base64Data: inputImgBase64,
|
|
|
|
outputPath: inputImagePath,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (!saveImgType?.disableOutputImage) {
|
|
|
|
await saveBase64Image({
|
|
|
|
base64Data: compositeElementInfoImgBase64,
|
|
|
|
outputPath: outputImagePath,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (!saveImgType?.disableOutputWithoutTextImg) {
|
|
|
|
await saveBase64Image({
|
|
|
|
base64Data: compositeElementInfoImgWithoutTextBase64,
|
|
|
|
outputPath: outputWithoutTextImgPath,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (!saveImgType?.disableResizeOutputImg) {
|
|
|
|
await saveBase64Image({
|
|
|
|
base64Data: resizeImgBase64,
|
|
|
|
outputPath: resizeOutputImgPath,
|
|
|
|
});
|
|
|
|
}
|
2024-07-23 16:25:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export function generateTestDataPath(testDataName: string) {
|
|
|
|
// `dist/lib/index.js` Is the default export path
|
2024-08-04 08:28:19 +08:00
|
|
|
const modulePath = require
|
|
|
|
.resolve('@midscene/core')
|
|
|
|
.replace('dist/lib/index.js', '');
|
|
|
|
const midsceneTestDataPath = path.join(
|
|
|
|
modulePath,
|
2024-08-20 07:41:08 +08:00
|
|
|
`tests/ai/inspector/test-data/${testDataName}`,
|
2024-08-04 08:28:19 +08:00
|
|
|
);
|
2024-07-23 16:25:11 +08:00
|
|
|
|
|
|
|
return midsceneTestDataPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
function ensureDirectoryExistence(filePath: string) {
|
|
|
|
const dirname = path.dirname(filePath);
|
|
|
|
if (existsSync(dirname)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ensureDirectoryExistence(dirname);
|
|
|
|
mkdirSync(dirname);
|
|
|
|
}
|
|
|
|
|
|
|
|
type WriteFileSyncParams = Parameters<typeof writeFileSync>;
|
|
|
|
|
|
|
|
export function writeFileSyncWithDir(
|
|
|
|
filePath: string,
|
|
|
|
content: WriteFileSyncParams[1],
|
|
|
|
options: WriteFileSyncParams[2] = {},
|
|
|
|
) {
|
|
|
|
ensureDirectoryExistence(filePath);
|
|
|
|
writeFileSync(filePath, content, options);
|
|
|
|
}
|
2024-08-26 18:50:33 +08:00
|
|
|
|
2024-09-05 20:05:19 +08:00
|
|
|
export async function getElementInfos(page: WebPage) {
|
2024-08-26 18:50:33 +08:00
|
|
|
const captureElementSnapshot: Array<ElementInfo> =
|
2024-09-05 20:05:19 +08:00
|
|
|
await page.getElementInfos();
|
2024-08-31 08:17:50 +08:00
|
|
|
|
|
|
|
const elementsPositionInfo = captureElementSnapshot.map(
|
|
|
|
(elementInfo, index) => {
|
|
|
|
return {
|
|
|
|
label: elementInfo.indexId?.toString() || index.toString(),
|
|
|
|
x: elementInfo.rect.left,
|
|
|
|
y: elementInfo.rect.top,
|
|
|
|
width: elementInfo.rect.width,
|
|
|
|
height: elementInfo.rect.height,
|
|
|
|
attributes: elementInfo.attributes,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
);
|
2024-08-26 18:50:33 +08:00
|
|
|
const elementsPositionInfoWithoutText = elementsPositionInfo.filter(
|
|
|
|
(elementInfo) => {
|
|
|
|
if (elementInfo.attributes.nodeType === NodeType.TEXT) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
);
|
|
|
|
return {
|
|
|
|
elementsPositionInfo,
|
|
|
|
captureElementSnapshot,
|
|
|
|
elementsPositionInfoWithoutText,
|
|
|
|
};
|
|
|
|
}
|