接入画板生成视频功能
新增画板底部生成视频入口、Lovart 风格面板、视频图层渲染与元数据展示。 接入 /api/editor/videos/generations 契约与后端 Ark/VectorEngine 视频任务链路。 统一编辑器生成类泥点配置,并补充 UI 设计图、参考图与生成面板结构测试。 更新编辑器技术方案、生成类面板方案和 Hermes 共享决策/踩坑记录。
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
generateEditorCharacterAnimation,
|
||||
generateEditorIconSpritesheet,
|
||||
generateEditorImage,
|
||||
generateEditorVideo,
|
||||
listEditorProjects,
|
||||
loadEditorAssetLibrary,
|
||||
loadEditorProject,
|
||||
@@ -760,6 +761,58 @@ describe('editorProjectClient', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('generates editor videos through the backend BFF', async () => {
|
||||
requestJsonMock.mockResolvedValueOnce({
|
||||
videoSrc: '/generated-editor-videos/video-task-1/preview.mp4',
|
||||
width: 1280,
|
||||
height: 720,
|
||||
sourceType: 'generated',
|
||||
prompt: '让角色向镜头挥手',
|
||||
actualPrompt: '让角色向镜头挥手',
|
||||
model: 'kling3.0-omni',
|
||||
provider: 'VectorEngine',
|
||||
taskId: 'video-task-1',
|
||||
durationSeconds: 5,
|
||||
resolution: '480p',
|
||||
priceMudPoints: 50,
|
||||
});
|
||||
|
||||
const result = await generateEditorVideo({
|
||||
prompt: '让角色向镜头挥手',
|
||||
model: 'kling3.0-omni',
|
||||
aspectRatio: '16:9',
|
||||
durationSeconds: 5,
|
||||
resolution: '480p',
|
||||
mode: 'std',
|
||||
sound: 'off',
|
||||
priceMudPoints: 50,
|
||||
});
|
||||
|
||||
expect(result.taskId).toBe('video-task-1');
|
||||
expect(requestJsonMock).toHaveBeenCalledWith(
|
||||
'/api/editor/videos/generations',
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
prompt: '让角色向镜头挥手',
|
||||
model: 'kling3.0-omni',
|
||||
aspectRatio: '16:9',
|
||||
durationSeconds: 5,
|
||||
resolution: '480p',
|
||||
mode: 'std',
|
||||
sound: 'off',
|
||||
priceMudPoints: 50,
|
||||
}),
|
||||
}),
|
||||
'生成视频失败',
|
||||
expect.objectContaining({
|
||||
timeoutMs: 1_200_000,
|
||||
retry: { maxRetries: 0 },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('edits editor images through the backend BFF', async () => {
|
||||
requestJsonMock.mockResolvedValueOnce({
|
||||
imageSrc: 'data:image/png;base64,edited',
|
||||
|
||||
@@ -8,6 +8,7 @@ const EDITOR_ICON_SPRITESHEET_GENERATION_API =
|
||||
'/api/editor/icon-spritesheets/generations';
|
||||
const EDITOR_CHARACTER_ANIMATION_GENERATION_API =
|
||||
'/api/editor/character-animations/generations';
|
||||
const EDITOR_VIDEO_GENERATION_API = '/api/editor/videos/generations';
|
||||
const EDITOR_IMAGE_MODEL_NANOBANANA2 = 'gemini-3.1-flash-image-preview';
|
||||
const DEFAULT_PROJECT_TITLE = '未命名画布';
|
||||
|
||||
@@ -83,7 +84,7 @@ export type EditorAssetLibrarySnapshot = {
|
||||
export type EditorImageGenerationInput = {
|
||||
prompt: string;
|
||||
size?: string;
|
||||
kind?: 'spec' | 'character' | 'quick-edit';
|
||||
kind?: 'spec' | 'character' | 'quick-edit' | 'ui-design';
|
||||
model?: string;
|
||||
aspectRatio?: string;
|
||||
imageSize?: string;
|
||||
@@ -185,6 +186,38 @@ export type EditorCharacterAnimationGenerationResult = {
|
||||
priceMudPoints: number;
|
||||
};
|
||||
|
||||
export type EditorVideoModel =
|
||||
| 'seedance2.0'
|
||||
| 'seedance2.0-fast'
|
||||
| 'kling3.0'
|
||||
| 'kling3.0-omni'
|
||||
| 'veo3.1'
|
||||
| 'veo3.1-fast';
|
||||
|
||||
export type EditorVideoGenerationInput = {
|
||||
prompt: string;
|
||||
model: EditorVideoModel;
|
||||
aspectRatio: '16:9';
|
||||
durationSeconds: 4 | 5;
|
||||
resolution: '480p' | '720p';
|
||||
mode: 'std';
|
||||
sound: 'off';
|
||||
priceMudPoints: number;
|
||||
};
|
||||
|
||||
export type EditorVideoGenerationResult = {
|
||||
videoSrc: string;
|
||||
width: number;
|
||||
height: number;
|
||||
sourceType: 'generated';
|
||||
prompt: string;
|
||||
actualPrompt?: string | null;
|
||||
model: string;
|
||||
provider: string;
|
||||
taskId: string;
|
||||
priceMudPoints?: number;
|
||||
};
|
||||
|
||||
export type EditorProjectSnapshot = {
|
||||
projectId: string;
|
||||
title: string;
|
||||
@@ -281,6 +314,7 @@ type EditorAssetResponse = {
|
||||
type EditorImageGenerationResponse = EditorImageGenerationResult;
|
||||
type EditorIconSpritesheetGenerationResponse =
|
||||
EditorIconSpritesheetGenerationResult;
|
||||
type EditorVideoGenerationResponse = EditorVideoGenerationResult;
|
||||
|
||||
function jsonRequest(method: 'POST' | 'PATCH', body: Record<string, unknown>) {
|
||||
return {
|
||||
@@ -534,3 +568,17 @@ export async function generateEditorCharacterAnimation(
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export async function generateEditorVideo(input: EditorVideoGenerationInput) {
|
||||
return requestJson<EditorVideoGenerationResponse>(
|
||||
EDITOR_VIDEO_GENERATION_API,
|
||||
jsonRequest('POST', input),
|
||||
'生成视频失败',
|
||||
{
|
||||
timeoutMs: 1_200_000,
|
||||
retry: {
|
||||
maxRetries: 0,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user