chore: add ruxa image model verification script

This commit is contained in:
Your Name 2026-06-08 18:22:41 +08:00
parent afd1f84789
commit a8e62962b8
2 changed files with 209 additions and 0 deletions

View File

@ -33,6 +33,7 @@
"clean:artifacts": "node scripts/clean-local-artifacts.mjs",
"smoke:routes": "node scripts/smoke-routes.mjs",
"verify:release": "node scripts/verify-release.mjs",
"verify:ruxa-models": "pnpm exec tsx scripts/verify-ruxa-image-models.ts",
"backfill:agent-preview-images": "pnpm exec tsx scripts/backfill-agent-workflow-preview-images.ts",
"rewrite:agent-preview-image-urls": "pnpm exec tsx scripts/rewrite-agent-workflow-preview-image-urls.ts",
"format": "pnpm exec ultracite fix",

View File

@ -0,0 +1,208 @@
import { config as loadEnv } from "dotenv";
import { and, eq, sql } from "drizzle-orm";
import { db } from "../lib/db";
import { aiModel, aiProvider } from "../lib/db/schema";
loadEnv({ path: ".env.local" });
type ModelExpectation = {
modelId: string;
displayName: string;
};
const EXPECTED_MODELS: ModelExpectation[] = [
{ modelId: "google/nano-banana-2", displayName: "nano-banana-2「专线」" },
{ modelId: "google/nano-banana-pro", displayName: "nano-banana-pro「专线」" },
];
type Row = {
providerId: string;
providerName: string;
providerType: string;
modelId: string;
displayName: string;
supportsImageGen: boolean | null;
supportsVision: boolean | null;
isEnabled: boolean | null;
isHidden: boolean | null;
healthStatus: string | null;
imageGenConfig: Record<string, unknown> | null;
};
function getConfigFlag(
config: Record<string, unknown> | null,
key: string
): boolean | null {
const raw = config?.[key];
return typeof raw === "boolean" ? raw : null;
}
async function main() {
const rows = await db
.select({
providerId: aiProvider.id,
providerName: aiProvider.name,
providerType: aiProvider.type,
modelId: aiModel.modelId,
displayName: aiModel.displayName,
supportsImageGen: aiModel.supportsImageGen,
supportsVision: aiModel.supportsVision,
isEnabled: aiModel.isEnabled,
isHidden: aiModel.isHidden,
healthStatus: aiModel.healthStatus,
imageGenConfig: aiModel.imageGenConfig,
})
.from(aiModel)
.innerJoin(aiProvider, eq(aiModel.providerId, aiProvider.id))
.where(
and(
eq(aiProvider.type, "ruxa-image"),
sql`LOWER(${aiProvider.name}) LIKE ${"%ruxa%"}`,
sql`LOWER(${aiModel.modelId}) IN (${"google/nano-banana-2"}, ${"google/nano-banana-pro"})`
)
);
const found = new Map<string, Row[]>();
for (const row of rows) {
const bucket = found.get(row.providerId) ?? [];
bucket.push(row);
found.set(row.providerId, bucket);
}
const providers = [...found.entries()].map(([providerId, models]) => ({
providerId,
providerName: models[0]?.providerName ?? "",
providerType: models[0]?.providerType ?? "",
modelCount: models.length,
models,
}));
const failures: string[] = [];
const expectByModelId = new Map(
EXPECTED_MODELS.map((entry) => [entry.modelId, entry.displayName])
);
const expectedSet = new Set(expectByModelId.keys());
for (const row of rows) {
if (!expectedSet.has(row.modelId)) {
failures.push(`Unexpected model present in RUXA image provider: ${row.modelId}`);
continue;
}
const expectedDisplayName = expectByModelId.get(row.modelId);
if (expectedDisplayName && row.displayName !== expectedDisplayName) {
failures.push(
`${row.providerName} ${row.modelId}: displayName mismatch (expected "${expectedDisplayName}", got "${row.displayName}")`
);
}
const config =
row.imageGenConfig &&
typeof row.imageGenConfig === "object" &&
!Array.isArray(row.imageGenConfig)
? (row.imageGenConfig as Record<string, unknown>)
: null;
if (row.supportsImageGen !== true) {
failures.push(`${row.providerName} ${row.modelId}: supportsImageGen is not true`);
}
if (row.supportsVision !== true) {
failures.push(`${row.providerName} ${row.modelId}: supportsVision is not true`);
}
if (row.isEnabled !== true) {
failures.push(`${row.providerName} ${row.modelId}: isEnabled is not true`);
}
if (row.isHidden === true) {
failures.push(`${row.providerName} ${row.modelId}: isHidden should be false`);
}
if (row.healthStatus !== "healthy") {
failures.push(
`${row.providerName} ${row.modelId}: healthStatus is ${row.healthStatus ?? "null"}, expected healthy`
);
}
if (getConfigFlag(config, "supportsSize") !== true) {
failures.push(`${row.providerName} ${row.modelId}: imageGenConfig.supportsSize should be true`);
}
if (getConfigFlag(config, "supports1K") !== true) {
failures.push(
`${row.providerName} ${row.modelId}: imageGenConfig.supports1K should be true`
);
}
if (getConfigFlag(config, "supports2K") !== true) {
failures.push(
`${row.providerName} ${row.modelId}: imageGenConfig.supports2K should be true`
);
}
if (getConfigFlag(config, "supports4K") !== true) {
failures.push(
`${row.providerName} ${row.modelId}: imageGenConfig.supports4K should be true`
);
}
}
for (const provider of providers) {
const providerModels = provider.models.map((item) => item.modelId);
for (const expected of EXPECTED_MODELS) {
if (!providerModels.includes(expected.modelId)) {
failures.push(
`${provider.providerName}: missing required model ${expected.modelId} (${expected.displayName})`
);
}
}
}
const providerSummary = providers
.sort((a, b) => a.providerName.localeCompare(b.providerName))
.map((provider) => {
return {
providerName: provider.providerName,
providerType: provider.providerType,
providerId: provider.providerId,
hasAllTargets: EXPECTED_MODELS.every((expected) =>
provider.models.some((row) => row.modelId === expected.modelId)
),
modelRows: provider.models
.sort((a, b) => a.modelId.localeCompare(b.modelId))
.map((row) => ({
modelId: row.modelId,
displayName: row.displayName,
isEnabled: row.isEnabled,
healthStatus: row.healthStatus,
imageSize4K: getConfigFlag(
row.imageGenConfig &&
typeof row.imageGenConfig === "object" &&
!Array.isArray(row.imageGenConfig)
? (row.imageGenConfig as Record<string, unknown>)
: null,
"supports4K"
),
})),
};
});
console.log(
JSON.stringify(
{
expected: EXPECTED_MODELS,
providerSummary,
},
null,
2
)
);
if (failures.length > 0) {
console.error("RUXA image model check failed:");
failures.forEach((item) => console.error(`- ${item}`));
process.exit(1);
}
console.log("RUXA image model check passed.");
}
main().catch((error) => {
console.error("RUXA image model verification failed to execute:", error);
process.exit(1);
});