1
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-11 15:43:32 +08:00
parent f19e482c8f
commit 0981d6ee1b
78 changed files with 1102 additions and 8510 deletions

File diff suppressed because it is too large Load Diff

View 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, '发布角色基础动作失败');
}