拆分编辑器高级生成提交模型

抽出图标素材生成校验和请求参数组装

抽出角色动画生成请求参数组装

补充高级生成提交模型单测

更新 TRACKING.md 记录第三十八阶段验证
This commit is contained in:
2026-06-17 18:27:33 +08:00
parent 6e8089c297
commit bf24d259a7
4 changed files with 242 additions and 54 deletions

View File

@@ -24,7 +24,6 @@ import {
} from './ImageCanvasGenerationLayerModel';
import {
CHARACTER_ANIMATION_DURATION_OPTIONS,
CHARACTER_ANIMATION_MODEL,
CHARACTER_FRAME_DISPLAY_SIZE,
CHARACTER_FRAME_ORIGINAL_SIZE,
DEFAULT_ICON_DESCRIPTIONS,
@@ -37,16 +36,18 @@ import {
SPEC_FRAME_DISPLAY_SIZE,
SPEC_FRAME_ORIGINAL_SIZE,
buildEditGenerationInputs,
buildIconGenerationInputs,
buildQuickEditModelOptions,
buildQuickEditSizeOptions,
calculateCharacterAnimationPrice,
createCanvasLayerReference,
isCanvasGenerationDialog,
resolveCharacterAnimationSourceImageSrc,
resolveImageGenerationErrorMessage,
} from './ImageCanvasGenerationModel';
import { buildImageGenerationSubmissionPlan } from './ImageCanvasGenerationSubmissionModel';
import {
buildCharacterAnimationSubmissionPlan,
buildIconSpritesheetGenerationSubmissionPlan,
buildImageGenerationSubmissionPlan,
} from './ImageCanvasGenerationSubmissionModel';
import { formatImageSizeValue } from './ImageCanvasEditorModel';
import type {
CanvasGenerationDialogState,
@@ -657,29 +658,15 @@ export function useImageCanvasGenerationWorkflow({
) => {
updateCanvasGenerationDialogById(nextDialog.id, () => nextDialog);
};
const iconDescriptions = (
dialog.iconDescriptions ?? DEFAULT_ICON_DESCRIPTIONS
)
.map((description) => description.trim())
.filter(Boolean);
if (!dialog.iconSpecReference) {
const submissionPlan =
buildIconSpritesheetGenerationSubmissionPlan(dialog);
if (!submissionPlan.ok) {
if (canvasDialog) {
setSubmittingIconDialog({
...canvasDialog,
status: 'failed',
composerOpen: true,
errorMessage: '请选择图标素材规范',
});
}
return;
}
if (!iconDescriptions.length) {
if (canvasDialog) {
setSubmittingIconDialog({
...canvasDialog,
status: 'failed',
composerOpen: true,
errorMessage: '请填写素材描述',
errorMessage: submissionPlan.errorMessage,
});
}
return;
@@ -691,32 +678,28 @@ export function useImageCanvasGenerationWorkflow({
setSubmittingIconDialog({
...canvasDialog,
iconDescriptions,
iconDescriptions: submissionPlan.iconDescriptions,
status: 'generating',
composerOpen: false,
errorMessage: undefined,
});
try {
const generated = await generateEditorIconSpritesheet({
referenceImageSrc: dialog.iconSpecReference.src,
iconDescriptions,
model: dialog.imageModel ?? DEFAULT_IMAGE_MODEL,
aspectRatio: dialog.aspectRatio ?? '1:1',
imageSize: dialog.imageSize ?? '1K',
});
setLastImageModel(dialog.imageModel ?? DEFAULT_IMAGE_MODEL);
const generated = await generateEditorIconSpritesheet(
submissionPlan.input,
);
setLastImageModel(submissionPlan.rememberImageModel);
addIconSpritesheetResultLayers(
generated,
generated.iconImageSrcs,
buildIconGenerationInputs(iconDescriptions, dialog.iconSpecReference),
submissionPlan.generationInputs,
getGeneratingDialogPlaceholder(dialog),
canvasDialog.id,
);
} catch (error) {
setSubmittingIconDialog({
...canvasDialog,
iconDescriptions,
iconDescriptions: submissionPlan.iconDescriptions,
status: 'failed',
composerOpen: true,
errorMessage: resolveImageGenerationErrorMessage(error),
@@ -913,10 +896,13 @@ export function useImageCanvasGenerationWorkflow({
if (!characterAnimationPanel || !characterAnimationSourceLayer) {
return;
}
const promptText = characterAnimationPanel.promptText.trim();
const submissionPlan = buildCharacterAnimationSubmissionPlan({
panel: characterAnimationPanel,
sourceLayer: characterAnimationSourceLayer,
});
const nextPanel = {
...characterAnimationPanel,
promptText,
promptText: submissionPlan.promptText,
status: 'generating' as const,
errorMessage: undefined,
result: undefined,
@@ -924,24 +910,9 @@ export function useImageCanvasGenerationWorkflow({
setCharacterAnimationPanel(nextPanel);
try {
const result = await generateEditorCharacterAnimation({
sourceLayerId: characterAnimationSourceLayer.id,
sourceImageSrc: resolveCharacterAnimationSourceImageSrc(
characterAnimationSourceLayer,
),
sourceWidth: characterAnimationSourceLayer.originalWidth,
sourceHeight: characterAnimationSourceLayer.originalHeight,
promptText,
resolution: nextPanel.resolution,
ratio: nextPanel.ratio,
frameCount: nextPanel.frameCount,
durationSeconds: nextPanel.durationSeconds,
priceMudPoints: calculateCharacterAnimationPrice(
nextPanel.resolution,
nextPanel.durationSeconds,
),
model: CHARACTER_ANIMATION_MODEL,
});
const result = await generateEditorCharacterAnimation(
submissionPlan.input,
);
setCharacterAnimationPanel((currentPanel) =>
currentPanel
? {