ai-chatbot/tests/routes/model-classification.test.ts

117 lines
3.4 KiB
TypeScript

import { expect, test } from "@playwright/test";
import {
isImageGenerationModelDescriptor,
isStillImageGenerationModelDescriptor,
isVideoModelDescriptor,
} from "@/lib/ai/model-classification";
import { getStyleProModelAvailability } from "@/lib/style-pro/model-availability";
import type { AiProvider } from "@/lib/db/schema";
function styleProEntry(overrides?: {
providerType?: AiProvider["type"];
modelId?: string;
supportsVision?: boolean;
healthStatus?: "healthy" | "degraded" | "auto_disabled";
healthAutoDisabledAt?: Date | null;
healthObservationStartedAt?: Date | null;
}) {
return {
model: {
displayName: "Test Image Model",
modelId: overrides?.modelId || "test-image-model",
supportsVision: overrides?.supportsVision ?? true,
capabilities: null,
defaultParams: null,
isEnabled: true,
healthStatus: overrides?.healthStatus || "healthy",
healthAutoDisabledAt: overrides?.healthAutoDisabledAt || null,
healthObservationStartedAt:
overrides?.healthObservationStartedAt || null,
},
provider: {
type: overrides?.providerType || "openai-image",
},
};
}
test.describe("model classification", () => {
test("keeps multi-reference BananaImage models classified as image models", () => {
const descriptor = {
providerType: "bananaimage",
modelId: "gemini-3-pro-image-preview",
capabilities: {
supportedModes: [
"text-to-image",
"image-to-image",
"reference-images",
],
},
supportsImageGen: true,
};
expect(isVideoModelDescriptor(descriptor)).toBe(false);
expect(isImageGenerationModelDescriptor(descriptor)).toBe(true);
});
test("still recognizes explicit video generation modes", () => {
expect(
isVideoModelDescriptor({
providerType: "custom",
modelId: "custom-video-model",
capabilities: { supportedModes: ["text-to-video"] },
})
).toBe(true);
});
test("uses one image-only rule for canvas and Style Pro model pools", () => {
expect(
isStillImageGenerationModelDescriptor({
providerType: "ruxa-image",
modelId: "google/nano-banana-2",
supportsImageGen: true,
})
).toBe(true);
expect(
isStillImageGenerationModelDescriptor({
providerType: "ruxa-video",
modelId: "kling-video",
supportsImageGen: true,
})
).toBe(false);
});
test("prevents reference-incompatible models from being selected in Style Pro", () => {
const availability = getStyleProModelAvailability(
styleProEntry({ supportsVision: false })
);
expect(availability.selectable).toBe(false);
expect(availability.availabilityLabel).toBe("仅文生图");
});
test("temporarily disables degraded models in Style Pro", () => {
const availability = getStyleProModelAvailability(
styleProEntry({
healthStatus: "degraded",
healthObservationStartedAt: new Date(),
})
);
expect(availability.selectable).toBe(false);
expect(availability.availabilityLabel).toBe("暂不可用");
});
test("keeps known reference-capable BFL models selectable", () => {
const availability = getStyleProModelAvailability(
styleProEntry({
providerType: "bfl-image",
modelId: "flux-2-klein-4b",
supportsVision: false,
})
);
expect(availability.selectable).toBe(true);
});
});