1
This commit is contained in:
@@ -125,10 +125,7 @@ pub fn build_form_anchor_pack(title: &str, picture_description: &str) -> PuzzleA
|
||||
pack.visual_mood.status = PuzzleAnchorStatus::Inferred;
|
||||
pack.composition_hooks.value = "主体轮廓、色块分区、局部细节".to_string();
|
||||
pack.composition_hooks.status = PuzzleAnchorStatus::Inferred;
|
||||
pack.tags_and_forbidden.value = build_form_tags_and_forbidden(
|
||||
normalized_title.as_deref().unwrap_or(""),
|
||||
normalized_description.as_deref().unwrap_or(""),
|
||||
);
|
||||
pack.tags_and_forbidden.value = build_form_tags_and_forbidden(title, picture_description);
|
||||
pack.tags_and_forbidden.status = PuzzleAnchorStatus::Inferred;
|
||||
|
||||
pack
|
||||
@@ -178,12 +175,12 @@ pub fn compile_result_draft_from_seed(
|
||||
seed_text: Option<&str>,
|
||||
) -> PuzzleResultDraft {
|
||||
let creator_intent = build_creator_intent(anchor_pack, messages);
|
||||
let normalized_tags = normalize_theme_tags(creator_intent.theme_tags.clone());
|
||||
let work_title = build_work_title(anchor_pack);
|
||||
let normalized_tags = resolve_initial_theme_tags(seed_text, &creator_intent);
|
||||
let work_description = resolve_work_description(seed_text, anchor_pack);
|
||||
let picture_description = fallback_text(&anchor_pack.visual_subject.value, "画面主体");
|
||||
let level_name =
|
||||
build_level_name_from_picture(picture_description.as_str(), &normalized_tags, 1);
|
||||
let work_title = resolve_work_title(seed_text, anchor_pack, &level_name);
|
||||
let level = PuzzleDraftLevel {
|
||||
level_id: "puzzle-level-1".to_string(),
|
||||
level_name: level_name.clone(),
|
||||
@@ -238,16 +235,6 @@ pub fn build_form_draft_from_parts(
|
||||
let work_description = work_description.and_then(|value| normalize_required_string(&value));
|
||||
let picture_description =
|
||||
picture_description.and_then(|value| normalize_required_string(&value));
|
||||
let title_for_tags = work_title.as_deref().unwrap_or("");
|
||||
let picture_for_tags = picture_description.as_deref().unwrap_or("");
|
||||
let mut tags = normalize_theme_tags(derive_form_theme_tags(title_for_tags, picture_for_tags));
|
||||
if tags.is_empty() {
|
||||
tags = vec![
|
||||
"拼图".to_string(),
|
||||
"插画".to_string(),
|
||||
"清晰构图".to_string(),
|
||||
];
|
||||
}
|
||||
let summary = work_description.clone().unwrap_or_default();
|
||||
let level = PuzzleDraftLevel {
|
||||
level_id: "puzzle-level-1".to_string(),
|
||||
@@ -266,7 +253,7 @@ pub fn build_form_draft_from_parts(
|
||||
work_description: summary.clone(),
|
||||
level_name: String::new(),
|
||||
summary,
|
||||
theme_tags: tags,
|
||||
theme_tags: Vec::new(),
|
||||
forbidden_directives: Vec::new(),
|
||||
creator_intent: None,
|
||||
anchor_pack: anchor_pack.clone(),
|
||||
@@ -349,12 +336,6 @@ pub fn apply_selected_candidate(
|
||||
}
|
||||
|
||||
pub fn normalize_puzzle_draft(mut draft: PuzzleResultDraft) -> PuzzleResultDraft {
|
||||
if draft.work_title.trim().is_empty() {
|
||||
draft.work_title = fallback_text(&draft.anchor_pack.theme_promise.value, &draft.level_name);
|
||||
}
|
||||
if draft.work_description.trim().is_empty() {
|
||||
draft.work_description = draft.summary.clone();
|
||||
}
|
||||
if draft.levels.is_empty() {
|
||||
draft.levels = vec![PuzzleDraftLevel {
|
||||
level_id: "puzzle-level-1".to_string(),
|
||||
@@ -383,9 +364,6 @@ pub fn sync_primary_level_fields(draft: &mut PuzzleResultDraft) {
|
||||
draft.cover_asset_id = primary_level.cover_asset_id.clone();
|
||||
draft.generation_status = primary_level.generation_status.clone();
|
||||
}
|
||||
if draft.work_description.trim().is_empty() {
|
||||
draft.work_description = draft.summary.clone();
|
||||
}
|
||||
draft.summary = draft.work_description.clone();
|
||||
if draft.form_draft.is_some() {
|
||||
draft.form_draft = Some(PuzzleFormDraft {
|
||||
@@ -642,23 +620,19 @@ pub fn apply_publish_overrides_to_draft(
|
||||
) -> Result<PuzzleResultDraft, PuzzleFieldError> {
|
||||
let mut next_draft = normalize_puzzle_draft(draft.clone());
|
||||
|
||||
if let Some(next_work_title) = work_title
|
||||
&& let Some(normalized_work_title) = normalize_required_string(&next_work_title)
|
||||
{
|
||||
next_draft.work_title = normalized_work_title;
|
||||
if let Some(next_work_title) = work_title {
|
||||
next_draft.work_title = normalize_required_string(&next_work_title).unwrap_or_default();
|
||||
}
|
||||
|
||||
if let Some(next_work_description) = work_description
|
||||
&& let Some(normalized_work_description) = normalize_required_string(&next_work_description)
|
||||
{
|
||||
next_draft.work_description = normalized_work_description;
|
||||
if let Some(next_work_description) = work_description {
|
||||
next_draft.work_description =
|
||||
normalize_required_string(&next_work_description).unwrap_or_default();
|
||||
}
|
||||
|
||||
if let Some(next_level_name) = level_name
|
||||
&& let Some(normalized_level_name) = normalize_required_string(&next_level_name)
|
||||
{
|
||||
if let Some(next_level_name) = level_name {
|
||||
if let Some(primary_level) = next_draft.levels.first_mut() {
|
||||
primary_level.level_name = normalized_level_name;
|
||||
primary_level.level_name =
|
||||
normalize_required_string(&next_level_name).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -689,7 +663,7 @@ pub fn apply_publish_overrides_to_draft(
|
||||
|
||||
pub fn normalize_puzzle_levels(
|
||||
levels: Vec<PuzzleDraftLevel>,
|
||||
theme_tags: &[String],
|
||||
_theme_tags: &[String],
|
||||
) -> Result<Vec<PuzzleDraftLevel>, PuzzleFieldError> {
|
||||
let mut normalized_levels = Vec::new();
|
||||
for (index, mut level) in levels.into_iter().enumerate() {
|
||||
@@ -697,9 +671,7 @@ pub fn normalize_puzzle_levels(
|
||||
.unwrap_or_else(|| format!("puzzle-level-{}", index + 1));
|
||||
let picture_description = normalize_required_string(&level.picture_description)
|
||||
.unwrap_or_else(|| format!("第{}关画面", index + 1));
|
||||
let level_name = normalize_required_string(&level.level_name).unwrap_or_else(|| {
|
||||
build_level_name_from_picture(picture_description.as_str(), theme_tags, index + 1)
|
||||
});
|
||||
let level_name = normalize_required_string(&level.level_name).unwrap_or_default();
|
||||
level.level_id = level_id;
|
||||
level.level_name = level_name;
|
||||
level.picture_description = picture_description;
|
||||
@@ -1959,21 +1931,67 @@ fn build_result_summary(anchor_pack: &PuzzleAnchorPack) -> String {
|
||||
}
|
||||
|
||||
fn resolve_work_description(seed_text: Option<&str>, anchor_pack: &PuzzleAnchorPack) -> String {
|
||||
seed_text
|
||||
.and_then(parse_form_seed_text)
|
||||
.and_then(|parts| {
|
||||
parts
|
||||
.work_description
|
||||
.or(parts.picture_description)
|
||||
.or(parts.work_title)
|
||||
})
|
||||
.unwrap_or_else(|| build_result_summary(anchor_pack))
|
||||
if let Some(parts) = seed_text.and_then(parse_form_seed_text) {
|
||||
if parts.picture_description.is_some()
|
||||
&& parts.work_title.is_none()
|
||||
&& parts.work_description.is_none()
|
||||
{
|
||||
return String::new();
|
||||
}
|
||||
return parts
|
||||
.work_description
|
||||
.unwrap_or_else(|| build_result_summary(anchor_pack));
|
||||
}
|
||||
build_result_summary(anchor_pack)
|
||||
}
|
||||
|
||||
fn build_work_title(anchor_pack: &PuzzleAnchorPack) -> String {
|
||||
fallback_text(&anchor_pack.theme_promise.value, "奇景拼图")
|
||||
}
|
||||
|
||||
fn resolve_work_title(
|
||||
seed_text: Option<&str>,
|
||||
anchor_pack: &PuzzleAnchorPack,
|
||||
level_name: &str,
|
||||
) -> String {
|
||||
seed_text
|
||||
.and_then(parse_form_seed_text)
|
||||
.and_then(|parts| {
|
||||
parts
|
||||
.work_title
|
||||
.or_else(|| normalize_required_string(level_name))
|
||||
})
|
||||
.unwrap_or_else(|| build_work_title(anchor_pack))
|
||||
}
|
||||
|
||||
fn resolve_initial_theme_tags(
|
||||
seed_text: Option<&str>,
|
||||
creator_intent: &PuzzleCreatorIntent,
|
||||
) -> Vec<String> {
|
||||
if let Some(parts) = seed_text.and_then(parse_form_seed_text) {
|
||||
if parts.picture_description.is_some()
|
||||
&& parts.work_title.is_none()
|
||||
&& parts.work_description.is_none()
|
||||
{
|
||||
return Vec::new();
|
||||
}
|
||||
let derived_tags = normalize_theme_tags(derive_form_theme_tags(
|
||||
parts
|
||||
.work_title
|
||||
.as_deref()
|
||||
.unwrap_or(creator_intent.theme_promise.as_str()),
|
||||
parts
|
||||
.picture_description
|
||||
.as_deref()
|
||||
.unwrap_or(creator_intent.visual_subject.as_str()),
|
||||
));
|
||||
if !derived_tags.is_empty() {
|
||||
return derived_tags;
|
||||
}
|
||||
}
|
||||
normalize_theme_tags(creator_intent.theme_tags.clone())
|
||||
}
|
||||
|
||||
fn extract_forbidden_directive(source: &str) -> String {
|
||||
if let Some((_, tail)) = source.split_once(';') {
|
||||
return normalize_required_string(tail).unwrap_or_else(|| "禁止标题字".to_string());
|
||||
@@ -1996,7 +2014,7 @@ fn build_level_name_from_picture(
|
||||
}
|
||||
}
|
||||
if let Some(tag) = normalized_tags.first() {
|
||||
return format!("{tag}第{level_index}关");
|
||||
return format!("{tag}画面");
|
||||
}
|
||||
format!("第{level_index}关")
|
||||
}
|
||||
@@ -2912,6 +2930,23 @@ mod tests {
|
||||
assert!(draft.theme_tags.len() >= PUZZLE_MIN_TAG_COUNT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn picture_only_form_seed_uses_level_name_as_work_title_and_empty_metadata() {
|
||||
let seed_text = "画面描述:一只猫在雨夜灯牌下回头。";
|
||||
let anchor_pack = infer_anchor_pack(seed_text, None);
|
||||
let draft = compile_result_draft_from_seed(&anchor_pack, &[], Some(seed_text));
|
||||
|
||||
assert_eq!(draft.level_name, "猫画面");
|
||||
assert_eq!(draft.work_title, "猫画面");
|
||||
assert_eq!(draft.work_description, "");
|
||||
assert_eq!(draft.summary, "");
|
||||
assert!(draft.theme_tags.is_empty());
|
||||
assert_eq!(
|
||||
draft.levels[0].picture_description,
|
||||
"一只猫在雨夜灯牌下回头。"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn form_seed_keeps_multiline_picture_description() {
|
||||
let anchor_pack = infer_anchor_pack(
|
||||
@@ -3452,4 +3487,34 @@ mod tests {
|
||||
|
||||
assert_eq!(error, PuzzleFieldError::InvalidTagCount);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_publish_overrides_preserves_empty_level_name_for_publish_gate() {
|
||||
let anchor_pack = infer_anchor_pack("雨夜猫咪神庙", Some("雨夜猫咪神庙"));
|
||||
let draft = compile_result_draft(&anchor_pack, &[]);
|
||||
let mut levels = draft.levels.clone();
|
||||
levels[0].level_name = " ".to_string();
|
||||
|
||||
let updated = apply_publish_overrides_to_draft(
|
||||
&draft,
|
||||
Some("雨夜猫塔作品".to_string()),
|
||||
Some("作品描述。".to_string()),
|
||||
Some("".to_string()),
|
||||
Some("作品描述。".to_string()),
|
||||
Some(vec![
|
||||
"雨夜".to_string(),
|
||||
"猫咪".to_string(),
|
||||
"遗迹".to_string(),
|
||||
]),
|
||||
Some(levels),
|
||||
)
|
||||
.expect("empty level name should remain editable before publish gate");
|
||||
|
||||
assert_eq!(updated.levels[0].level_name, "");
|
||||
assert!(
|
||||
validate_publish_requirements(&updated, Some("玩家"))
|
||||
.iter()
|
||||
.any(|blocker| blocker.code == "MISSING_LEVEL_NAME")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user