1
This commit is contained in:
@@ -6,7 +6,7 @@ pub(crate) fn build_custom_world_framework_prompt(setting_text: &str) -> String
|
||||
[
|
||||
"请先根据下面的玩家设定创建一份“世界核心骨架”,后续我会分步骤生成角色名单、场景名单和详细档案。".to_string(),
|
||||
"你必须只输出一个能被 JSON.parse 直接解析的 JSON 对象,不要输出 Markdown、代码块、注释或解释。".to_string(),
|
||||
"这一步只保留世界顶层信息与一个开局归处场景,不要输出 playableNpcs、storyNpcs、landmarks,也不要展开人物和地图细节。".to_string(),
|
||||
"这一步只保留世界顶层信息与一个开局归处占位,不要输出 playableNpcs、storyNpcs、landmarks,也不要展开人物、地图细节或多幕场景内容。".to_string(),
|
||||
"玩家设定:".to_string(),
|
||||
setting_text.trim().to_string(),
|
||||
"".to_string(),
|
||||
@@ -33,10 +33,7 @@ pub(crate) fn build_custom_world_framework_prompt(setting_text: &str) -> String
|
||||
" },".to_string(),
|
||||
" \"camp\": {".to_string(),
|
||||
" \"name\": \"开局归处名称\",".to_string(),
|
||||
" \"description\": \"这是玩家进入世界后的第一处落脚点描述\",".to_string(),
|
||||
" \"sceneTaskDescription\": \"首次进入该场景时要生成的章节任务核心上下文\",".to_string(),
|
||||
" \"actBackgroundPromptTexts\": [\"开局第一幕背景画面描述\", \"开局第二幕背景画面描述\", \"开局第三幕背景画面描述\"],".to_string(),
|
||||
" \"actEventDescriptions\": [\"开局第一幕事件描述\", \"开局第二幕事件描述\", \"开局第三幕事件描述\"],".to_string(),
|
||||
" \"description\": \"这是玩家进入世界后的第一处落脚点描述\"".to_string(),
|
||||
" }".to_string(),
|
||||
"}".to_string(),
|
||||
"".to_string(),
|
||||
@@ -45,10 +42,7 @@ pub(crate) fn build_custom_world_framework_prompt(setting_text: &str) -> String
|
||||
"- 这一步只输出顶层 10 个字段:name、subtitle、summary、tone、playerGoal、templateWorldType、majorFactions、coreConflicts、attributeSchema、camp。".to_string(),
|
||||
"- 这是一个完全独立的自定义世界;不要在任何正文里直接写出“武侠世界”“仙侠世界”等现成世界名。".to_string(),
|
||||
"- templateWorldType 只是系统兼容字段,不代表正文应当引用的世界名称。".to_string(),
|
||||
"- camp 必须表示玩家开局时的落脚处,更接近归舍、住处、栖居、前哨居所这类“家/归处”的概念。".to_string(),
|
||||
"- camp.sceneTaskDescription 必须描述玩家首次进入开局场景时要完成的核心任务,会作为游戏章节任务生成上下文,控制在 24 到 56 个汉字内。".to_string(),
|
||||
"- camp.actEventDescriptions 必须恰好 3 条,分别描述每一幕发生的事件;第 1 幕负责铺垫,第 2 幕必须让冲突升级,第 3 幕必须形成高潮或关键抉择;事件必须和当前幕对面的角色强相关,控制在 24 到 56 个汉字内。".to_string(),
|
||||
"- camp.actBackgroundPromptTexts 必须恰好 3 条,分别对应第 1/2/3 幕背景图画面内容描述;每条必须基于同序号 actEventDescriptions 和相关角色写出画面主体、站位空间、冲突痕迹与氛围,能直接交给生图模型,控制在 40 到 90 个汉字内。".to_string(),
|
||||
"- camp 只表示玩家开局时的落脚处占位,更接近归舍、住处、栖居、前哨居所这类“家/归处”的概念;不要在这一步生成开局场景任务、三幕事件或三幕背景。".to_string(),
|
||||
"- 不要输出 playableNpcs、storyNpcs、landmarks、items,也不要输出任何角色和地图细节。".to_string(),
|
||||
"- majorFactions 保持 2 到 3 个,coreConflicts 保持 2 到 3 个。".to_string(),
|
||||
"- attributeSchema 必须是本世界专属的角色六维属性体系,slots 必须恰好 6 个,slotId 固定为 axis_a 到 axis_f,维度名必须是 2 到 4 个汉字且互不重复。".to_string(),
|
||||
@@ -68,7 +62,7 @@ pub(crate) fn build_custom_world_framework_json_repair_prompt(response_text: &st
|
||||
"不要输出 playableNpcs、storyNpcs、landmarks、items 或任何其他字段。",
|
||||
"majorFactions 与 coreConflicts 必须是字符串数组。",
|
||||
"attributeSchema 必须是对象,且包含 schemaName 与 slots;slots 必须恰好 6 个,slotId 固定为 axis_a 到 axis_f。",
|
||||
"camp 必须是对象,且包含:name、description、sceneTaskDescription、actBackgroundPromptTexts、actEventDescriptions。",
|
||||
"camp 必须是对象,且只包含:name、description。",
|
||||
"原始文本:",
|
||||
response_text.trim(),
|
||||
].join("\n")
|
||||
@@ -154,16 +148,26 @@ pub(crate) fn build_custom_world_landmark_seed_batch_prompt(
|
||||
framework: &JsonValue,
|
||||
batch_count: usize,
|
||||
forbidden_names: &[String],
|
||||
is_opening_batch: bool,
|
||||
) -> String {
|
||||
let story_npc_names = names_from_entries(&array_field(framework, "storyNpcs"));
|
||||
[
|
||||
"请根据下面的世界核心信息,生成一批关键场景框架名单。".to_string(),
|
||||
"这一步必须一次性生成场景骨架、地点默认生图描述、逐幕背景描述、幕 NPC 分配和相连场景信息。".to_string(),
|
||||
"请根据下面的世界核心信息,批量生成场景框架名单。".to_string(),
|
||||
if is_opening_batch {
|
||||
"这一步必须一次性生成开局场景和普通关键场景的场景骨架、默认生图描述、逐幕背景描述、幕 NPC 分配和相连场景信息。".to_string()
|
||||
} else {
|
||||
"这一步必须一次性生成普通关键场景的场景骨架、默认生图描述、逐幕背景描述、幕 NPC 分配和相连场景信息。".to_string()
|
||||
},
|
||||
"你必须只输出一个能被 JSON.parse 直接解析的 JSON 对象,不要输出 Markdown、代码块、注释或解释。".to_string(),
|
||||
"世界核心信息:".to_string(),
|
||||
build_framework_summary_text(framework, 0),
|
||||
if story_npc_names.is_empty() { "".to_string() } else { format!("可用场景角色名单:{}", story_npc_names.join("、")) },
|
||||
if forbidden_names.is_empty() { "".to_string() } else { format!("这些地点已经生成,禁止重复:{}", forbidden_names.join("、")) },
|
||||
if is_opening_batch {
|
||||
"第一条场景必须是玩家进入世界时所在的开局场景,后续条目才是普通关键场景。".to_string()
|
||||
} else {
|
||||
"本批只生成普通关键场景,不要再生成开局场景。".to_string()
|
||||
},
|
||||
if forbidden_names.is_empty() { "".to_string() } else { format!("这些场景已经生成,禁止重复:{}", forbidden_names.join("、")) },
|
||||
"".to_string(),
|
||||
"输出 JSON 模板:".to_string(),
|
||||
"{".to_string(),
|
||||
@@ -183,16 +187,21 @@ pub(crate) fn build_custom_world_landmark_seed_batch_prompt(
|
||||
"}".to_string(),
|
||||
"".to_string(),
|
||||
"要求:".to_string(),
|
||||
format!("- 必须生成恰好 {batch_count} 个关键场景。"),
|
||||
"- 这是一个完全独立的自定义世界;地点名称必须直接服务玩家输入主题。".to_string(),
|
||||
"- 名称必须具体且互不重复,不要使用 地点1、场景1 之类的占位名。".to_string(),
|
||||
"- 每个地点只保留:name、description、visualDescription、sceneTaskDescription、actBackgroundPromptTexts、actEventDescriptions、actNPCNames、connectedLandmarkNames、entryHook。".to_string(),
|
||||
if is_opening_batch {
|
||||
format!("- 必须生成恰好 {batch_count} 个场景,第 1 个必须是开局场景。")
|
||||
} else {
|
||||
format!("- 必须生成恰好 {batch_count} 个普通关键场景,不能包含开局场景。")
|
||||
},
|
||||
if is_opening_batch { "- 开局场景也必须按普通场景同级规则生成完整字段,不能只给 camp 简介。".to_string() } else { "".to_string() },
|
||||
"- 这是一个完全独立的自定义世界;场景名称必须直接服务玩家输入主题。".to_string(),
|
||||
"- 名称必须具体且互不重复,不要使用 地点1、场景1、开局场景 之类的占位名。".to_string(),
|
||||
"- 每个场景只保留:name、description、visualDescription、sceneTaskDescription、actBackgroundPromptTexts、actEventDescriptions、actNPCNames、connectedLandmarkNames、entryHook。".to_string(),
|
||||
"- sceneTaskDescription 必须描述玩家首次进入该场景时要完成的核心任务,会作为游戏章节任务生成上下文,控制在 24 到 56 个汉字内。".to_string(),
|
||||
"- visualDescription 是打开场景背景图像生成面板时默认填入的场景描述,必须具体到画面主体、远近景层次、地面可站立区域和氛围识别点,控制在 32 到 80 个汉字内。".to_string(),
|
||||
"- actNPCNames 只能引用上方可用场景角色名单中的名字,表示第 1/2/3 幕各自的主场景角色;如果名单为空,输出空数组。".to_string(),
|
||||
"- 可用场景角色名单非空时,actNPCNames 必须恰好 3 个;可以重复使用同一角色,但每一项都必须服务对应幕事件。".to_string(),
|
||||
"- actNPCNames[n] 会成为第 n+1 幕对面主角色;三幕事件和幕背景必须围绕对应角色的行动、阻碍、试探或求助展开。".to_string(),
|
||||
"- connectedLandmarkNames 优先引用本批或已知关键场景名称,每个地点 1 到 3 个;只有 1 个地点时可以输出空数组。".to_string(),
|
||||
"- connectedLandmarkNames 优先引用本批或已知场景名称,每个场景 1 到 3 个;只有 1 个场景时可以输出空数组。".to_string(),
|
||||
"- entryHook 控制在 16 到 36 个汉字内。".to_string(),
|
||||
"- actEventDescriptions 必须恰好 3 条,分别描述每一幕发生的事件;第 1 幕负责铺垫,第 2 幕必须让冲突升级,第 3 幕必须形成高潮或关键抉择;事件必须和当前幕对面的角色强相关,控制在 24 到 56 个汉字内。".to_string(),
|
||||
"- actBackgroundPromptTexts 必须恰好 3 条,分别对应这个场景章节的第 1/2/3 幕背景图画面内容描述;每条都必须基于同序号 actEventDescriptions、当前地点和可出场角色直接写出画面主体、站位空间、冲突痕迹与氛围,控制在 40 到 90 个汉字内。".to_string(),
|
||||
@@ -207,14 +216,16 @@ pub(crate) fn build_custom_world_landmark_seed_batch_json_repair_prompt(
|
||||
response_text: &str,
|
||||
expected_count: usize,
|
||||
forbidden_names: &[String],
|
||||
is_opening_batch: bool,
|
||||
) -> String {
|
||||
[
|
||||
"下面这段文本本应是自定义世界关键场景框架名单批次的单个 JSON 对象,但当前不能被 JSON.parse 直接解析。".to_string(),
|
||||
"下面这段文本本应是自定义世界场景框架名单批次的单个 JSON 对象,但当前不能被 JSON.parse 直接解析。".to_string(),
|
||||
"请只输出修复后的 JSON 对象。".to_string(),
|
||||
"顶层必须只包含一个 landmarks 数组。".to_string(),
|
||||
format!("必须保留恰好 {expected_count} 个地点对象。"),
|
||||
format!("必须保留恰好 {expected_count} 个场景对象。"),
|
||||
if is_opening_batch { "第一项必须是开局场景,且字段粒度与普通场景一致。".to_string() } else { "本批只保留普通关键场景,不要包含开局场景。".to_string() },
|
||||
if forbidden_names.is_empty() { "".to_string() } else { format!("禁止使用这些重复名:{}。", forbidden_names.join("、")) },
|
||||
"每个地点只包含:name、description、visualDescription、sceneTaskDescription、actBackgroundPromptTexts、actEventDescriptions、actNPCNames、connectedLandmarkNames、entryHook。".to_string(),
|
||||
"每个场景只包含:name、description、visualDescription、sceneTaskDescription、actBackgroundPromptTexts、actEventDescriptions、actNPCNames、connectedLandmarkNames、entryHook。".to_string(),
|
||||
"如果缺少字段:字符串补空字符串,actBackgroundPromptTexts、actEventDescriptions、actNPCNames 和 connectedLandmarkNames 补空数组。".to_string(),
|
||||
"不要输出 items 或任何其他字段。".to_string(),
|
||||
"原始文本:".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user