/// 拼图作品草稿生成动作的提示词主源。 /// /// 拼图结果页草稿本体仍由 SpacetimeDB reducer 按表单/锚点确定性编译; /// 这里收口 api-server 在生成草稿前后需要写入 reducer 的表单 seed 文本, /// 以及草稿首图生成时的 prompt 来源选择,避免业务路由直接拼提示词文本。 #[derive(Clone, Copy, Debug, Default)] pub(crate) struct PuzzleFormSeedPromptParts<'a> { pub(crate) title: Option<&'a str>, pub(crate) work_description: Option<&'a str>, pub(crate) picture_description: Option<&'a str>, } /// 将填表式拼图输入编译成 SpacetimeDB 可恢复的表单 seed prompt。 pub(crate) fn build_puzzle_form_seed_prompt(parts: PuzzleFormSeedPromptParts<'_>) -> String { [ ("作品名称", normalize_prompt_part(parts.title)), ("作品描述", normalize_prompt_part(parts.work_description)), ("画面描述", normalize_prompt_part(parts.picture_description)), ] .into_iter() .filter_map(|(label, value)| value.map(|value| format!("{label}:{value}"))) .collect::>() .join("\n") } /// 生成作品草稿时,首图 prompt 优先使用玩家当前表单里的画面描述。 pub(crate) fn resolve_puzzle_draft_cover_prompt( explicit_prompt: Option<&str>, level_picture_description: &str, draft_summary: &str, ) -> String { normalize_prompt_part(explicit_prompt) .or_else(|| normalize_prompt_part(Some(level_picture_description))) .or_else(|| normalize_prompt_part(Some(draft_summary))) .unwrap_or_default() .to_string() } /// 结果页单关重新生成时,优先使用面板当前编辑态 prompt,再回退关卡画面描述。 pub(crate) fn resolve_puzzle_level_image_prompt( explicit_prompt: Option<&str>, level_picture_description: &str, draft_summary: &str, ) -> String { normalize_prompt_part(explicit_prompt) .or_else(|| normalize_prompt_part(Some(level_picture_description))) .or_else(|| normalize_prompt_part(Some(draft_summary))) .unwrap_or_default() .to_string() } fn normalize_prompt_part(value: Option<&str>) -> Option<&str> { value.map(str::trim).filter(|value| !value.is_empty()) } #[cfg(test)] mod tests { use super::*; #[test] fn form_seed_prompt_keeps_only_user_visible_fields() { let prompt = build_puzzle_form_seed_prompt(PuzzleFormSeedPromptParts { title: None, work_description: None, picture_description: Some("猫咪在灯牌下回头"), }); assert_eq!(prompt, "画面描述:猫咪在灯牌下回头"); } #[test] fn draft_cover_prompt_prefers_current_picture_description() { let prompt = resolve_puzzle_draft_cover_prompt(Some(" 当前表单画面 "), "旧关卡画面", "作品简介"); assert_eq!(prompt, "当前表单画面"); } #[test] fn level_image_prompt_falls_back_to_level_description() { let prompt = resolve_puzzle_level_image_prompt(Some(" "), "关卡画面描述", "作品简介"); assert_eq!(prompt, "关卡画面描述"); } #[test] fn level_image_prompt_falls_back_to_draft_summary_like_initial_cover() { let prompt = resolve_puzzle_level_image_prompt(Some(" "), " ", "作品简介"); assert_eq!(prompt, "作品简介"); } }