完成图片编辑器宣发素材生成

新增宣发素材入口、工作流模型、画布生成卡片和参考图选择能力。

接入宣发素材真实生图请求,隐藏 Prompt 摘要和约束预览,并将约束作为内部 Prompt 使用。

支持游戏首图、详情五图、运营海报尺寸,其中详情五图一次生成五张 720x1280 竖图。

后端仅对 publication-material 生图扣 5 泥点,并沿用现有失败退款逻辑。

补充前后端测试和宣发素材设计文档。
This commit is contained in:
Codex
2026-06-18 00:05:25 +08:00
parent 7dec8b7a66
commit 0ebf6242bb
34 changed files with 1883 additions and 86 deletions
@@ -5,6 +5,7 @@ import type {
CanvasViewport,
CharacterAnimationPanelState,
GenerateDialogState,
PublicationMaterialsWorkflowId,
QuickEditPanelState,
SpecFormValues,
SpecGenerationType,
@@ -16,11 +17,14 @@ import {
createCanvasLayerReference,
DEFAULT_ICON_DESCRIPTIONS,
DEFAULT_IMAGE_MODEL,
DEFAULT_PUBLICATION_GAME_INFO,
DEFAULT_SPEC_FORM_VALUES,
EDITOR_IMAGE_DIMENSION_OPTIONS,
ICON_DESCRIPTION_LIMIT,
ICON_FRAME_DISPLAY_SIZE,
ICON_FRAME_ORIGINAL_SIZE,
PUBLICATION_FRAME_DISPLAY_SIZE,
PUBLICATION_FRAME_ORIGINAL_SIZE,
SPEC_FRAME_DISPLAY_SIZE,
SPEC_FRAME_ORIGINAL_SIZE,
} from './ImageCanvasGenerationModel';
@@ -180,6 +184,37 @@ export function createIconGenerationDialogDraft({
};
}
export function createPublicationGenerationDialogDraft({
canvasSize,
viewport,
workflowId,
}: {
canvasSize: CanvasSize;
viewport: CanvasViewport;
workflowId: PublicationMaterialsWorkflowId;
}): Omit<CanvasGenerationDialogState, 'id'> {
const worldCenter = getViewportWorldCenter({ canvasSize, viewport });
const frameDisplaySize = PUBLICATION_FRAME_DISPLAY_SIZE[workflowId];
const frameOriginalSize = PUBLICATION_FRAME_ORIGINAL_SIZE[workflowId];
return {
mode: 'publication',
prompt: '',
status: 'idle',
composerOpen: true,
publicationWorkflowId: workflowId,
publicationGameInfo: { ...DEFAULT_PUBLICATION_GAME_INFO },
publicationReferences: [],
placeholder: {
x: worldCenter.x - frameDisplaySize.width / 2,
y: worldCenter.y - frameDisplaySize.height / 2,
width: frameDisplaySize.width,
height: frameDisplaySize.height,
originalWidth: frameOriginalSize.width,
originalHeight: frameOriginalSize.height,
},
};
}
export function createEditDialogDraft(
sourceLayer: CanvasLayer,
): GenerateDialogState {
@@ -255,6 +290,22 @@ export function appendCharacterReference(
: dialog;
}
export function appendPublicationReference(
dialog: GenerateDialogState | null,
layer: CanvasLayer,
): GenerateDialogState | null {
return dialog?.mode === 'publication'
? {
...resetFailedGenerationDialog(dialog),
publicationReferences: [
...(dialog.publicationReferences ?? []),
createCanvasLayerReference(layer),
],
composerOpen: true,
}
: dialog;
}
export function assignIconSpecReference(
dialog: GenerateDialogState | null,
layer: CanvasLayer,
@@ -348,7 +399,8 @@ export function hideGeneratedLayerComposerAfterBlur(
return (dialog?.mode === 'generate' ||
dialog?.mode === 'spec' ||
dialog?.mode === 'character' ||
dialog?.mode === 'icon') &&
dialog?.mode === 'icon' ||
dialog?.mode === 'publication') &&
dialog.status !== 'generating'
? {
...dialog,
@@ -360,7 +412,7 @@ export function hideGeneratedLayerComposerAfterBlur(
export function closeGenerateComposerDialog(
dialog: GenerateDialogState | null,
): GenerateDialogState | null {
return dialog?.mode === 'generate'
return dialog?.mode === 'generate' || dialog?.mode === 'publication'
? {
...dialog,
composerOpen: false,