Resolve spacetime client binding merge conflicts
This commit is contained in:
@@ -15,11 +15,25 @@ pub enum DraftFoundationPayloadError {
|
||||
InvalidGeneratedDraft(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CustomWorldFoundationDraftProgress {
|
||||
pub phase_label: String,
|
||||
pub phase_detail: String,
|
||||
pub progress: u32,
|
||||
}
|
||||
|
||||
pub async fn generate_custom_world_foundation_draft(
|
||||
llm_client: &LlmClient,
|
||||
session: &CustomWorldAgentSessionRecord,
|
||||
mut on_progress: impl FnMut(CustomWorldFoundationDraftProgress) + Send,
|
||||
) -> Result<CustomWorldFoundationDraftResult, String> {
|
||||
let setting_text = build_foundation_generation_seed_text(session);
|
||||
emit_foundation_draft_progress(
|
||||
&mut on_progress,
|
||||
"整理世界骨架",
|
||||
"正在根据创作者锚点生成第一版世界框架。",
|
||||
12,
|
||||
);
|
||||
let mut framework = request_foundation_json_stage(
|
||||
llm_client,
|
||||
build_custom_world_framework_prompt(setting_text.as_str()),
|
||||
@@ -36,6 +50,8 @@ pub async fn generate_custom_world_foundation_draft(
|
||||
&framework,
|
||||
"playable",
|
||||
FOUNDATION_DRAFT_PLAYABLE_COUNT,
|
||||
(16, 30),
|
||||
&mut on_progress,
|
||||
)
|
||||
.await?;
|
||||
framework["playableNpcs"] = JsonValue::Array(playable_outlines.clone());
|
||||
@@ -45,6 +61,8 @@ pub async fn generate_custom_world_foundation_draft(
|
||||
&framework,
|
||||
"story",
|
||||
FOUNDATION_DRAFT_STORY_COUNT,
|
||||
(30, 44),
|
||||
&mut on_progress,
|
||||
)
|
||||
.await?;
|
||||
framework["storyNpcs"] = JsonValue::Array(story_outlines.clone());
|
||||
@@ -53,6 +71,8 @@ pub async fn generate_custom_world_foundation_draft(
|
||||
llm_client,
|
||||
&framework,
|
||||
FOUNDATION_DRAFT_LANDMARK_COUNT,
|
||||
(44, 56),
|
||||
&mut on_progress,
|
||||
)
|
||||
.await?;
|
||||
framework["landmarks"] = JsonValue::Array(landmark_seeds.clone());
|
||||
@@ -62,6 +82,8 @@ pub async fn generate_custom_world_foundation_draft(
|
||||
&framework,
|
||||
&story_outlines,
|
||||
&landmark_seeds,
|
||||
(56, 66),
|
||||
&mut on_progress,
|
||||
)
|
||||
.await?;
|
||||
framework["landmarks"] = JsonValue::Array(landmarks.clone());
|
||||
@@ -72,6 +94,8 @@ pub async fn generate_custom_world_foundation_draft(
|
||||
"playable",
|
||||
&playable_outlines,
|
||||
"narrative",
|
||||
(66, 76),
|
||||
&mut on_progress,
|
||||
)
|
||||
.await?;
|
||||
let playable_detailed = expand_foundation_role_entries(
|
||||
@@ -80,6 +104,8 @@ pub async fn generate_custom_world_foundation_draft(
|
||||
"playable",
|
||||
&playable_narrative,
|
||||
"dossier",
|
||||
(76, 84),
|
||||
&mut on_progress,
|
||||
)
|
||||
.await?;
|
||||
let story_narrative = expand_foundation_role_entries(
|
||||
@@ -88,6 +114,8 @@ pub async fn generate_custom_world_foundation_draft(
|
||||
"story",
|
||||
&story_outlines,
|
||||
"narrative",
|
||||
(84, 92),
|
||||
&mut on_progress,
|
||||
)
|
||||
.await?;
|
||||
let story_detailed = expand_foundation_role_entries(
|
||||
@@ -96,9 +124,18 @@ pub async fn generate_custom_world_foundation_draft(
|
||||
"story",
|
||||
&story_narrative,
|
||||
"dossier",
|
||||
(92, 96),
|
||||
&mut on_progress,
|
||||
)
|
||||
.await?;
|
||||
|
||||
emit_foundation_draft_progress(
|
||||
&mut on_progress,
|
||||
"编译世界底稿",
|
||||
"正在把分批生成结果直接整理成第一版 foundation draft,并同步兼容结果快照。",
|
||||
97,
|
||||
);
|
||||
|
||||
let draft_profile = build_foundation_draft_profile_from_framework(
|
||||
framework,
|
||||
playable_detailed,
|
||||
@@ -166,6 +203,8 @@ async fn generate_foundation_role_outline_entries(
|
||||
framework: &JsonValue,
|
||||
role_type: &str,
|
||||
total_count: usize,
|
||||
progress_range: (u32, u32),
|
||||
on_progress: &mut (impl FnMut(CustomWorldFoundationDraftProgress) + Send),
|
||||
) -> Result<Vec<JsonValue>, String> {
|
||||
let mut merged_entries = Vec::new();
|
||||
let planned_batch_count = total_count
|
||||
@@ -178,6 +217,24 @@ async fn generate_foundation_role_outline_entries(
|
||||
let batch_count =
|
||||
(total_count - merged_entries.len()).min(FOUNDATION_ROLE_OUTLINE_BATCH_SIZE);
|
||||
let forbidden_names = names_from_entries(&merged_entries);
|
||||
let role_label = if role_type == "playable" {
|
||||
"可扮演角色"
|
||||
} else {
|
||||
"场景角色"
|
||||
};
|
||||
emit_foundation_draft_progress(
|
||||
on_progress,
|
||||
format!("生成{role_label}").as_str(),
|
||||
format!(
|
||||
"正在生成{role_label}第 {} / {} 批,当前已完成 {}/{}。",
|
||||
batch_index + 1,
|
||||
planned_batch_count,
|
||||
merged_entries.len(),
|
||||
total_count,
|
||||
)
|
||||
.as_str(),
|
||||
to_batch_progress(progress_range, merged_entries.len(), total_count),
|
||||
);
|
||||
let raw = request_foundation_json_stage(
|
||||
llm_client,
|
||||
build_custom_world_role_outline_batch_prompt(
|
||||
@@ -210,13 +267,27 @@ async fn generate_foundation_role_outline_entries(
|
||||
let key = role_key(role_type);
|
||||
merged_entries.extend(array_field(&raw, key).into_iter().take(batch_count));
|
||||
}
|
||||
Ok(merged_entries.into_iter().take(total_count).collect())
|
||||
let merged_entries: Vec<JsonValue> = merged_entries.into_iter().take(total_count).collect();
|
||||
let role_label = if role_type == "playable" {
|
||||
"可扮演角色"
|
||||
} else {
|
||||
"场景角色"
|
||||
};
|
||||
emit_foundation_draft_progress(
|
||||
on_progress,
|
||||
format!("生成{role_label}").as_str(),
|
||||
format!("{role_label}已经整理完成,共 {} 个。", merged_entries.len()).as_str(),
|
||||
progress_range.1,
|
||||
);
|
||||
Ok(merged_entries)
|
||||
}
|
||||
|
||||
async fn generate_foundation_landmark_seed_entries(
|
||||
llm_client: &LlmClient,
|
||||
framework: &JsonValue,
|
||||
total_count: usize,
|
||||
progress_range: (u32, u32),
|
||||
on_progress: &mut (impl FnMut(CustomWorldFoundationDraftProgress) + Send),
|
||||
) -> Result<Vec<JsonValue>, String> {
|
||||
let mut merged_entries = Vec::new();
|
||||
let planned_batch_count = total_count.div_ceil(FOUNDATION_LANDMARK_BATCH_SIZE).max(1);
|
||||
@@ -226,6 +297,19 @@ async fn generate_foundation_landmark_seed_entries(
|
||||
}
|
||||
let batch_count = (total_count - merged_entries.len()).min(FOUNDATION_LANDMARK_BATCH_SIZE);
|
||||
let forbidden_names = names_from_entries(&merged_entries);
|
||||
emit_foundation_draft_progress(
|
||||
on_progress,
|
||||
"生成关键场景",
|
||||
format!(
|
||||
"正在生成关键场景第 {} / {} 批,当前已完成 {}/{}。",
|
||||
batch_index + 1,
|
||||
planned_batch_count,
|
||||
merged_entries.len(),
|
||||
total_count,
|
||||
)
|
||||
.as_str(),
|
||||
to_batch_progress(progress_range, merged_entries.len(), total_count),
|
||||
);
|
||||
let raw = request_foundation_json_stage(
|
||||
llm_client,
|
||||
build_custom_world_landmark_seed_batch_prompt(framework, batch_count, &forbidden_names),
|
||||
@@ -247,7 +331,14 @@ async fn generate_foundation_landmark_seed_entries(
|
||||
.await?;
|
||||
merged_entries.extend(array_field(&raw, "landmarks").into_iter().take(batch_count));
|
||||
}
|
||||
Ok(merged_entries.into_iter().take(total_count).collect())
|
||||
let merged_entries: Vec<JsonValue> = merged_entries.into_iter().take(total_count).collect();
|
||||
emit_foundation_draft_progress(
|
||||
on_progress,
|
||||
"生成关键场景",
|
||||
format!("关键场景骨架已整理完成,共 {} 个。", merged_entries.len()).as_str(),
|
||||
progress_range.1,
|
||||
);
|
||||
Ok(merged_entries)
|
||||
}
|
||||
|
||||
async fn expand_foundation_landmark_network_entries(
|
||||
@@ -255,12 +346,28 @@ async fn expand_foundation_landmark_network_entries(
|
||||
framework: &JsonValue,
|
||||
story_npcs: &[JsonValue],
|
||||
base_entries: &[JsonValue],
|
||||
progress_range: (u32, u32),
|
||||
on_progress: &mut (impl FnMut(CustomWorldFoundationDraftProgress) + Send),
|
||||
) -> Result<Vec<JsonValue>, String> {
|
||||
let mut merged_entries = Vec::new();
|
||||
for (batch_index, batch) in base_entries
|
||||
let batches: Vec<&[JsonValue]> = base_entries
|
||||
.chunks(FOUNDATION_LANDMARK_BATCH_SIZE)
|
||||
.enumerate()
|
||||
{
|
||||
.collect();
|
||||
let mut processed_count = 0usize;
|
||||
for (batch_index, batch) in batches.iter().enumerate() {
|
||||
emit_foundation_draft_progress(
|
||||
on_progress,
|
||||
"建立场景连接",
|
||||
format!(
|
||||
"正在补全场景连接第 {} / {} 批,当前已完成 {}/{}。",
|
||||
batch_index + 1,
|
||||
batches.len(),
|
||||
processed_count,
|
||||
base_entries.len(),
|
||||
)
|
||||
.as_str(),
|
||||
to_batch_progress(progress_range, processed_count, base_entries.len()),
|
||||
);
|
||||
let raw = request_foundation_json_stage(
|
||||
llm_client,
|
||||
build_custom_world_landmark_network_batch_prompt(framework, story_npcs, batch),
|
||||
@@ -284,7 +391,16 @@ async fn expand_foundation_landmark_network_entries(
|
||||
)
|
||||
.await?;
|
||||
merged_entries.extend(array_field(&raw, "landmarks"));
|
||||
processed_count = processed_count
|
||||
.saturating_add(batch.len())
|
||||
.min(base_entries.len());
|
||||
}
|
||||
emit_foundation_draft_progress(
|
||||
on_progress,
|
||||
"建立场景连接",
|
||||
"关键场景的角色分布与路径连接已经整理完成。",
|
||||
progress_range.1,
|
||||
);
|
||||
Ok(merge_entries_by_name(base_entries, &merged_entries))
|
||||
}
|
||||
|
||||
@@ -294,13 +410,39 @@ async fn expand_foundation_role_entries(
|
||||
role_type: &str,
|
||||
base_entries: &[JsonValue],
|
||||
stage: &str,
|
||||
progress_range: (u32, u32),
|
||||
on_progress: &mut (impl FnMut(CustomWorldFoundationDraftProgress) + Send),
|
||||
) -> Result<Vec<JsonValue>, String> {
|
||||
let mut merged_entries = Vec::new();
|
||||
for (batch_index, batch) in base_entries
|
||||
let batches: Vec<&[JsonValue]> = base_entries
|
||||
.chunks(FOUNDATION_ROLE_DETAIL_BATCH_SIZE)
|
||||
.enumerate()
|
||||
{
|
||||
.collect();
|
||||
let mut processed_count = 0usize;
|
||||
for (batch_index, batch) in batches.iter().enumerate() {
|
||||
let expected_names = names_from_entries(batch);
|
||||
let role_label = if role_type == "playable" {
|
||||
"可扮演角色"
|
||||
} else {
|
||||
"场景角色"
|
||||
};
|
||||
let stage_label = if stage == "narrative" {
|
||||
"叙事基础"
|
||||
} else {
|
||||
"档案细节"
|
||||
};
|
||||
emit_foundation_draft_progress(
|
||||
on_progress,
|
||||
format!("补全{role_label}{stage_label}").as_str(),
|
||||
format!(
|
||||
"正在补全{role_label}{stage_label}第 {} / {} 批,当前已完成 {}/{}。",
|
||||
batch_index + 1,
|
||||
batches.len(),
|
||||
processed_count,
|
||||
base_entries.len(),
|
||||
)
|
||||
.as_str(),
|
||||
to_batch_progress(progress_range, processed_count, base_entries.len()),
|
||||
);
|
||||
let raw = request_foundation_json_stage(
|
||||
llm_client,
|
||||
build_custom_world_role_batch_prompt(framework, role_type, batch, stage),
|
||||
@@ -326,9 +468,51 @@ async fn expand_foundation_role_entries(
|
||||
)
|
||||
.await?;
|
||||
merged_entries.extend(array_field(&raw, role_key(role_type)));
|
||||
processed_count = processed_count
|
||||
.saturating_add(batch.len())
|
||||
.min(base_entries.len());
|
||||
}
|
||||
let role_label = if role_type == "playable" {
|
||||
"可扮演角色"
|
||||
} else {
|
||||
"场景角色"
|
||||
};
|
||||
let stage_label = if stage == "narrative" {
|
||||
"叙事基础"
|
||||
} else {
|
||||
"档案细节"
|
||||
};
|
||||
emit_foundation_draft_progress(
|
||||
on_progress,
|
||||
format!("补全{role_label}{stage_label}").as_str(),
|
||||
format!("{role_label}{stage_label}已经整理完成。").as_str(),
|
||||
progress_range.1,
|
||||
);
|
||||
Ok(merge_entries_by_name(base_entries, &merged_entries))
|
||||
}
|
||||
|
||||
fn emit_foundation_draft_progress(
|
||||
on_progress: &mut (impl FnMut(CustomWorldFoundationDraftProgress) + Send),
|
||||
phase_label: &str,
|
||||
phase_detail: &str,
|
||||
progress: u32,
|
||||
) {
|
||||
on_progress(CustomWorldFoundationDraftProgress {
|
||||
phase_label: phase_label.to_string(),
|
||||
phase_detail: phase_detail.to_string(),
|
||||
progress: progress.min(100),
|
||||
});
|
||||
}
|
||||
|
||||
fn to_batch_progress(progress_range: (u32, u32), completed: usize, total: usize) -> u32 {
|
||||
if total == 0 {
|
||||
return progress_range.1;
|
||||
}
|
||||
let start = progress_range.0 as f64;
|
||||
let end = progress_range.1 as f64;
|
||||
let ratio = (completed as f64 / total as f64).clamp(0.0, 1.0);
|
||||
(start + (end - start) * ratio).round().clamp(0.0, 100.0) as u32
|
||||
}
|
||||
// foundation draft 已经由 api-server 真实生成,落库前只负责把它注入现有 action payload。
|
||||
pub fn build_draft_foundation_action_payload_json(
|
||||
payload: &ExecuteCustomWorldAgentActionRequest,
|
||||
@@ -1528,7 +1712,7 @@ mod tests {
|
||||
let llm_client = build_test_llm_client(server_url);
|
||||
let session = build_test_session();
|
||||
|
||||
let result = generate_custom_world_foundation_draft(&llm_client, &session)
|
||||
let result = generate_custom_world_foundation_draft(&llm_client, &session, |_| {})
|
||||
.await
|
||||
.expect("draft generation should succeed");
|
||||
let draft_profile = serde_json::from_str::<JsonValue>(&result.draft_profile_json)
|
||||
|
||||
Reference in New Issue
Block a user