This commit is contained in:
2026-04-25 22:38:03 +08:00
29 changed files with 1988 additions and 121 deletions

View File

@@ -684,7 +684,7 @@ fn save_puzzle_generated_images_tx(
if candidates.is_empty() {
return Err("拼图候选图不能为空".to_string());
}
draft.candidates = candidates;
append_generated_candidates(&mut draft, candidates);
draft.generation_status = "ready".to_string();
if let Some(selected) = draft
.candidates
@@ -1507,6 +1507,23 @@ fn increment_puzzle_profile_play_count(
);
}
fn append_generated_candidates(
draft: &mut PuzzleResultDraft,
candidates: Vec<PuzzleGeneratedImageCandidate>,
) {
let has_selected_candidate = draft.candidates.iter().any(|entry| entry.selected);
// 再次生成图片是扩充候选池,不覆盖创作者已经看到或已经选择的候选图。
// 若已有正式选择,新追加候选图保持未选中,避免同一草稿出现多个 selected。
draft
.candidates
.extend(candidates.into_iter().map(|mut candidate| {
if has_selected_candidate {
candidate.selected = false;
}
candidate
}));
}
fn list_published_puzzle_profiles(ctx: &TxContext) -> Result<Vec<PuzzleWorkProfile>, String> {
ctx.db
.puzzle_work_profile()
@@ -1613,6 +1630,40 @@ mod tests {
assert!(preview.publish_ready);
}
#[test]
fn puzzle_generated_images_are_appended_without_clearing_existing_candidates() {
let anchor_pack = infer_anchor_pack("蒸汽城市雨夜猫咪", Some("蒸汽城市雨夜猫咪"));
let mut draft = compile_result_draft(&anchor_pack, &[]);
draft.candidates = vec![PuzzleGeneratedImageCandidate {
candidate_id: "session-1-candidate-1".to_string(),
image_src: "/generated-puzzle-assets/session-1/old/cover.png".to_string(),
asset_id: "asset-old".to_string(),
prompt: "旧提示词".to_string(),
actual_prompt: Some("旧提示词".to_string()),
source_type: "generated".to_string(),
selected: true,
}];
append_generated_candidates(
&mut draft,
vec![PuzzleGeneratedImageCandidate {
candidate_id: "session-1-candidate-2".to_string(),
image_src: "/generated-puzzle-assets/session-1/new/cover.png".to_string(),
asset_id: "asset-new".to_string(),
prompt: "新提示词".to_string(),
actual_prompt: Some("新提示词".to_string()),
source_type: "generated".to_string(),
selected: true,
}],
);
assert_eq!(draft.candidates.len(), 2);
assert_eq!(draft.candidates[0].candidate_id, "session-1-candidate-1");
assert!(draft.candidates[0].selected);
assert_eq!(draft.candidates[1].candidate_id, "session-1-candidate-2");
assert!(!draft.candidates[1].selected);
}
#[test]
fn puzzle_recommendation_score_prefers_same_author_weight() {
let left = PuzzleWorkProfile {