2024-08-04 08:28:19 +08:00
|
|
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
|
import path from 'node:path';
|
2025-02-10 16:36:12 +08:00
|
|
|
import { describeUserPage } from '@midscene/core';
|
|
|
|
import { base64Encoded, imageInfoOfBase64 } from '@midscene/shared/img';
|
|
|
|
|
|
|
|
export const repeatTime = 1;
|
2024-07-23 16:25:11 +08:00
|
|
|
|
|
|
|
type TestCase = {
|
2024-09-29 17:16:07 +08:00
|
|
|
prompt: string;
|
2024-10-31 18:18:31 +08:00
|
|
|
response: Array<{ id: string; indexId: number }>;
|
2025-01-16 14:37:35 +08:00
|
|
|
expected?: boolean;
|
2024-09-29 17:16:07 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export type InspectAiTestCase = {
|
|
|
|
testDataPath: string;
|
|
|
|
testCases: Array<TestCase>;
|
2024-07-23 16:25:11 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export interface AiElementsResponse {
|
2024-10-31 18:18:31 +08:00
|
|
|
elements: Array<
|
|
|
|
| {
|
|
|
|
id: string;
|
|
|
|
reason: string;
|
|
|
|
text: string;
|
|
|
|
}
|
|
|
|
| {
|
|
|
|
position: {
|
|
|
|
x: number;
|
|
|
|
y: number;
|
|
|
|
};
|
|
|
|
reason: string;
|
|
|
|
text: string;
|
|
|
|
}
|
|
|
|
>;
|
2024-07-23 16:25:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface TextAiElementResponse extends AiElementsResponse {
|
2024-10-31 18:18:31 +08:00
|
|
|
response: Array<
|
|
|
|
| {
|
|
|
|
id: string;
|
|
|
|
}
|
|
|
|
| {
|
|
|
|
position: {
|
|
|
|
x: number;
|
|
|
|
y: number;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
>;
|
2024-08-04 08:28:19 +08:00
|
|
|
// for test
|
|
|
|
caseIndex?: number;
|
|
|
|
prompt: string;
|
|
|
|
error?: string;
|
2024-09-29 17:16:07 +08:00
|
|
|
spendTime: number;
|
2024-08-09 21:37:41 +08:00
|
|
|
elementsSnapshot: Array<any>;
|
2024-07-23 16:25:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export async function runTestCases(
|
2024-08-04 08:28:19 +08:00
|
|
|
testCases: Array<TestCase>,
|
2024-08-09 21:37:41 +08:00
|
|
|
context: any,
|
2024-08-04 08:28:19 +08:00
|
|
|
getAiResponse: (options: {
|
|
|
|
description: string;
|
|
|
|
}) => Promise<AiElementsResponse>,
|
2024-07-23 16:25:11 +08:00
|
|
|
) {
|
2024-08-04 08:28:19 +08:00
|
|
|
let aiResponse: Array<TextAiElementResponse> = [];
|
2024-08-09 21:37:41 +08:00
|
|
|
const { content: elementSnapshot } = context;
|
2025-02-10 16:36:12 +08:00
|
|
|
for (let caseIndex = 0; caseIndex < testCases.length; caseIndex++) {
|
|
|
|
const testCase = testCases[caseIndex];
|
2024-08-04 08:28:19 +08:00
|
|
|
const startTime = Date.now();
|
2024-09-29 17:16:07 +08:00
|
|
|
const msg = await getAiResponse({
|
|
|
|
description: testCase.prompt,
|
|
|
|
});
|
2024-08-04 08:28:19 +08:00
|
|
|
const endTime = Date.now();
|
2024-09-29 17:16:07 +08:00
|
|
|
const spendTime = endTime - startTime;
|
2024-08-04 08:28:19 +08:00
|
|
|
if (msg.elements) {
|
|
|
|
aiResponse.push({
|
|
|
|
...msg,
|
2024-09-29 17:16:07 +08:00
|
|
|
prompt: testCase.prompt,
|
|
|
|
response: msg.elements,
|
2024-08-04 08:28:19 +08:00
|
|
|
caseIndex,
|
2024-09-29 17:16:07 +08:00
|
|
|
spendTime,
|
2024-08-09 21:37:41 +08:00
|
|
|
elementsSnapshot: msg.elements.map((element) => {
|
|
|
|
const index = elementSnapshot.findIndex((item: any) => {
|
2024-10-31 18:18:31 +08:00
|
|
|
if ('id' in element && item.nodeHashId === element.id) {
|
2024-08-09 21:37:41 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return elementSnapshot[index];
|
|
|
|
}),
|
2024-08-04 08:28:19 +08:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
aiResponse.push({
|
2024-09-29 17:16:07 +08:00
|
|
|
error: `can't find element with description: ${testCase.prompt}`,
|
2024-08-04 08:28:19 +08:00
|
|
|
} as any);
|
|
|
|
}
|
2025-02-10 16:36:12 +08:00
|
|
|
}
|
|
|
|
|
2024-08-04 08:28:19 +08:00
|
|
|
aiResponse = aiResponse.sort((a, b) => {
|
|
|
|
if (a.caseIndex !== undefined && b.caseIndex !== undefined) {
|
|
|
|
return a.caseIndex - b.caseIndex;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
});
|
2024-07-23 16:25:11 +08:00
|
|
|
|
2024-08-04 08:28:19 +08:00
|
|
|
aiResponse.forEach((item) => {
|
|
|
|
if ('caseIndex' in item) {
|
|
|
|
item.caseIndex = undefined;
|
|
|
|
}
|
|
|
|
});
|
2024-07-23 16:25:11 +08:00
|
|
|
|
2024-08-06 10:00:25 +08:00
|
|
|
const filterUnstableResult = aiResponse.map((aiInfo) => {
|
2024-08-09 21:37:41 +08:00
|
|
|
const { elements = [], prompt, error = [], elementsSnapshot } = aiInfo;
|
2024-07-23 16:25:11 +08:00
|
|
|
return {
|
2024-08-09 21:37:41 +08:00
|
|
|
elements: elements.map((element, index) => {
|
2024-08-04 08:28:19 +08:00
|
|
|
return {
|
2024-10-31 18:18:31 +08:00
|
|
|
id: 'id' in element ? element.id.toString() : '',
|
2024-09-29 17:16:07 +08:00
|
|
|
indexId: elementsSnapshot[index]?.indexId,
|
2024-08-04 08:28:19 +08:00
|
|
|
};
|
|
|
|
}),
|
|
|
|
error,
|
2024-08-31 08:17:50 +08:00
|
|
|
prompt,
|
2024-07-23 16:25:11 +08:00
|
|
|
};
|
2024-08-04 08:28:19 +08:00
|
|
|
});
|
2024-07-23 16:25:11 +08:00
|
|
|
|
2024-08-04 08:28:19 +08:00
|
|
|
return {
|
|
|
|
aiResponse,
|
2024-08-06 10:00:25 +08:00
|
|
|
filterUnstableResult,
|
2024-08-04 08:28:19 +08:00
|
|
|
};
|
|
|
|
}
|
2024-07-23 16:25:11 +08:00
|
|
|
|
|
|
|
export const repeat = (times: number, fn: (index: number) => void) => {
|
2024-08-04 08:28:19 +08:00
|
|
|
for (let i = 1; i <= times; i++) {
|
|
|
|
fn(i);
|
|
|
|
}
|
2024-07-23 16:25:11 +08:00
|
|
|
};
|
|
|
|
|
2025-01-16 14:37:35 +08:00
|
|
|
export const repeatFile = (
|
|
|
|
files: Array<string>,
|
|
|
|
times: number,
|
|
|
|
fn: (file: string, index: number) => void,
|
|
|
|
) => {
|
|
|
|
for (const file of files) {
|
|
|
|
repeat(times, (index) => {
|
|
|
|
fn(file, index);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-07-23 16:25:11 +08:00
|
|
|
function ensureDirectoryExistence(filePath: string) {
|
2024-08-04 08:28:19 +08:00
|
|
|
const dirname = path.dirname(filePath);
|
|
|
|
if (existsSync(dirname)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
ensureDirectoryExistence(dirname);
|
|
|
|
mkdirSync(dirname);
|
2024-07-23 16:25:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type WriteFileSyncParams = Parameters<typeof writeFileSync>;
|
|
|
|
|
2024-08-04 08:28:19 +08:00
|
|
|
export function writeFileSyncWithDir(
|
|
|
|
filePath: string,
|
|
|
|
content: WriteFileSyncParams[1],
|
|
|
|
options: WriteFileSyncParams[2] = {},
|
|
|
|
) {
|
|
|
|
ensureDirectoryExistence(filePath);
|
|
|
|
writeFileSync(filePath, content, options);
|
2024-07-23 16:25:11 +08:00
|
|
|
}
|