Merge remote-tracking branch 'origin/codex/wooden-fish-template'
This commit is contained in:
@@ -61,6 +61,7 @@ pub enum CreationAudioStoragePrefix {
|
||||
PuzzleAssets,
|
||||
#[serde(rename = "match3d_assets")]
|
||||
Match3DAssets,
|
||||
WoodenFishAssets,
|
||||
CustomWorldScenes,
|
||||
}
|
||||
|
||||
@@ -125,4 +126,20 @@ mod tests {
|
||||
assert_eq!(payload["taskId"], json!("task-1"));
|
||||
assert_eq!(payload["audioSrc"], json!("/generated-puzzle-assets/a.mp3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn creation_audio_contracts_support_wooden_fish_storage_prefix() {
|
||||
let request = PublishGeneratedAudioAssetRequest {
|
||||
entity_kind: "wooden_fish_work".to_string(),
|
||||
entity_id: "wooden-fish-profile-1".to_string(),
|
||||
slot: "hit_sound".to_string(),
|
||||
asset_kind: "wooden_fish_hit_sound".to_string(),
|
||||
profile_id: Some("wooden-fish-profile-1".to_string()),
|
||||
storage_prefix: Some(CreationAudioStoragePrefix::WoodenFishAssets),
|
||||
};
|
||||
|
||||
let payload = serde_json::to_value(request).expect("request should serialize");
|
||||
|
||||
assert_eq!(payload["storagePrefix"], json!("wooden_fish_assets"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,3 +29,4 @@ pub mod square_hole_runtime;
|
||||
pub mod square_hole_works;
|
||||
pub mod story;
|
||||
pub mod visual_novel;
|
||||
pub mod wooden_fish;
|
||||
|
||||
507
server-rs/crates/shared-contracts/src/wooden_fish.rs
Normal file
507
server-rs/crates/shared-contracts/src/wooden_fish.rs
Normal file
@@ -0,0 +1,507 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum WoodenFishGenerationStatus {
|
||||
Draft,
|
||||
Generating,
|
||||
Ready,
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum WoodenFishActionType {
|
||||
CompileDraft,
|
||||
RegenerateHitObject,
|
||||
GenerateHitSound,
|
||||
ReplaceHitSound,
|
||||
UpdateWorkMeta,
|
||||
UpdateFloatingWords,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum WoodenFishRunStatus {
|
||||
Playing,
|
||||
Finished,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishImageAsset {
|
||||
pub asset_id: String,
|
||||
pub image_src: String,
|
||||
pub image_object_key: String,
|
||||
pub asset_object_id: String,
|
||||
pub generation_provider: String,
|
||||
pub prompt: String,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishAudioAsset {
|
||||
pub asset_id: String,
|
||||
pub audio_src: String,
|
||||
pub audio_object_key: String,
|
||||
pub asset_object_id: String,
|
||||
pub source: String,
|
||||
#[serde(default)]
|
||||
pub prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub duration_ms: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishWorkspaceCreateRequest {
|
||||
pub template_id: String,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub hit_object_prompt: String,
|
||||
#[serde(default)]
|
||||
pub hit_object_reference_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub hit_sound_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub hit_sound_asset: Option<WoodenFishAudioAsset>,
|
||||
pub floating_words: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishActionRequest {
|
||||
pub action_type: WoodenFishActionType,
|
||||
#[serde(default, skip_deserializing)]
|
||||
pub profile_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub work_title: Option<String>,
|
||||
#[serde(default)]
|
||||
pub work_description: Option<String>,
|
||||
#[serde(default)]
|
||||
pub theme_tags: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub hit_object_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub hit_object_reference_image_src: Option<String>,
|
||||
#[serde(default, skip_deserializing)]
|
||||
pub hit_object_asset: Option<WoodenFishImageAsset>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_deserializing)]
|
||||
pub background_asset: Option<WoodenFishImageAsset>,
|
||||
#[serde(default)]
|
||||
pub hit_sound_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub hit_sound_asset: Option<WoodenFishAudioAsset>,
|
||||
#[serde(default)]
|
||||
pub floating_words: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishWordCounter {
|
||||
pub text: String,
|
||||
pub count: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishDraftResponse {
|
||||
pub template_id: String,
|
||||
pub template_name: String,
|
||||
#[serde(default)]
|
||||
pub profile_id: Option<String>,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub hit_object_prompt: String,
|
||||
#[serde(default)]
|
||||
pub hit_object_reference_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub hit_sound_prompt: Option<String>,
|
||||
pub floating_words: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub hit_object_asset: Option<WoodenFishImageAsset>,
|
||||
#[serde(default)]
|
||||
pub background_asset: Option<WoodenFishImageAsset>,
|
||||
#[serde(default)]
|
||||
pub hit_sound_asset: Option<WoodenFishAudioAsset>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
pub generation_status: WoodenFishGenerationStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishSessionSnapshotResponse {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: WoodenFishGenerationStatus,
|
||||
#[serde(default)]
|
||||
pub draft: Option<WoodenFishDraftResponse>,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishSessionResponse {
|
||||
pub session: WoodenFishSessionSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishActionResponse {
|
||||
pub action_type: WoodenFishActionType,
|
||||
pub session: WoodenFishSessionSnapshotResponse,
|
||||
#[serde(default)]
|
||||
pub work: Option<WoodenFishWorkProfileResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishWorkSummaryResponse {
|
||||
pub runtime_kind: String,
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
#[serde(default)]
|
||||
pub source_session_id: Option<String>,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
pub publication_status: String,
|
||||
pub play_count: u32,
|
||||
pub updated_at: String,
|
||||
#[serde(default)]
|
||||
pub published_at: Option<String>,
|
||||
pub publish_ready: bool,
|
||||
pub generation_status: WoodenFishGenerationStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishWorkProfileResponse {
|
||||
pub summary: WoodenFishWorkSummaryResponse,
|
||||
pub draft: WoodenFishDraftResponse,
|
||||
pub hit_object_asset: WoodenFishImageAsset,
|
||||
#[serde(default)]
|
||||
pub background_asset: Option<WoodenFishImageAsset>,
|
||||
pub hit_sound_asset: WoodenFishAudioAsset,
|
||||
pub floating_words: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishWorkDetailResponse {
|
||||
pub item: WoodenFishWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishWorkMutationResponse {
|
||||
pub item: WoodenFishWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishGalleryCardResponse {
|
||||
pub public_work_code: String,
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub author_display_name: String,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub publication_status: String,
|
||||
pub play_count: u32,
|
||||
pub updated_at: String,
|
||||
#[serde(default)]
|
||||
pub published_at: Option<String>,
|
||||
pub generation_status: WoodenFishGenerationStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishGalleryResponse {
|
||||
pub items: Vec<WoodenFishGalleryCardResponse>,
|
||||
pub has_more: bool,
|
||||
#[serde(default)]
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishGalleryDetailResponse {
|
||||
pub item: WoodenFishWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishRuntimeRunSnapshotResponse {
|
||||
pub run_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: WoodenFishRunStatus,
|
||||
pub total_tap_count: u32,
|
||||
pub word_counters: Vec<WoodenFishWordCounter>,
|
||||
pub started_at_ms: u64,
|
||||
pub updated_at_ms: u64,
|
||||
#[serde(default)]
|
||||
pub finished_at_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishRunResponse {
|
||||
pub run: WoodenFishRuntimeRunSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishStartRunRequest {
|
||||
pub profile_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishCheckpointRunRequest {
|
||||
pub total_tap_count: u32,
|
||||
pub word_counters: Vec<WoodenFishWordCounter>,
|
||||
pub client_event_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WoodenFishFinishRunRequest {
|
||||
pub total_tap_count: u32,
|
||||
pub word_counters: Vec<WoodenFishWordCounter>,
|
||||
pub client_event_id: String,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn wooden_fish_workspace_request_uses_camel_case_and_default_words() {
|
||||
let payload = serde_json::to_value(WoodenFishWorkspaceCreateRequest {
|
||||
template_id: "wooden-fish".to_string(),
|
||||
work_title: "今日敲木鱼".to_string(),
|
||||
work_description: "轻松敲击".to_string(),
|
||||
theme_tags: vec!["休闲".to_string()],
|
||||
hit_object_prompt: "卡通木鱼".to_string(),
|
||||
hit_object_reference_image_src: None,
|
||||
hit_sound_prompt: Some("清脆木鱼声".to_string()),
|
||||
hit_sound_asset: None,
|
||||
floating_words: vec![
|
||||
"幸运".to_string(),
|
||||
"健康".to_string(),
|
||||
"财富".to_string(),
|
||||
"姻缘".to_string(),
|
||||
"幸福".to_string(),
|
||||
"事业".to_string(),
|
||||
"成功".to_string(),
|
||||
"功德".to_string(),
|
||||
],
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload["templateId"], json!("wooden-fish"));
|
||||
assert_eq!(payload["hitObjectPrompt"], json!("卡通木鱼"));
|
||||
assert_eq!(payload["hitSoundPrompt"], json!("清脆木鱼声"));
|
||||
assert_eq!(payload["floatingWords"][7], json!("功德"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wooden_fish_runtime_snapshot_counts_words_inside_one_run() {
|
||||
let payload = serde_json::to_value(WoodenFishRuntimeRunSnapshotResponse {
|
||||
run_id: "wooden-fish-run-1".to_string(),
|
||||
profile_id: "wooden-fish-profile-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
status: WoodenFishRunStatus::Playing,
|
||||
total_tap_count: 3,
|
||||
word_counters: vec![
|
||||
WoodenFishWordCounter {
|
||||
text: "幸运".to_string(),
|
||||
count: 2,
|
||||
},
|
||||
WoodenFishWordCounter {
|
||||
text: "功德".to_string(),
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
started_at_ms: 100,
|
||||
updated_at_ms: 130,
|
||||
finished_at_ms: None,
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload["status"], json!("playing"));
|
||||
assert_eq!(payload["totalTapCount"], json!(3));
|
||||
assert_eq!(payload["wordCounters"][0]["text"], json!("幸运"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wooden_fish_action_request_serializes_audio_and_image_fields() {
|
||||
let payload = serde_json::to_value(WoodenFishActionRequest {
|
||||
action_type: WoodenFishActionType::ReplaceHitSound,
|
||||
profile_id: Some("wooden-fish-profile-1".to_string()),
|
||||
work_title: None,
|
||||
work_description: None,
|
||||
theme_tags: None,
|
||||
hit_object_prompt: Some("卡通铜钹".to_string()),
|
||||
hit_object_reference_image_src: Some("/uploads/reference.png".to_string()),
|
||||
hit_object_asset: Some(WoodenFishImageAsset {
|
||||
asset_id: "image-1".to_string(),
|
||||
image_src: "/generated-wooden-fish-assets/profile/hit-object/image.png".to_string(),
|
||||
image_object_key: "generated-wooden-fish-assets/profile/hit-object/image.png"
|
||||
.to_string(),
|
||||
asset_object_id: "image-object-1".to_string(),
|
||||
generation_provider: "image2".to_string(),
|
||||
prompt: "卡通铜钹".to_string(),
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
}),
|
||||
background_asset: Some(WoodenFishImageAsset {
|
||||
asset_id: "background-1".to_string(),
|
||||
image_src: "/generated-wooden-fish-assets/profile/background/image.png"
|
||||
.to_string(),
|
||||
image_object_key: "generated-wooden-fish-assets/profile/background/image.png"
|
||||
.to_string(),
|
||||
asset_object_id: "background-object-1".to_string(),
|
||||
generation_provider: "image2".to_string(),
|
||||
prompt: "赛博莲花背景".to_string(),
|
||||
width: 1024,
|
||||
height: 1536,
|
||||
}),
|
||||
hit_sound_prompt: Some("短促木鱼声".to_string()),
|
||||
hit_sound_asset: Some(WoodenFishAudioAsset {
|
||||
asset_id: "sound-1".to_string(),
|
||||
audio_src: "/generated/wooden-fish.mp3".to_string(),
|
||||
audio_object_key: "generated/wooden-fish.mp3".to_string(),
|
||||
asset_object_id: "asset-object-1".to_string(),
|
||||
source: "upload".to_string(),
|
||||
prompt: None,
|
||||
duration_ms: Some(800),
|
||||
}),
|
||||
floating_words: Some(vec!["功德".to_string()]),
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload["actionType"], json!("replace-hit-sound"));
|
||||
assert_eq!(payload["profileId"], json!("wooden-fish-profile-1"));
|
||||
assert_eq!(payload["hitObjectPrompt"], json!("卡通铜钹"));
|
||||
assert_eq!(
|
||||
payload["hitObjectAsset"]["imageObjectKey"],
|
||||
json!("generated-wooden-fish-assets/profile/hit-object/image.png")
|
||||
);
|
||||
assert_eq!(payload["backgroundAsset"]["height"], json!(1536));
|
||||
assert_eq!(payload["hitSoundAsset"]["source"], json!("upload"));
|
||||
assert_eq!(payload["hitSoundAsset"]["durationMs"], json!(800));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wooden_fish_action_request_ignores_client_hit_object_asset() {
|
||||
let payload = serde_json::from_value::<WoodenFishActionRequest>(json!({
|
||||
"actionType": "compile-draft",
|
||||
"hitObjectPrompt": "卡通铜钹",
|
||||
"hitObjectAsset": {
|
||||
"assetId": "client-image",
|
||||
"imageSrc": "/generated-wooden-fish-assets/client/image.png",
|
||||
"imageObjectKey": "generated-wooden-fish-assets/client/image.png",
|
||||
"assetObjectId": "client-asset-object",
|
||||
"generationProvider": "client",
|
||||
"prompt": "跳过生成",
|
||||
"width": 1024,
|
||||
"height": 1024
|
||||
}
|
||||
}))
|
||||
.expect("payload should deserialize");
|
||||
|
||||
assert_eq!(payload.action_type, WoodenFishActionType::CompileDraft);
|
||||
assert_eq!(payload.hit_object_prompt.as_deref(), Some("卡通铜钹"));
|
||||
assert_eq!(payload.hit_object_asset, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wooden_fish_work_profile_keeps_summary_and_runtime_assets() {
|
||||
let image = WoodenFishImageAsset {
|
||||
asset_id: "image-1".to_string(),
|
||||
image_src: "/generated/wooden-fish.png".to_string(),
|
||||
image_object_key: "generated/wooden-fish.png".to_string(),
|
||||
asset_object_id: "image-object-1".to_string(),
|
||||
generation_provider: "image2".to_string(),
|
||||
prompt: "卡通木鱼".to_string(),
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
};
|
||||
let audio = WoodenFishAudioAsset {
|
||||
asset_id: "sound-1".to_string(),
|
||||
audio_src: "/generated/wooden-fish.mp3".to_string(),
|
||||
audio_object_key: "generated/wooden-fish.mp3".to_string(),
|
||||
asset_object_id: "sound-object-1".to_string(),
|
||||
source: "generated".to_string(),
|
||||
prompt: Some("清脆木鱼".to_string()),
|
||||
duration_ms: Some(600),
|
||||
};
|
||||
let profile = WoodenFishWorkProfileResponse {
|
||||
summary: WoodenFishWorkSummaryResponse {
|
||||
runtime_kind: "wooden-fish".to_string(),
|
||||
work_id: "wooden-fish-profile-1".to_string(),
|
||||
profile_id: "wooden-fish-profile-1".to_string(),
|
||||
owner_user_id: "user-1".to_string(),
|
||||
source_session_id: Some("wooden-fish-session-1".to_string()),
|
||||
work_title: "敲木鱼".to_string(),
|
||||
work_description: String::new(),
|
||||
theme_tags: vec!["休闲".to_string()],
|
||||
cover_image_src: Some(image.image_src.clone()),
|
||||
publication_status: "draft".to_string(),
|
||||
play_count: 0,
|
||||
updated_at: "2026-05-20T00:00:00Z".to_string(),
|
||||
published_at: None,
|
||||
publish_ready: true,
|
||||
generation_status: WoodenFishGenerationStatus::Ready,
|
||||
},
|
||||
draft: WoodenFishDraftResponse {
|
||||
template_id: "wooden-fish".to_string(),
|
||||
template_name: "敲木鱼".to_string(),
|
||||
profile_id: Some("wooden-fish-profile-1".to_string()),
|
||||
work_title: "敲木鱼".to_string(),
|
||||
work_description: String::new(),
|
||||
theme_tags: vec!["休闲".to_string()],
|
||||
hit_object_prompt: "卡通木鱼".to_string(),
|
||||
hit_object_reference_image_src: None,
|
||||
hit_sound_prompt: Some("清脆木鱼".to_string()),
|
||||
floating_words: vec!["功德".to_string()],
|
||||
hit_object_asset: Some(image.clone()),
|
||||
background_asset: None,
|
||||
hit_sound_asset: Some(audio.clone()),
|
||||
cover_image_src: Some(image.image_src.clone()),
|
||||
generation_status: WoodenFishGenerationStatus::Ready,
|
||||
},
|
||||
hit_object_asset: image,
|
||||
background_asset: None,
|
||||
hit_sound_asset: audio,
|
||||
floating_words: vec!["功德".to_string()],
|
||||
};
|
||||
|
||||
let payload = serde_json::to_value(profile).expect("profile should serialize");
|
||||
|
||||
assert_eq!(payload["summary"]["runtimeKind"], json!("wooden-fish"));
|
||||
assert_eq!(
|
||||
payload["hitObjectAsset"]["generationProvider"],
|
||||
json!("image2")
|
||||
);
|
||||
assert_eq!(payload["hitSoundAsset"]["source"], json!("generated"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user