1
This commit is contained in:
@@ -26,6 +26,7 @@ use platform_oss::{
|
||||
};
|
||||
use serde_json::{Map, Value, json};
|
||||
use shared_contracts::{
|
||||
creation_audio::CreationAudioAsset,
|
||||
puzzle_agent::{
|
||||
CreatePuzzleAgentSessionRequest, ExecutePuzzleAgentActionRequest,
|
||||
PuzzleAgentActionResponse, PuzzleAgentMessageResponse, PuzzleAgentOperationResponse,
|
||||
@@ -56,7 +57,7 @@ use spacetime_client::{
|
||||
PuzzleAgentMessageRecord, PuzzleAgentMessageSubmitRecordInput,
|
||||
PuzzleAgentSessionCreateRecordInput, PuzzleAgentSessionRecord,
|
||||
PuzzleAgentSuggestedActionRecord, PuzzleAnchorItemRecord, PuzzleAnchorPackRecord,
|
||||
PuzzleCreatorIntentRecord, PuzzleDraftLevelRecord, PuzzleFormDraftRecord,
|
||||
PuzzleAudioAssetRecord, PuzzleCreatorIntentRecord, PuzzleDraftLevelRecord, PuzzleFormDraftRecord,
|
||||
PuzzleFormDraftSaveRecordInput, PuzzleGeneratedImageCandidateRecord,
|
||||
PuzzleGeneratedImagesSaveRecordInput, PuzzleLeaderboardEntryRecord,
|
||||
PuzzleLeaderboardSubmitRecordInput, PuzzlePublishRecordInput, PuzzleRecommendedNextWorkRecord,
|
||||
@@ -228,6 +229,7 @@ pub async fn generate_puzzle_onboarding_work(
|
||||
level_name: level_name.clone(),
|
||||
picture_description: prompt_text.clone(),
|
||||
picture_reference: None,
|
||||
background_music: None,
|
||||
candidates,
|
||||
selected_candidate_id: Some(selected.candidate_id.clone()),
|
||||
cover_image_src: Some(selected.image_src.clone()),
|
||||
@@ -2059,6 +2061,7 @@ fn map_puzzle_draft_level_response(level: PuzzleDraftLevelRecord) -> PuzzleDraft
|
||||
level_name: level.level_name,
|
||||
picture_description: level.picture_description,
|
||||
picture_reference: level.picture_reference,
|
||||
background_music: level.background_music.map(map_puzzle_audio_asset_record_response),
|
||||
candidates: level
|
||||
.candidates
|
||||
.into_iter()
|
||||
@@ -2071,6 +2074,70 @@ fn map_puzzle_draft_level_response(level: PuzzleDraftLevelRecord) -> PuzzleDraft
|
||||
}
|
||||
}
|
||||
|
||||
fn map_puzzle_audio_asset_record_response(asset: PuzzleAudioAssetRecord) -> CreationAudioAsset {
|
||||
CreationAudioAsset {
|
||||
task_id: asset.task_id,
|
||||
provider: asset.provider,
|
||||
asset_object_id: asset.asset_object_id,
|
||||
asset_kind: asset.asset_kind,
|
||||
audio_src: asset.audio_src,
|
||||
prompt: asset.prompt,
|
||||
title: asset.title,
|
||||
updated_at: asset.updated_at,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_puzzle_audio_asset_domain_record(
|
||||
asset: module_puzzle::PuzzleAudioAsset,
|
||||
) -> PuzzleAudioAssetRecord {
|
||||
PuzzleAudioAssetRecord {
|
||||
task_id: asset.task_id,
|
||||
provider: asset.provider,
|
||||
asset_object_id: asset.asset_object_id,
|
||||
asset_kind: asset.asset_kind,
|
||||
audio_src: asset.audio_src,
|
||||
prompt: asset.prompt,
|
||||
title: asset.title,
|
||||
updated_at: asset.updated_at,
|
||||
}
|
||||
}
|
||||
|
||||
fn puzzle_audio_asset_response_module_json(asset: &Option<CreationAudioAsset>) -> Value {
|
||||
asset
|
||||
.as_ref()
|
||||
.map(|asset| {
|
||||
json!({
|
||||
"task_id": asset.task_id,
|
||||
"provider": asset.provider,
|
||||
"asset_object_id": asset.asset_object_id,
|
||||
"asset_kind": asset.asset_kind,
|
||||
"audio_src": asset.audio_src,
|
||||
"prompt": asset.prompt,
|
||||
"title": asset.title,
|
||||
"updated_at": asset.updated_at,
|
||||
})
|
||||
})
|
||||
.unwrap_or(Value::Null)
|
||||
}
|
||||
|
||||
fn puzzle_audio_asset_record_module_json(asset: &Option<PuzzleAudioAssetRecord>) -> Value {
|
||||
asset
|
||||
.as_ref()
|
||||
.map(|asset| {
|
||||
json!({
|
||||
"task_id": asset.task_id,
|
||||
"provider": asset.provider,
|
||||
"asset_object_id": asset.asset_object_id,
|
||||
"asset_kind": asset.asset_kind,
|
||||
"audio_src": asset.audio_src,
|
||||
"prompt": asset.prompt,
|
||||
"title": asset.title,
|
||||
"updated_at": asset.updated_at,
|
||||
})
|
||||
})
|
||||
.unwrap_or(Value::Null)
|
||||
}
|
||||
|
||||
fn map_puzzle_creator_intent_response(
|
||||
intent: PuzzleCreatorIntentRecord,
|
||||
) -> PuzzleCreatorIntentResponse {
|
||||
@@ -2600,6 +2667,7 @@ fn parse_puzzle_level_records_from_module_json(
|
||||
level_name: level.level_name,
|
||||
picture_description: level.picture_description,
|
||||
picture_reference: level.picture_reference,
|
||||
background_music: level.background_music.map(map_puzzle_audio_asset_domain_record),
|
||||
candidates: level
|
||||
.candidates
|
||||
.into_iter()
|
||||
@@ -2767,6 +2835,7 @@ fn serialize_puzzle_levels_response(
|
||||
"level_name": level.level_name,
|
||||
"picture_description": level.picture_description,
|
||||
"picture_reference": level.picture_reference,
|
||||
"background_music": puzzle_audio_asset_response_module_json(&level.background_music),
|
||||
"candidates": level
|
||||
.candidates
|
||||
.iter()
|
||||
@@ -2815,6 +2884,7 @@ fn normalize_puzzle_levels_json_for_module(value: Option<&str>) -> Result<Option
|
||||
"level_name": level.level_name,
|
||||
"picture_description": level.picture_description,
|
||||
"picture_reference": level.picture_reference,
|
||||
"background_music": puzzle_audio_asset_response_module_json(&level.background_music),
|
||||
"candidates": level
|
||||
.candidates
|
||||
.iter()
|
||||
@@ -3806,6 +3876,8 @@ fn serialize_puzzle_level_records_for_module(
|
||||
"level_id": level.level_id,
|
||||
"level_name": level.level_name,
|
||||
"picture_description": level.picture_description,
|
||||
"picture_reference": level.picture_reference,
|
||||
"background_music": puzzle_audio_asset_record_module_json(&level.background_music),
|
||||
"candidates": level
|
||||
.candidates
|
||||
.iter()
|
||||
@@ -4504,6 +4576,65 @@ mod tests {
|
||||
assert_eq!(draft.levels[0].level_name, "雨夜猫街");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn puzzle_level_audio_asset_roundtrips_between_response_and_module_json() {
|
||||
let level = PuzzleDraftLevelResponse {
|
||||
level_id: "puzzle-level-1".to_string(),
|
||||
level_name: "雨夜猫街".to_string(),
|
||||
picture_description: "一只猫在雨夜灯牌下回头。".to_string(),
|
||||
picture_reference: None,
|
||||
background_music: Some(CreationAudioAsset {
|
||||
task_id: "suno-task-1".to_string(),
|
||||
provider: "vector-engine-suno".to_string(),
|
||||
asset_object_id: Some("assetobj_1".to_string()),
|
||||
asset_kind: Some("puzzle_background_music".to_string()),
|
||||
audio_src: "/generated-puzzle-assets/audio.mp3".to_string(),
|
||||
prompt: Some("轻快拼图音乐".to_string()),
|
||||
title: Some("雨夜猫街背景音乐".to_string()),
|
||||
updated_at: Some("2026-05-11T00:00:00Z".to_string()),
|
||||
}),
|
||||
candidates: vec![],
|
||||
selected_candidate_id: None,
|
||||
cover_image_src: None,
|
||||
cover_asset_id: None,
|
||||
generation_status: "ready".to_string(),
|
||||
};
|
||||
let request_context = RequestContext::new(
|
||||
"test-request".to_string(),
|
||||
"PUT /api/runtime/puzzle/works/test".to_string(),
|
||||
Duration::ZERO,
|
||||
false,
|
||||
);
|
||||
|
||||
let levels_json = serialize_puzzle_levels_response(&request_context, &[level])
|
||||
.expect("levels should serialize");
|
||||
let payload: Value =
|
||||
serde_json::from_str(&levels_json).expect("levels json should parse");
|
||||
assert_eq!(
|
||||
payload[0]["background_music"]["audio_src"],
|
||||
Value::String("/generated-puzzle-assets/audio.mp3".to_string())
|
||||
);
|
||||
assert!(payload[0]["background_music"].get("audioSrc").is_none());
|
||||
|
||||
let records = parse_puzzle_level_records_from_module_json(&levels_json)
|
||||
.expect("levels should map back into records");
|
||||
let music = records[0]
|
||||
.background_music
|
||||
.as_ref()
|
||||
.expect("background music should exist");
|
||||
assert_eq!(music.audio_src, "/generated-puzzle-assets/audio.mp3");
|
||||
assert_eq!(music.asset_kind.as_deref(), Some("puzzle_background_music"));
|
||||
|
||||
let response = map_puzzle_draft_level_response(records[0].clone());
|
||||
assert_eq!(
|
||||
response
|
||||
.background_music
|
||||
.as_ref()
|
||||
.map(|asset| asset.audio_src.as_str()),
|
||||
Some("/generated-puzzle-assets/audio.mp3")
|
||||
);
|
||||
}
|
||||
|
||||
fn test_puzzle_anchor_pack_record() -> PuzzleAnchorPackRecord {
|
||||
let item = PuzzleAnchorItemRecord {
|
||||
key: "visualSubject".to_string(),
|
||||
@@ -4542,6 +4673,7 @@ mod tests {
|
||||
level_name: "猫画面".to_string(),
|
||||
picture_description: "一只猫在雨夜灯牌下回头。".to_string(),
|
||||
picture_reference: None,
|
||||
background_music: None,
|
||||
candidates: vec![],
|
||||
selected_candidate_id: None,
|
||||
cover_image_src: None,
|
||||
|
||||
Reference in New Issue
Block a user