严格区分Seedance视频模型

将画板生成视频默认模型调整为 seedance2.0-fast

为 seedance2.0 与 seedance2.0-fast 分别映射独立上游模型

固定角色动画使用 seedance2.0-fast 并更新前后端契约测试

同步更新编辑器生成面板和项目记忆文档
This commit is contained in:
2026-06-18 14:40:39 +08:00
parent 7b277480f0
commit 38cbb85d48
19 changed files with 163 additions and 41 deletions
@@ -199,7 +199,7 @@ describe('ImageCanvasCharacterAnimationPanelView', () => {
it('renders completed frame count and failed error state', () => {
const result = {
taskId: 'task-a',
model: 'seedance2.0' as const,
model: 'seedance2.0-fast' as const,
prompt: '行走动作',
previewVideoPath: '/preview.mp4',
frames: [],
@@ -1935,7 +1935,7 @@ describe('ImageCanvasEditorView generation integration', () => {
});
generateEditorCharacterAnimationMock.mockResolvedValueOnce({
taskId: 'character-animation-task-1',
model: 'seedance2.0',
model: 'seedance2.0-fast',
prompt: '生成游戏角色动画\n动作描述:\n待机',
previewVideoPath: '/generated-character-drafts/editor/preview.mp4',
frames: Array.from({ length: 48 }, (_, index) => ({
@@ -2049,7 +2049,7 @@ describe('ImageCanvasEditorView generation integration', () => {
frameCount: 48,
durationSeconds: 6,
priceMudPoints: 120,
model: 'seedance2.0',
model: 'seedance2.0-fast',
}),
);
expect(
@@ -261,7 +261,7 @@ describe('ImageCanvasGenerationComposerView', () => {
status: 'idle',
composerOpen: true,
generationReferences: [],
videoModel: 'seedance2.0',
videoModel: 'seedance2.0-fast',
videoAspectRatio: '16:9',
videoDurationSeconds: 4,
videoResolution: '480p',
@@ -299,7 +299,7 @@ describe('ImageCanvasGenerationComposerView', () => {
status: 'idle',
composerOpen: true,
generationReferences: [],
videoModel: 'seedance2.0',
videoModel: 'seedance2.0-fast',
videoAspectRatio: '16:9',
videoDurationSeconds: 4,
videoResolution: '480p',
@@ -326,7 +326,7 @@ describe('ImageCanvasGenerationComposerView', () => {
within(panel).getByRole('button', { name: '视频参数 16:9 · 4秒 · 480p' }),
).toBeTruthy();
expect(
within(panel).getByRole('button', { name: '模型 Seedance 2.0' }),
within(panel).getByRole('button', { name: '模型 Seedance 2.0 Fast' }),
).toBeTruthy();
expect(within(panel).getByRole('button', { name: '生成视频' }).textContent).toBe(
'生成40泥点',
@@ -351,7 +351,7 @@ describe('ImageCanvasGenerationComposerView', () => {
'生成100泥点',
);
fireEvent.click(screen.getByRole('button', { name: '模型 Seedance 2.0' }));
fireEvent.click(screen.getByRole('button', { name: '模型 Seedance 2.0 Fast' }));
const modelPanel = screen.getByRole('menu', { name: '视频模型选项' });
expect(within(modelPanel).queryByRole('button', { name: /Veo/i })).toBeNull();
fireEvent.click(within(modelPanel).getByRole('button', { name: 'Kling 3.0' }));
@@ -146,7 +146,7 @@ describe('ImageCanvasGenerationDialogModel', () => {
status: 'idle',
composerOpen: true,
generationReferences: [],
videoModel: 'seedance2.0',
videoModel: 'seedance2.0-fast',
videoAspectRatio: '16:9',
videoResolution: '480p',
videoDurationSeconds: 4,
@@ -17,6 +17,7 @@ import {
DEFAULT_ICON_DESCRIPTIONS,
DEFAULT_IMAGE_MODEL,
DEFAULT_SPEC_FORM_VALUES,
DEFAULT_VIDEO_MODEL,
EDITOR_IMAGE_DIMENSION_OPTIONS,
EDITOR_VIDEO_MODEL_OPTIONS,
ICON_DESCRIPTION_LIMIT,
@@ -203,7 +204,7 @@ export function createVideoGenerationDialogDraft({
status: 'idle',
composerOpen: true,
generationReferences: [],
videoModel: EDITOR_VIDEO_MODEL_OPTIONS[0].value,
videoModel: DEFAULT_VIDEO_MODEL,
videoAspectRatio: '16:9',
videoResolution: '480p',
videoDurationSeconds: 4,
@@ -78,7 +78,10 @@ export const EDITOR_IMAGE_DIMENSION_OPTIONS = {
imageSizes: ['1K', '2K'],
},
} as const;
export const CHARACTER_ANIMATION_MODEL = 'seedance2.0';
export const VIDEO_MODEL_SEEDANCE_2 = 'seedance2.0';
export const VIDEO_MODEL_SEEDANCE_2_FAST = 'seedance2.0-fast';
export const DEFAULT_VIDEO_MODEL = VIDEO_MODEL_SEEDANCE_2_FAST;
export const CHARACTER_ANIMATION_MODEL = VIDEO_MODEL_SEEDANCE_2_FAST;
export const CHARACTER_ANIMATION_ACTION_PROMPTS = [
{ label: '待机', text: '待机动作,轻微呼吸起伏。' },
{ label: '行走', text: '循环行走动作,步伐稳定。' },
@@ -107,8 +110,8 @@ export const CHARACTER_ANIMATION_DURATION_OPTIONS = [
export const VIDEO_FRAME_ORIGINAL_SIZE = { width: 1280, height: 720 };
export const VIDEO_FRAME_DISPLAY_SIZE = { width: 560, height: 315 };
export const EDITOR_VIDEO_MODEL_OPTIONS = [
{ label: 'Seedance 2.0', value: 'seedance2.0' },
{ label: 'Seedance 2.0 Fast', value: 'seedance2.0-fast' },
{ label: 'Seedance 2.0 Fast', value: VIDEO_MODEL_SEEDANCE_2_FAST },
{ label: 'Seedance 2.0', value: VIDEO_MODEL_SEEDANCE_2 },
{ label: 'Kling 3.0', value: 'kling3.0' },
{ label: 'Kling 3.0 Omni', value: 'kling3.0-omni' },
] as const;
@@ -37,11 +37,14 @@ describe('ImageCanvasGenerationSubmissionModel', () => {
nextGeneratedIndex: 3,
});
expect(plan).toEqual({
expect(plan).toMatchObject({
kind: 'image',
normalizedPrompt: '一张发光主视觉',
input: {
prompt: '一张发光主视觉',
model: 'gemini-3.1-flash-image-preview',
aspectRatio: '1:1',
imageSize: '1K',
},
result: {
generationInputs: {
@@ -49,6 +52,7 @@ describe('ImageCanvasGenerationSubmissionModel', () => {
references: [],
},
},
rememberImageModel: 'gemini-3.1-flash-image-preview',
});
});
@@ -326,7 +330,64 @@ describe('ImageCanvasGenerationSubmissionModel', () => {
frameCount: 48,
durationSeconds: 6,
priceMudPoints: 120,
model: 'seedance2.0-fast',
},
});
});
it('builds video generation plans with seedance fast as the fallback model', () => {
const plan = buildImageGenerationSubmissionPlan({
dialog: {
mode: 'video',
prompt: ' 角色绕场一周 ',
status: 'idle',
generationReferences: [],
videoResolution: '480p',
videoDurationSeconds: 4,
},
layers: [],
nextGeneratedIndex: 3,
});
expect(plan).toMatchObject({
kind: 'video',
normalizedPrompt: '角色绕场一周',
input: {
model: 'seedance2.0-fast',
priceMudPoints: 40,
},
result: {
title: '生成视频 3',
},
});
});
it('builds video generation plans with explicit seedance standard model', () => {
const plan = buildImageGenerationSubmissionPlan({
dialog: {
mode: 'video',
prompt: ' 生成电影感开场动画 ',
status: 'idle',
videoModel: 'seedance2.0',
videoResolution: '720p',
videoDurationSeconds: 5,
},
layers: [],
nextGeneratedIndex: 7,
});
expect(plan).toMatchObject({
kind: 'video',
normalizedPrompt: '生成电影感开场动画',
input: {
prompt: '生成电影感开场动画',
model: 'seedance2.0',
resolution: '720p',
durationSeconds: 5,
priceMudPoints: 100,
},
result: {
title: '生成视频 7',
},
});
});
@@ -15,6 +15,7 @@ import {
DEFAULT_IMAGE_MODEL,
DEFAULT_ICON_DESCRIPTIONS,
DEFAULT_SPEC_FORM_VALUES,
DEFAULT_VIDEO_MODEL,
SPEC_GENERATION_SIZE,
SPEC_TYPE_LABEL,
buildIconGenerationInputs,
@@ -200,7 +201,7 @@ export function buildImageGenerationSubmissionPlan({
if (dialog.mode === 'video') {
const resolution = dialog.videoResolution ?? '480p';
const durationSeconds = dialog.videoDurationSeconds ?? 4;
const model = dialog.videoModel ?? 'seedance2.0';
const model = dialog.videoModel ?? DEFAULT_VIDEO_MODEL;
return {
kind: 'video',
normalizedPrompt,
@@ -589,7 +589,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
sourceLayerId: 'character-layer',
sourceImageSrc: 'generated/character.png',
promptText: '跑步',
model: 'seedance2.0',
model: 'seedance2.0-fast',
}),
);
});
@@ -702,7 +702,7 @@ describe('editorProjectClient', () => {
it('generates editor character animations through the backend BFF', async () => {
requestJsonMock.mockResolvedValueOnce({
taskId: 'character-animation-1',
model: 'seedance2.0',
model: 'seedance2.0-fast',
prompt: '生成游戏角色动画\n动作描述:\n待机',
previewVideoPath: '/generated-character-drafts/editor/preview.mp4',
frames: [
@@ -730,7 +730,7 @@ describe('editorProjectClient', () => {
frameCount: 32,
durationSeconds: 4,
priceMudPoints: 40,
model: 'seedance2.0',
model: 'seedance2.0-fast',
});
expect(result.taskId).toBe('character-animation-1');
@@ -750,7 +750,7 @@ describe('editorProjectClient', () => {
frameCount: 32,
durationSeconds: 4,
priceMudPoints: 40,
model: 'seedance2.0',
model: 'seedance2.0-fast',
}),
}),
'生成角色动画失败',
@@ -164,7 +164,7 @@ export type EditorCharacterAnimationGenerationInput = {
frameCount: EditorCharacterAnimationFrameCount;
durationSeconds: EditorCharacterAnimationDurationSeconds;
priceMudPoints: number;
model: 'seedance2.0';
model: 'seedance2.0-fast';
};
export type EditorCharacterAnimationFrameResult = {
@@ -176,7 +176,7 @@ export type EditorCharacterAnimationFrameResult = {
export type EditorCharacterAnimationGenerationResult = {
taskId: string;
model: 'seedance2.0';
model: 'seedance2.0-fast';
prompt: string;
previewVideoPath: string;
frames: EditorCharacterAnimationFrameResult[];