新增编辑器生成规范、生成角色形象、生成图标素材等功能

新增编辑器生成规范、生成角色形象、生成图标素材等功能
This commit is contained in:
2026-06-16 14:47:13 +08:00
parent 0fd0a06387
commit 7eeff10c67
33 changed files with 8783 additions and 502 deletions

View File

@@ -304,6 +304,48 @@ pub struct CharacterAnimationGenerateResponse {
pub preview_video_path: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorCharacterAnimationGenerateRequest {
pub source_layer_id: String,
pub source_image_src: String,
pub source_width: u32,
pub source_height: u32,
pub prompt_text: String,
pub resolution: String,
pub ratio: String,
pub frame_count: u32,
pub duration_seconds: u32,
pub price_mud_points: u32,
pub model: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorCharacterAnimationFramePayload {
pub frame_index: u32,
pub image_src: String,
pub width: u32,
pub height: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct EditorCharacterAnimationGenerateResponse {
pub ok: bool,
pub task_id: String,
pub model: String,
pub prompt: String,
pub preview_video_path: String,
pub frames: Vec<EditorCharacterAnimationFramePayload>,
pub frame_count: u32,
pub duration_seconds: u32,
pub frame_width: u32,
pub frame_height: u32,
pub fps: u32,
pub price_mud_points: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CharacterAnimationDraftPayload {
@@ -815,6 +857,57 @@ mod tests {
assert_eq!(payload["draftId"], json!("animation-import-1"));
}
#[test]
fn editor_character_animation_request_uses_expected_camel_case_shape() {
let payload = serde_json::to_value(EditorCharacterAnimationGenerateRequest {
source_layer_id: "layer-1".to_string(),
source_image_src: "/generated-characters/hero/master.png".to_string(),
source_width: 768,
source_height: 1024,
prompt_text: "待机呼吸".to_string(),
resolution: "720p".to_string(),
ratio: "same".to_string(),
frame_count: 48,
duration_seconds: 6,
price_mud_points: 120,
model: "seedance2.0".to_string(),
})
.expect("request should serialize");
assert_eq!(payload["sourceLayerId"], json!("layer-1"));
assert_eq!(payload["sourceImageSrc"], json!("/generated-characters/hero/master.png"));
assert_eq!(payload["priceMudPoints"], json!(120));
assert_eq!(payload["model"], json!("seedance2.0"));
}
#[test]
fn editor_character_animation_response_includes_frames_and_preview_video() {
let payload = serde_json::to_value(EditorCharacterAnimationGenerateResponse {
ok: true,
task_id: "task-1".to_string(),
model: "seedance2.0".to_string(),
prompt: "生成游戏角色动画".to_string(),
preview_video_path: "/generated-character-drafts/editor/layer/preview.mp4".to_string(),
frames: vec![EditorCharacterAnimationFramePayload {
frame_index: 1,
image_src: "/generated-animations/editor/layer/frame01.png".to_string(),
width: 768,
height: 1024,
}],
frame_count: 1,
duration_seconds: 4,
frame_width: 768,
frame_height: 1024,
fps: 8,
price_mud_points: 40,
})
.expect("response should serialize");
assert_eq!(payload["previewVideoPath"], json!("/generated-character-drafts/editor/layer/preview.mp4"));
assert_eq!(payload["frames"][0]["imageSrc"], json!("/generated-animations/editor/layer/frame01.png"));
assert_eq!(payload["fps"], json!(8));
}
#[test]
fn character_workflow_cache_response_keeps_legacy_shape() {
let payload = serde_json::to_value(CharacterWorkflowCacheSaveResponse {