限制序列帧去背景仅用于视频转换

后端仅接受 character-animation.convert 结果执行序列帧去背景

前端工具栏与工作流同步收紧视频转换门禁

更新相关测试与Spine序列帧技术方案
This commit is contained in:
2026-08-15 15:35:27 +08:00
parent b5dc99e067
commit f65a813768
7 changed files with 57 additions and 73 deletions
@@ -70,15 +70,13 @@ import {
} from './ImageCanvasGenerationModel';
describe('ImageCanvasGenerationModel', () => {
it('allows sequence background removal only for green generated animations', () => {
it('allows sequence background removal only for direct video conversions', () => {
const layer = {
assetKind: 'character-animation',
generationInputs: {
version: 2 as const,
action: 'character-animation.generate' as const,
fields: [
{ id: 'backgroundColor', title: '背景颜色', value: 'green' as const },
],
action: 'character-animation.convert' as const,
fields: [],
references: [],
},
} as unknown as CanvasLayer;
@@ -88,7 +86,7 @@ describe('ImageCanvasGenerationModel', () => {
...layer,
generationInputs: {
...layer.generationInputs!,
action: 'character-animation.convert',
action: 'character-animation.generate',
},
}),
).toBe(false);
@@ -97,7 +95,7 @@ describe('ImageCanvasGenerationModel', () => {
...layer,
generationInputs: {
...layer.generationInputs!,
fields: [{ id: 'backgroundColor', title: '背景颜色', value: 'blue' }],
action: 'character-animation.remove-background',
},
}),
).toBe(false);
@@ -1041,15 +1041,10 @@ export function buildCharacterAnimationGenerationInputs(
}
export function canRemoveCharacterAnimationBackground(layer: CanvasLayer) {
if (
layer.assetKind !== 'character-animation' ||
layer.generationInputs?.version !== 2 ||
layer.generationInputs.action !== 'character-animation.generate'
) {
return false;
}
return layer.generationInputs.fields.some(
(field) => field.id === 'backgroundColor' && field.value === 'green',
return (
layer.assetKind === 'character-animation' &&
layer.generationInputs?.version === 2 &&
layer.generationInputs.action === 'character-animation.convert'
);
}
@@ -459,11 +459,8 @@ describe('ImageCanvasSelectedLayerToolbarView', () => {
assetKind: 'character-animation',
generationInputs: {
version: 2,
action: 'character-animation.generate',
fields: [
{ id: 'prompt', title: '动作描述', value: '挥手' },
{ id: 'backgroundColor', title: '背景颜色', value: 'green' },
],
action: 'character-animation.convert',
fields: [],
references: [],
},
}),
@@ -492,21 +489,18 @@ describe('ImageCanvasSelectedLayerToolbarView', () => {
);
});
it('hides sequence background removal unless the authoritative background is green', () => {
const whiteLayer = createLayer({
it('shows sequence background removal only for direct video conversions', () => {
const generatedLayer = createLayer({
mediaType: 'image-sequence',
assetKind: 'character-animation',
generationInputs: {
version: 2,
action: 'character-animation.generate',
fields: [
{ id: 'prompt', title: '动作描述', value: '挥手' },
{ id: 'backgroundColor', title: '背景颜色', value: 'white' },
],
fields: [{ id: 'prompt', title: '动作描述', value: '挥手' }],
references: [],
},
});
renderSelectedToolbar({ selectedLayer: whiteLayer });
renderSelectedToolbar({ selectedLayer: generatedLayer });
expect(screen.queryByRole('button', { name: '去背景' })).toBeNull();
@@ -517,13 +511,13 @@ describe('ImageCanvasSelectedLayerToolbarView', () => {
generationInputs: {
version: 2,
action: 'character-animation.convert',
fields: [{ id: 'backgroundColor', title: '背景颜色', value: 'green' }],
fields: [],
references: [],
},
});
renderSelectedToolbar({ selectedLayer: convertedLayer });
expect(screen.queryByRole('button', { name: '去背景' })).toBeNull();
expect(screen.getByRole('button', { name: '去背景' })).toBeTruthy();
});
it('disables frame splitting while a character animation resource is pending registration', () => {
@@ -3067,6 +3067,12 @@ describe('useImageCanvasGenerationWorkflow', () => {
title: '勇者奔跑',
assetKind: 'character-animation',
mediaType: 'image-sequence',
generationInputs: {
version: 2,
action: 'character-animation.convert',
fields: [],
references: [],
},
}),
]}
/>,
@@ -96,6 +96,7 @@ import {
appendLimitedImageReferences,
buildDeterministicGenerationInputs,
calculateCharacterAnimationPrice,
canRemoveCharacterAnimationBackground,
canSplitCharacterAnimationFrames,
CANVAS_GENERATION_PARAMETER_FALLBACK_WARNING,
CHARACTER_ANIMATION_DURATION_OPTIONS,
@@ -3677,6 +3678,7 @@ export function useImageCanvasGenerationWorkflow({
const removeSelectedCharacterAnimationBackground = useCallback(
async (sourceLayer: CanvasLayer) => {
if (
!canRemoveCharacterAnimationBackground(sourceLayer) ||
!canSplitCharacterAnimationFrames(sourceLayer) ||
!projectId ||
removingBackgroundCharacterAnimationLayerIdsRef.current.has(