import type { CharacterAnimationGenerationPayload } from '../asset-studio/characterAssetWorkflowPersistence'; import { generateCharacterAnimationDraft } from '../asset-studio/characterAssetWorkflowPersistence'; import type { CustomWorldAiActionConfig, EditableCustomWorldRole, } from './roleAssetStudioModel'; import { roleAssetStudioPublishClient } from './roleAssetStudioPublishClient'; export function useRoleAnimationWorkflow() { const generateAnimationClipForRole = async (params: { actionConfig: CustomWorldAiActionConfig; animationPromptText: string; characterBriefText: string; role: EditableCustomWorldRole; }) => { const { actionConfig, animationPromptText, characterBriefText, role } = params; if (!role.imageSrc || !role.generatedVisualAssetId) { throw new Error('请先生成角色形象,再生成动作。'); } const result = await generateCharacterAnimationDraft({ characterId: role.id, strategy: 'image-to-video', animation: actionConfig.animation, promptText: animationPromptText, characterBriefText, actionTemplateId: actionConfig.templateId, visualSource: role.imageSrc, referenceImageDataUrls: [], referenceVideoDataUrls: [], lastFrameImageDataUrl: role.imageSrc, frameCount: actionConfig.frameCount, fps: actionConfig.fps, durationSeconds: actionConfig.durationSeconds, loop: actionConfig.loop, useChromaKey: true, resolution: '480p', ratio: '1:1', imageSequenceModel: 'wan2.7-image-pro', videoModel: 'doubao-seedance-2-0-fast-260128', referenceVideoModel: 'wan2.7-r2v', motionTransferModel: 'wan2.2-animate-move', } satisfies CharacterAnimationGenerationPayload); if (result.strategy !== 'image-to-video') { throw new Error('当前自定义世界动作工坊只支持图生视频方案。'); } return { fps: actionConfig.fps, loop: actionConfig.loop, frameWidth: 192, frameHeight: 256, frameCount: actionConfig.frameCount, applyChromaKey: true, sampleStartRatio: actionConfig.loop ? 0.12 : 0, sampleEndRatio: actionConfig.loop ? 0.94 : 1, previewVideoPath: result.previewVideoPath, }; }; const publishAnimationClipForRole = async (params: { actionConfig: CustomWorldAiActionConfig; clip: Awaited>; role: EditableCustomWorldRole; }) => { const { actionConfig, clip, role } = params; if (!role.generatedVisualAssetId) { throw new Error('缺少角色主图资产,无法发布动作。'); } return roleAssetStudioPublishClient.publishCharacterAnimationAssets({ characterId: role.id, visualAssetId: role.generatedVisualAssetId, animations: { [actionConfig.animation]: { framesDataUrls: [], fps: clip.fps, loop: clip.loop, frameWidth: clip.frameWidth, frameHeight: clip.frameHeight, frameCount: clip.frameCount, applyChromaKey: clip.applyChromaKey, sampleStartRatio: clip.sampleStartRatio, sampleEndRatio: clip.sampleEndRatio, previewVideoPath: clip.previewVideoPath, }, }, updateCharacterOverride: false, }); }; return { generateAnimationClipForRole, publishAnimationClipForRole, }; }