1
This commit is contained in:
@@ -946,10 +946,18 @@ fn save_puzzle_generated_images_tx(
|
||||
) -> Result<PuzzleAgentSessionSnapshot, String> {
|
||||
let row = get_owned_session_row(ctx, &input.session_id, &input.owner_user_id)?;
|
||||
let mut draft = deserialize_draft_required(&row.draft_json)?;
|
||||
let previous_primary_level_name = draft.level_name.clone();
|
||||
let previous_work_title = draft.work_title.clone();
|
||||
if let Some(levels) = deserialize_optional_levels_input(input.levels_json.as_deref())? {
|
||||
// 中文注释:结果页新增关卡可能还没等到自动保存,生成图时以本次 action 携带的关卡快照作为写回目标。
|
||||
draft.levels = levels;
|
||||
module_puzzle::sync_primary_level_fields(&mut draft);
|
||||
// 中文注释:入口直创会在 api-server 生成首关名后随 levels_json 写入;作品名仍是旧首关名或空值时才跟随首关名,避免覆盖用户手动命名。
|
||||
sync_generated_primary_level_name_as_default_work_title(
|
||||
&mut draft,
|
||||
&previous_work_title,
|
||||
&previous_primary_level_name,
|
||||
);
|
||||
}
|
||||
let candidates: Vec<PuzzleGeneratedImageCandidate> = json_from_str(&input.candidates_json)
|
||||
.map_err(|error| format!("拼图候选图 JSON 非法: {error}"))?;
|
||||
@@ -1014,6 +1022,18 @@ fn save_puzzle_generated_images_tx(
|
||||
)
|
||||
}
|
||||
|
||||
fn sync_generated_primary_level_name_as_default_work_title(
|
||||
draft: &mut PuzzleResultDraft,
|
||||
previous_work_title: &str,
|
||||
previous_primary_level_name: &str,
|
||||
) {
|
||||
if previous_work_title.trim().is_empty()
|
||||
|| previous_work_title.trim() == previous_primary_level_name.trim()
|
||||
{
|
||||
draft.work_title = draft.level_name.clone();
|
||||
}
|
||||
}
|
||||
|
||||
fn select_puzzle_cover_image_tx(
|
||||
ctx: &TxContext,
|
||||
input: PuzzleSelectCoverImageInput,
|
||||
@@ -1189,7 +1209,7 @@ fn update_puzzle_work_tx(
|
||||
return Err("无权修改该拼图作品".to_string());
|
||||
}
|
||||
let theme_tags = normalize_theme_tags(input.theme_tags);
|
||||
if theme_tags.is_empty() || theme_tags.len() > PUZZLE_MAX_TAG_COUNT {
|
||||
if theme_tags.len() > PUZZLE_MAX_TAG_COUNT {
|
||||
return Err("拼图标签数量不合法".to_string());
|
||||
}
|
||||
let levels = deserialize_optional_levels_input(input.levels_json.as_deref())?
|
||||
@@ -1251,6 +1271,7 @@ fn update_puzzle_work_tx(
|
||||
published_at: row.published_at,
|
||||
};
|
||||
replace_puzzle_work_profile(ctx, &row, next_row);
|
||||
sync_puzzle_source_session_draft_from_work(ctx, &row, &preview_draft, input.updated_at_micros)?;
|
||||
get_puzzle_work_detail_tx(
|
||||
ctx,
|
||||
PuzzleWorkGetInput {
|
||||
@@ -1259,6 +1280,53 @@ fn update_puzzle_work_tx(
|
||||
)
|
||||
}
|
||||
|
||||
fn sync_puzzle_source_session_draft_from_work(
|
||||
ctx: &TxContext,
|
||||
work_row: &PuzzleWorkProfileRow,
|
||||
draft: &PuzzleResultDraft,
|
||||
updated_at_micros: i64,
|
||||
) -> Result<(), String> {
|
||||
let Some(session_id) = work_row.source_session_id.as_ref() else {
|
||||
return Ok(());
|
||||
};
|
||||
let Some(session_row) = ctx.db.puzzle_agent_session().session_id().find(session_id) else {
|
||||
return Ok(());
|
||||
};
|
||||
if session_row.owner_user_id != work_row.owner_user_id {
|
||||
return Ok(());
|
||||
}
|
||||
let normalized_draft = normalize_puzzle_draft(draft.clone());
|
||||
let updated_at = Timestamp::from_micros_since_unix_epoch(updated_at_micros);
|
||||
let next_stage = if session_row.stage == PuzzleAgentStage::Published {
|
||||
PuzzleAgentStage::Published
|
||||
} else if build_result_preview(&normalized_draft, Some(&work_row.author_display_name))
|
||||
.publish_ready
|
||||
{
|
||||
PuzzleAgentStage::ReadyToPublish
|
||||
} else {
|
||||
PuzzleAgentStage::ImageRefining
|
||||
};
|
||||
replace_puzzle_agent_session(
|
||||
ctx,
|
||||
&session_row,
|
||||
PuzzleAgentSessionRow {
|
||||
session_id: session_row.session_id.clone(),
|
||||
owner_user_id: session_row.owner_user_id.clone(),
|
||||
seed_text: session_row.seed_text.clone(),
|
||||
current_turn: session_row.current_turn,
|
||||
progress_percent: session_row.progress_percent.max(94),
|
||||
stage: next_stage,
|
||||
anchor_pack_json: session_row.anchor_pack_json.clone(),
|
||||
draft_json: Some(serialize_json(&normalized_draft)),
|
||||
last_assistant_reply: session_row.last_assistant_reply.clone(),
|
||||
published_profile_id: session_row.published_profile_id.clone(),
|
||||
created_at: session_row.created_at,
|
||||
updated_at,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_puzzle_work_tx(
|
||||
ctx: &TxContext,
|
||||
input: PuzzleWorkDeleteInput,
|
||||
@@ -3298,6 +3366,53 @@ mod tests {
|
||||
assert!(draft.candidates[0].selected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generated_first_level_name_defaults_work_title_when_previous_title_is_fallback() {
|
||||
let anchor_pack = infer_anchor_pack("画面描述:一只猫在雨夜灯牌下回头。", None);
|
||||
let mut draft = compile_result_draft_from_seed(
|
||||
&anchor_pack,
|
||||
&[],
|
||||
Some("画面描述:一只猫在雨夜灯牌下回头。"),
|
||||
);
|
||||
let previous_level_name = draft.level_name.clone();
|
||||
let previous_work_title = draft.work_title.clone();
|
||||
draft.levels[0].level_name = "雨夜猫街".to_string();
|
||||
module_puzzle::sync_primary_level_fields(&mut draft);
|
||||
|
||||
sync_generated_primary_level_name_as_default_work_title(
|
||||
&mut draft,
|
||||
&previous_work_title,
|
||||
&previous_level_name,
|
||||
);
|
||||
|
||||
assert_eq!(draft.level_name, "雨夜猫街");
|
||||
assert_eq!(draft.work_title, "雨夜猫街");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generated_first_level_name_keeps_manual_work_title() {
|
||||
let anchor_pack = infer_anchor_pack("画面描述:一只猫在雨夜灯牌下回头。", None);
|
||||
let mut draft = compile_result_draft_from_seed(
|
||||
&anchor_pack,
|
||||
&[],
|
||||
Some("画面描述:一只猫在雨夜灯牌下回头。"),
|
||||
);
|
||||
let previous_level_name = draft.level_name.clone();
|
||||
let previous_work_title = "我的猫街合集".to_string();
|
||||
draft.work_title = previous_work_title.clone();
|
||||
draft.levels[0].level_name = "雨夜猫街".to_string();
|
||||
module_puzzle::sync_primary_level_fields(&mut draft);
|
||||
|
||||
sync_generated_primary_level_name_as_default_work_title(
|
||||
&mut draft,
|
||||
&previous_work_title,
|
||||
&previous_level_name,
|
||||
);
|
||||
|
||||
assert_eq!(draft.level_name, "雨夜猫街");
|
||||
assert_eq!(draft.work_title, "我的猫街合集");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn puzzle_recommendation_score_prefers_same_author_weight() {
|
||||
let left = PuzzleWorkProfile {
|
||||
|
||||
Reference in New Issue
Block a user