ai-chatbot/tests/routes/video-subject-library.test.ts

173 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { expect, test } from "@playwright/test";
import { defaultVideoCanvasFunctionConfig } from "../../lib/video-canvas/config";
import {
addVideoCanvasAttachedSubject,
buildVideoCanvasSubjectProviderReferences,
composeVideoCanvasSubjectPrompt,
getVideoCanvasAttachedSubjects,
normalizeGeneratedSubjectDescription,
removeVideoCanvasAttachedSubject,
resolveVideoCanvasSubjectCategory,
supportsVideoCanvasSubjectUsage,
toVideoCanvasAttachedSubject,
validateVideoCanvasSubjectDraft,
} from "../../lib/video-canvas/subjects";
const config = defaultVideoCanvasFunctionConfig.subjectLibrary;
test.describe("video canvas subject library", () => {
test("validates the exact image and video creation ranges", () => {
expect(
validateVideoCanvasSubjectDraft(
{
assetCount: 1,
category: "人物",
description: "古风女性人物,黑色长发,绿色衣裙。",
mediaMode: "images",
name: "古风女主",
voiceId: "none",
},
config,
),
).toBe("请至少添加2张角色图片");
expect(
validateVideoCanvasSubjectDraft(
{
assetCount: 2,
category: "人物",
description: "古风女性人物,黑色长发,绿色衣裙。",
mediaMode: "images",
name: "古风女主",
voiceId: "gentle-female",
},
config,
),
).toBeNull();
expect(
validateVideoCanvasSubjectDraft(
{
assetCount: 1,
category: "人物",
description: "古风女性人物,黑色长发,绿色衣裙。",
durationSeconds: 8.1,
mediaMode: "video",
name: "古风女主",
voiceId: "original-video",
},
config,
),
).toBe("角色视频时长需为3-8秒");
});
test("normalizes labels and smart descriptions", () => {
expect(resolveVideoCanvasSubjectCategory("场景", config)).toBe("场景");
expect(resolveVideoCanvasSubjectCategory("unknown", config)).toBe("其他");
expect(resolveVideoCanvasSubjectCategory("", config)).toBe("其他");
expect(
normalizeGeneratedSubjectDescription(
"```text\n主体描述:一位黑色长发、绿色衣裙的古风女性人物。\n```",
100,
),
).toBe("一位黑色长发、绿色衣裙的古风女性人物。");
});
test("accepts uploaded custom voice ids", () => {
expect(
validateVideoCanvasSubjectDraft(
{
assetCount: 2,
category: "人物",
description: "古风女性人物,黑色长发,绿色衣裙。",
mediaMode: "images",
name: "古风女主",
voiceId: "custom:25c7404b-80ae-4f11-a237-a6ec35c4ed6a",
},
config,
),
).toBeNull();
});
test("stores subject references without changing unrelated node draft values", () => {
const subject = toVideoCanvasAttachedSubject({
description: { description: "成年古装男性,黑发束冠,金黄色龙纹长袍。" },
displayName: "古装男性",
id: "subject-1",
metadata: {
category: "人物",
mediaMode: "images",
mediaUrls: ["https://example.com/front.png", "https://example.com/back.png"],
voiceId: "none",
voiceName: "无配音",
},
thumbnailUrl: "https://example.com/front.png",
});
expect(subject).not.toBeNull();
const attached = addVideoCanvasAttachedSubject(
{ params: { model: "kling-o3", prompt: "人物转身。" }, untouched: true },
subject!,
4,
);
expect(getVideoCanvasAttachedSubjects(attached)).toEqual([subject]);
expect(attached).toMatchObject({
params: { model: "kling-o3", prompt: "人物转身。", subjects: [subject] },
untouched: true,
videoSubjects: [subject],
});
const removed = removeVideoCanvasAttachedSubject(attached, "subject-1");
expect(getVideoCanvasAttachedSubjects(removed)).toEqual([]);
expect(removed).toMatchObject({
params: { model: "kling-o3", prompt: "人物转身。" },
untouched: true,
});
});
test("maps subject data to hidden prompt and structured provider references", () => {
const subject = toVideoCanvasAttachedSubject({
description: { description: "白色短发,黑色机能服。" },
displayName: "测试主体",
id: "subject-2",
metadata: {
category: "人物",
mediaMode: "images",
mediaUrls: ["https://example.com/a.png", "https://example.com/b.png"],
voiceId: "broadcast-male",
voiceName: "播报男声",
},
originalUrl: "https://example.com/a.png",
})!;
const prompt = composeVideoCanvasSubjectPrompt(
"主体走向镜头。",
[subject],
"主体{{index}}「{{name}}」({{category}}):{{description}},音色{{voiceName}}。",
);
expect(prompt).toBe(
"主体走向镜头。 主体1「测试主体」(人物):白色短发,黑色机能服。,音色播报男声。",
);
expect(buildVideoCanvasSubjectProviderReferences([subject])).toEqual([
{
category: "人物",
description: "白色短发,黑色机能服。",
name: "测试主体",
referenceImages: ["https://example.com/a.png", "https://example.com/b.png"],
referenceVideo: undefined,
subjectId: "subject-2",
voiceId: "broadcast-male",
},
]);
});
test("shows subject usage only for administrator-configured video models", () => {
expect(supportsVideoCanvasSubjectUsage(config, "Kling O3")).toBe(true);
expect(supportsVideoCanvasSubjectUsage(config, "Seedance 2.0 VIP")).toBe(false);
expect(
supportsVideoCanvasSubjectUsage(
{ ...config, videoUsage: { ...config.videoUsage, enabled: false } },
"Kling O3",
),
).toBe(false);
});
});