1019
src/components/asset-studio/characterAssetWorkflowModel.ts
Normal file
1019
src/components/asset-studio/characterAssetWorkflowModel.ts
Normal file
File diff suppressed because it is too large
Load Diff
218
src/components/asset-studio/characterAssetWorkflowPersistence.ts
Normal file
218
src/components/asset-studio/characterAssetWorkflowPersistence.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
import {
|
||||
ASSET_API_PATHS,
|
||||
postApiJson,
|
||||
} from '../../editor/shared/editorApiClient';
|
||||
import { fetchJson } from '../../editor/shared/jsonClient';
|
||||
|
||||
export const CHARACTER_VISUAL_GENERATE_API_PATH =
|
||||
ASSET_API_PATHS.characterVisualGenerate;
|
||||
export const CHARACTER_VISUAL_PUBLISH_API_PATH =
|
||||
ASSET_API_PATHS.characterVisualPublish;
|
||||
export const CHARACTER_VISUAL_JOB_API_PATH = ASSET_API_PATHS.characterVisualJobs;
|
||||
export const CHARACTER_ANIMATION_GENERATE_API_PATH =
|
||||
ASSET_API_PATHS.characterAnimationGenerate;
|
||||
export const CHARACTER_ANIMATION_PUBLISH_API_PATH =
|
||||
ASSET_API_PATHS.characterAnimationPublish;
|
||||
export const CHARACTER_ANIMATION_JOB_API_PATH =
|
||||
ASSET_API_PATHS.characterAnimationJobs;
|
||||
export const CHARACTER_ANIMATION_IMPORT_VIDEO_API_PATH =
|
||||
ASSET_API_PATHS.characterAnimationImportVideo;
|
||||
export const CHARACTER_ANIMATION_TEMPLATES_API_PATH =
|
||||
ASSET_API_PATHS.characterAnimationTemplates;
|
||||
|
||||
export type CharacterVisualSourceMode =
|
||||
| 'text-to-image'
|
||||
| 'image-to-image'
|
||||
| 'upload';
|
||||
|
||||
export type CharacterAnimationStrategy =
|
||||
| 'image-sequence'
|
||||
| 'image-to-video'
|
||||
| 'motion-transfer'
|
||||
| 'reference-to-video';
|
||||
|
||||
export type CharacterMotionTransferModel =
|
||||
| 'wan2.2-animate-move'
|
||||
| 'wan2.2-animate-mix';
|
||||
|
||||
export type CharacterVisualDraft = {
|
||||
id: string;
|
||||
label: string;
|
||||
imageSrc: string;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export type CharacterVisualGenerationPayload = {
|
||||
characterId: string;
|
||||
sourceMode: Exclude<CharacterVisualSourceMode, 'upload'>;
|
||||
promptText: string;
|
||||
characterBriefText?: string;
|
||||
referenceImageDataUrls: string[];
|
||||
candidateCount: number;
|
||||
imageModel: string;
|
||||
size: string;
|
||||
};
|
||||
|
||||
export type CharacterVisualPublishPayload = {
|
||||
characterId: string;
|
||||
sourceMode: CharacterVisualSourceMode;
|
||||
promptText: string;
|
||||
selectedPreviewSource: string;
|
||||
previewSources: string[];
|
||||
width: number;
|
||||
height: number;
|
||||
updateCharacterOverride?: boolean;
|
||||
};
|
||||
|
||||
export type CharacterAnimationGenerationPayload = {
|
||||
characterId: string;
|
||||
strategy: CharacterAnimationStrategy;
|
||||
animation: string;
|
||||
promptText: string;
|
||||
characterBriefText?: string;
|
||||
actionTemplateId?: string;
|
||||
visualSource: string;
|
||||
referenceImageDataUrls: string[];
|
||||
referenceVideoDataUrls: string[];
|
||||
lastFrameImageDataUrl?: string;
|
||||
frameCount: number;
|
||||
fps: number;
|
||||
durationSeconds: number;
|
||||
loop: boolean;
|
||||
useChromaKey: boolean;
|
||||
resolution: string;
|
||||
imageSequenceModel: string;
|
||||
videoModel: string;
|
||||
referenceVideoModel: string;
|
||||
motionTransferModel: CharacterMotionTransferModel;
|
||||
};
|
||||
|
||||
export type CharacterAnimationDraftPayload = {
|
||||
framesDataUrls: string[];
|
||||
fps: number;
|
||||
loop: boolean;
|
||||
frameWidth: number;
|
||||
frameHeight: number;
|
||||
previewVideoPath?: string;
|
||||
};
|
||||
|
||||
export type CharacterAnimationTemplate = {
|
||||
id: string;
|
||||
label: string;
|
||||
animation: string;
|
||||
promptSuffix: string;
|
||||
notes: string;
|
||||
};
|
||||
|
||||
export type CharacterAssetJobStatus = {
|
||||
taskId: string;
|
||||
kind: 'visual' | 'animation';
|
||||
status: 'queued' | 'running' | 'completed' | 'failed';
|
||||
characterId: string;
|
||||
animation?: string;
|
||||
strategy?: CharacterAnimationStrategy;
|
||||
model: string;
|
||||
prompt: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
result?: Record<string, unknown>;
|
||||
errorMessage?: string;
|
||||
};
|
||||
|
||||
export async function generateCharacterVisualCandidates(
|
||||
payload: CharacterVisualGenerationPayload,
|
||||
) {
|
||||
return postApiJson<{
|
||||
ok: true;
|
||||
taskId: string;
|
||||
model: string;
|
||||
prompt: string;
|
||||
drafts: CharacterVisualDraft[];
|
||||
}>(CHARACTER_VISUAL_GENERATE_API_PATH, payload, '生成角色主形象候选失败');
|
||||
}
|
||||
|
||||
export async function fetchCharacterVisualJobStatus(taskId: string) {
|
||||
return fetchJson<CharacterAssetJobStatus>(
|
||||
`${CHARACTER_VISUAL_JOB_API_PATH}/${encodeURIComponent(taskId)}`,
|
||||
'读取角色主形象任务状态失败',
|
||||
);
|
||||
}
|
||||
|
||||
export async function publishCharacterVisualAsset(
|
||||
payload: CharacterVisualPublishPayload,
|
||||
) {
|
||||
return postApiJson<{
|
||||
ok: true;
|
||||
assetId: string;
|
||||
portraitPath: string;
|
||||
overrideMap: Record<string, unknown>;
|
||||
saveMessage: string;
|
||||
}>(CHARACTER_VISUAL_PUBLISH_API_PATH, payload, '发布角色主形象失败');
|
||||
}
|
||||
|
||||
export async function generateCharacterAnimationDraft(
|
||||
payload: CharacterAnimationGenerationPayload,
|
||||
) {
|
||||
return postApiJson<
|
||||
| {
|
||||
ok: true;
|
||||
taskId: string;
|
||||
strategy: 'image-sequence';
|
||||
model: string;
|
||||
prompt: string;
|
||||
imageSources: string[];
|
||||
}
|
||||
| {
|
||||
ok: true;
|
||||
taskId: string;
|
||||
strategy: 'image-to-video' | 'motion-transfer' | 'reference-to-video';
|
||||
model: string;
|
||||
prompt: string;
|
||||
previewVideoPath: string;
|
||||
}
|
||||
>(CHARACTER_ANIMATION_GENERATE_API_PATH, payload, '生成角色动作草稿失败');
|
||||
}
|
||||
|
||||
export async function fetchCharacterAnimationJobStatus(taskId: string) {
|
||||
return fetchJson<CharacterAssetJobStatus>(
|
||||
`${CHARACTER_ANIMATION_JOB_API_PATH}/${encodeURIComponent(taskId)}`,
|
||||
'读取角色动作任务状态失败',
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchCharacterAnimationTemplates() {
|
||||
return fetchJson<{
|
||||
ok: true;
|
||||
templates: CharacterAnimationTemplate[];
|
||||
}>(CHARACTER_ANIMATION_TEMPLATES_API_PATH, '读取动作模板列表失败');
|
||||
}
|
||||
|
||||
export async function importCharacterAnimationVideo(payload: {
|
||||
characterId: string;
|
||||
animation: string;
|
||||
videoSource: string;
|
||||
sourceLabel?: string;
|
||||
}) {
|
||||
return postApiJson<{
|
||||
ok: true;
|
||||
importedVideoPath: string;
|
||||
draftId: string;
|
||||
saveMessage: string;
|
||||
}>(CHARACTER_ANIMATION_IMPORT_VIDEO_API_PATH, payload, '导入动作视频失败');
|
||||
}
|
||||
|
||||
export async function publishCharacterAnimationAssets(payload: {
|
||||
characterId: string;
|
||||
visualAssetId: string;
|
||||
animations: Record<string, CharacterAnimationDraftPayload>;
|
||||
updateCharacterOverride?: boolean;
|
||||
}) {
|
||||
return postApiJson<{
|
||||
ok: true;
|
||||
animationSetId: string;
|
||||
overrideMap: Record<string, unknown>;
|
||||
animationMap: Record<string, unknown>;
|
||||
saveMessage: string;
|
||||
}>(CHARACTER_ANIMATION_PUBLISH_API_PATH, payload, '发布角色基础动作失败');
|
||||
}
|
||||
Reference in New Issue
Block a user