Files
Genarrative/server-rs/crates/api-server/src/prompt/puzzle/draft.rs
高物 ae014ac881 Switch to VectorEngine gpt-image-2 and edits
Replace uses of the legacy `gpt-image-2-all` model with `gpt-image-2` and standardize image workflows: no-reference generation uses POST /v1/images/generations, any-reference flows use POST /v1/images/edits with multipart `image` parts. Update SKILLs, generation scripts, decision logs, and docs to reflect the contract change and edits-vs-generations guidance. Apply corresponding changes across backend (api-server match3d/puzzle modules, openai image adapter, mappers, telemetry, spacetime client/module), frontend components and services (Match3D, Puzzle, CreativeImageInputPanel, runtime shells), and add new spritesheet/parser files and tests. Also add media/logo.png. These changes align repository code and documentation with the VectorEngine image API contract and update generation/upload handling (green-screen -> alpha processing, spritesheet handling, and related tests).
2026-05-22 03:06:41 +08:00

93 lines
3.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// 拼图作品草稿生成动作的提示词主源。
///
/// 拼图结果页草稿本体仍由 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::<Vec<_>>()
.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, "作品简介");
}
}