205 lines
6.3 KiB
TypeScript
205 lines
6.3 KiB
TypeScript
import { fetchAtlasCloudImagePresets } from "../lib/ai/atlascloud-models";
|
|
import { createAtlasCloudRequestBody } from "../lib/ai/atlascloud-request";
|
|
import {
|
|
is3DModelDescriptor,
|
|
isImageGenerationModelDescriptor,
|
|
isVideoModelDescriptor,
|
|
} from "../lib/ai/model-classification";
|
|
|
|
const FAKE_IMAGES = Array.from(
|
|
{ length: 14 },
|
|
(_, index) => `https://example.com/reference-${index + 1}.png`
|
|
);
|
|
const FAKE_VIDEOS = Array.from(
|
|
{ length: 4 },
|
|
(_, index) => `https://example.com/reference-${index + 1}.mp4`
|
|
);
|
|
|
|
type Failure = {
|
|
modelId: string;
|
|
scenario: string;
|
|
error: string;
|
|
};
|
|
|
|
function validateBody(
|
|
body: Record<string, unknown>,
|
|
runtime: any
|
|
) {
|
|
const missing = runtime.requiredFields.filter(
|
|
(key: string) => body[key] === undefined
|
|
);
|
|
if (missing.length > 0) {
|
|
throw new Error(`缺少必填参数:${missing.join(", ")}`);
|
|
}
|
|
for (const [key, values] of Object.entries(
|
|
runtime.enums as Record<string, Array<string | number>>
|
|
)) {
|
|
if (body[key] === undefined || !values.length) continue;
|
|
if (!values.some((value) => String(value) === String(body[key]))) {
|
|
throw new Error(`${key}=${String(body[key])} 不在官方枚举中`);
|
|
}
|
|
}
|
|
if (runtime.videoClipInput && body[runtime.videoClipInput.key] !== undefined) {
|
|
const clips = body[runtime.videoClipInput.key];
|
|
if (!Array.isArray(clips) || clips.length === 0) {
|
|
throw new Error("video_clips 请求格式无效");
|
|
}
|
|
for (const clip of clips) {
|
|
if (!clip || typeof clip !== "object" || !("url" in clip)) {
|
|
throw new Error("video_clips 缺少 url");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
const catalog = await fetchAtlasCloudImagePresets();
|
|
const failures: Failure[] = catalog.errors.map((item) => ({
|
|
modelId: item.modelId,
|
|
scenario: "catalog-schema",
|
|
error: item.error,
|
|
}));
|
|
let simulatedCases = 0;
|
|
let imageModels = 0;
|
|
let model3dModels = 0;
|
|
let videoReferenceModels = 0;
|
|
|
|
for (const preset of catalog.presets) {
|
|
const capabilities = preset.capabilities as Record<string, any>;
|
|
const descriptor = {
|
|
providerType: "atlascloud",
|
|
modelId: preset.modelId,
|
|
capabilities,
|
|
supportsImageGen: preset.supportsImageGen,
|
|
};
|
|
const mediaType = String(capabilities.mediaType || "");
|
|
|
|
if (mediaType === "3d") {
|
|
model3dModels += 1;
|
|
simulatedCases += 1;
|
|
if (
|
|
!is3DModelDescriptor(descriptor) ||
|
|
isImageGenerationModelDescriptor(descriptor) ||
|
|
isVideoModelDescriptor(descriptor)
|
|
) {
|
|
failures.push({
|
|
modelId: preset.modelId,
|
|
scenario: "3d-classification",
|
|
error: "3D 模型被错误归入图片或视频模型",
|
|
});
|
|
}
|
|
continue;
|
|
}
|
|
|
|
imageModels += 1;
|
|
if (
|
|
!isImageGenerationModelDescriptor(descriptor) ||
|
|
is3DModelDescriptor(descriptor) ||
|
|
isVideoModelDescriptor(descriptor)
|
|
) {
|
|
failures.push({
|
|
modelId: preset.modelId,
|
|
scenario: "image-classification",
|
|
error: "图片模型分类不正确",
|
|
});
|
|
continue;
|
|
}
|
|
|
|
const imageGenConfig = preset.imageGenConfig as Record<string, any>;
|
|
const runtime = imageGenConfig.atlasCloud;
|
|
if (!runtime) {
|
|
failures.push({
|
|
modelId: preset.modelId,
|
|
scenario: "runtime-config",
|
|
error: "缺少 AtlasCloud 运行配置",
|
|
});
|
|
continue;
|
|
}
|
|
|
|
const ratios = imageGenConfig.supportedAspectRatios?.length
|
|
? imageGenConfig.supportedAspectRatios
|
|
: [String(preset.defaultParams.aspectRatio || "1:1")];
|
|
const sizes = imageGenConfig.supportedImageSizes?.length
|
|
? imageGenConfig.supportedImageSizes
|
|
: [String(preset.defaultParams.imageSize || "1K")];
|
|
const counts = runtime.outputCountKey && runtime.maxImages > 1
|
|
? [1, runtime.maxImages]
|
|
: [1];
|
|
const requiredImageCount = runtime.imageInputs
|
|
.filter((input: any) => input.required)
|
|
.reduce((total: number, input: any) => total + input.maxItems, 0);
|
|
const imageReferenceCounts = new Set<number>([
|
|
requiredImageCount,
|
|
...(runtime.maxReferenceImages > requiredImageCount
|
|
? [runtime.maxReferenceImages]
|
|
: []),
|
|
]);
|
|
const requiredVideoCount = runtime.videoClipInput?.required
|
|
? runtime.videoClipInput.maxItems
|
|
: 0;
|
|
const videoReferenceCounts = new Set<number>([
|
|
requiredVideoCount,
|
|
...(runtime.maxVideoReferences > requiredVideoCount
|
|
? [runtime.maxVideoReferences]
|
|
: []),
|
|
]);
|
|
if (runtime.maxVideoReferences > 0) videoReferenceModels += 1;
|
|
|
|
for (const ratio of ratios) {
|
|
for (const size of sizes) {
|
|
for (const imageCount of counts) {
|
|
for (const referenceImageCount of imageReferenceCounts) {
|
|
for (const referenceVideoCount of videoReferenceCounts) {
|
|
const scenario = [
|
|
`ratio=${ratio}`,
|
|
`size=${size}`,
|
|
`count=${imageCount}`,
|
|
`images=${referenceImageCount}`,
|
|
`videos=${referenceVideoCount}`,
|
|
].join(",");
|
|
simulatedCases += 1;
|
|
try {
|
|
const { body } = createAtlasCloudRequestBody({
|
|
modelId: preset.modelId,
|
|
prompt: "AtlasCloud 前端请求模拟测试",
|
|
referenceImages: FAKE_IMAGES.slice(0, referenceImageCount),
|
|
referenceVideos: FAKE_VIDEOS.slice(0, referenceVideoCount),
|
|
imageParams: {
|
|
aspectRatio: ratio,
|
|
imageSize: size,
|
|
imageCount,
|
|
},
|
|
modelConfig: imageGenConfig,
|
|
});
|
|
validateBody(body, runtime);
|
|
} catch (error) {
|
|
failures.push({
|
|
modelId: preset.modelId,
|
|
scenario,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const summary = {
|
|
catalogModels: catalog.catalogCount,
|
|
availableModels: catalog.presets.length,
|
|
imageModels,
|
|
model3dModels,
|
|
videoReferenceModels,
|
|
simulatedCases,
|
|
passedCases: simulatedCases - failures.length,
|
|
failedCases: failures.length,
|
|
failures,
|
|
};
|
|
console.log(JSON.stringify(summary, null, 2));
|
|
if (failures.length > 0) process.exitCode = 1;
|
|
}
|
|
|
|
void main();
|