ai-chatbot/tests/routes/video-model-catalog.test.ts

156 lines
4.5 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { normalizeVideoCanvasFunctionConfig } from "../../lib/video-canvas/config";
import {
defaultVideoCanvasModelCatalog,
estimateVideoCanvasModelCatalogPoints,
getVideoCanvasModelCatalogEntry,
normalizeVideoCanvasModelCatalog,
resolveVideoCanvasCatalogModelRef,
} from "../../lib/video-canvas/video-model-catalog";
test.describe("video canvas model catalog", () => {
test("matches the competitor model order and keeps every observed option selectable", () => {
expect(defaultVideoCanvasModelCatalog).toHaveLength(31);
expect(defaultVideoCanvasModelCatalog.map((entry) => entry.label)).toEqual([
"Seedance 2.0 VIP",
"Seedance 2.0 Fast VIP",
"Seedance 2.0 Mini",
"Happy Horse 1.1",
"Happy Horse 1.0",
"Kling O3",
"Kling 3.0",
"Wan 2.7",
"Kling O1",
"Kling 2.6",
"Kling3.0 动作迁移",
"MJ Video",
"Hailuo 02",
"Vidu Q2",
"Vidu Q2 Pro",
"Vidu Q2 Turbo",
"Kling 2.5",
"Kling 2.1",
"Pixverse V5.5",
"Pixverse V5",
"Kling 3.0 Turbo",
"Wan 2.6",
"Hailuo 2.3 Fast",
"Hailuo 2.3",
"Seedance1.5 Pro",
"Seedance 1.0 Pro",
"Seedance 1.0 Lite",
"Vidu Q3 Pro",
"OmniHuman 1.5",
"Wan 2.2",
"Wan 2.5",
]);
expect(defaultVideoCanvasModelCatalog.every((entry) => entry.enabled)).toBe(true);
});
test("normalizes administrator catalog fields and stable unique ids", () => {
const catalog = normalizeVideoCanvasModelCatalog([
{
id: " Custom Model ",
label: " Custom Video ",
shortLabel: " CV ",
description: " Custom backend alias ",
durationLabel: " 9min ",
icon: "kling",
modelRef: " agnes-video-v2.0 ",
membershipOnly: true,
enabled: true,
discountRate: 4,
pointsPerSecondByResolution: { "720P": 12.345, broken: -1 },
},
{
id: "custom-model",
label: "Second alias",
},
]);
expect(catalog).toHaveLength(2);
expect(catalog[0]).toMatchObject({
discountRate: 1,
id: "custom-model",
label: "Custom Video",
modelRef: "agnes-video-v2.0",
pointsPerSecondByResolution: { "720P": 12.35 },
shortLabel: "CV",
});
expect(catalog[1].id).toBe("custom-model-2");
});
test("delivers the normalized catalog through video canvas configuration", () => {
const config = normalizeVideoCanvasFunctionConfig({
videoModelCatalog: [
{
id: "local-video",
label: "Local Video",
shortLabel: "Local",
description: "Local route",
durationLabel: "1min",
icon: "generic",
modelRef: "agnes-video-v2.0",
},
],
});
expect(config.videoModelCatalog).toHaveLength(1);
expect(config.videoModelCatalog[0]).toMatchObject({
label: "Local Video",
modelRef: "agnes-video-v2.0",
shortLabel: "Local",
});
});
test("resolves display aliases to an explicit backend model fallback", () => {
const fast = getVideoCanvasModelCatalogEntry(defaultVideoCanvasModelCatalog, {
label: "Seedance 2.0 Fast VIP",
});
expect(fast?.shortLabel).toBe("2.0 Fast");
expect(resolveVideoCanvasCatalogModelRef(fast!, "agnes-video-v2.0")).toBe(
"agnes-video-v2.0",
);
expect(
resolveVideoCanvasCatalogModelRef(
{ ...fast!, modelRef: "configured-video-model" },
"agnes-video-v2.0",
),
).toBe("configured-video-model");
});
test("reproduces observed model-specific price changes", () => {
const vip = defaultVideoCanvasModelCatalog[0];
const fast = defaultVideoCanvasModelCatalog[1];
const klingO3 = defaultVideoCanvasModelCatalog.find(
(entry) => entry.label === "Kling O3",
);
expect(
estimateVideoCanvasModelCatalogPoints(vip, {
count: 1,
durationSeconds: 6,
fallbackPointsPerSecond: 27,
resolution: "720P",
}),
).toEqual({ cost: 146, originalCost: 162 });
expect(
estimateVideoCanvasModelCatalogPoints(fast, {
count: 1,
durationSeconds: 6,
fallbackPointsPerSecond: 27,
resolution: "720P",
}),
).toEqual({ cost: 119, originalCost: 132 });
expect(
estimateVideoCanvasModelCatalogPoints(klingO3, {
count: 1,
durationSeconds: 5,
fallbackPointsPerSecond: 27,
resolution: "720P",
}),
).toEqual({ cost: 55, originalCost: undefined });
});
});