Enhance simulation preparation process and frontend display for improved user experience
- Added synchronous retrieval of entity count before starting background tasks in simulation.py, allowing immediate access to expected agent totals for the frontend. - Updated the simulation state to include expected entity count and types, enhancing the information available during preparation. - Modified Step2EnvSetup.vue to display a pending status when the simulation is in progress and adjusted the simulation rounds configuration to dynamically reflect calculated values. - Improved the slider for custom rounds to ensure it adapts to the auto-generated maximum rounds, enhancing usability and clarity.
This commit is contained in:
parent
c287fe71fc
commit
4345f3085e
2 changed files with 49 additions and 17 deletions
|
|
@ -467,6 +467,25 @@ def prepare_simulation():
|
||||||
use_llm_for_profiles = data.get('use_llm_for_profiles', True)
|
use_llm_for_profiles = data.get('use_llm_for_profiles', True)
|
||||||
parallel_profile_count = data.get('parallel_profile_count', 5)
|
parallel_profile_count = data.get('parallel_profile_count', 5)
|
||||||
|
|
||||||
|
# ========== 同步获取实体数量(在后台任务启动前) ==========
|
||||||
|
# 这样前端在调用prepare后立即就能获取到预期Agent总数
|
||||||
|
try:
|
||||||
|
logger.info(f"同步获取实体数量: graph_id={state.graph_id}")
|
||||||
|
reader = ZepEntityReader()
|
||||||
|
# 快速读取实体(不需要边信息,只统计数量)
|
||||||
|
filtered_preview = reader.filter_defined_entities(
|
||||||
|
graph_id=state.graph_id,
|
||||||
|
defined_entity_types=entity_types_list,
|
||||||
|
enrich_with_edges=False # 不获取边信息,加快速度
|
||||||
|
)
|
||||||
|
# 保存实体数量到状态(供前端立即获取)
|
||||||
|
state.entities_count = filtered_preview.filtered_count
|
||||||
|
state.entity_types = list(filtered_preview.entity_types)
|
||||||
|
logger.info(f"预期实体数量: {filtered_preview.filtered_count}, 类型: {filtered_preview.entity_types}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"同步获取实体数量失败(将在后台任务中重试): {e}")
|
||||||
|
# 失败不影响后续流程,后台任务会重新获取
|
||||||
|
|
||||||
# 创建异步任务
|
# 创建异步任务
|
||||||
task_manager = TaskManager()
|
task_manager = TaskManager()
|
||||||
task_id = task_manager.create_task(
|
task_id = task_manager.create_task(
|
||||||
|
|
@ -477,7 +496,7 @@ def prepare_simulation():
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# 更新模拟状态
|
# 更新模拟状态(包含预先获取的实体数量)
|
||||||
state.status = SimulationStatus.PREPARING
|
state.status = SimulationStatus.PREPARING
|
||||||
manager._save_simulation_state(state)
|
manager._save_simulation_state(state)
|
||||||
|
|
||||||
|
|
@ -594,7 +613,9 @@ def prepare_simulation():
|
||||||
"task_id": task_id,
|
"task_id": task_id,
|
||||||
"status": "preparing",
|
"status": "preparing",
|
||||||
"message": "准备任务已启动,请通过 /api/simulation/prepare/status 查询进度",
|
"message": "准备任务已启动,请通过 /api/simulation/prepare/status 查询进度",
|
||||||
"already_prepared": False
|
"already_prepared": False,
|
||||||
|
"expected_entities_count": state.entities_count, # 预期的Agent总数
|
||||||
|
"entity_types": state.entity_types # 实体类型列表
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -427,6 +427,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="step-status">
|
<div class="step-status">
|
||||||
<span v-if="phase >= 4" class="badge processing">进行中</span>
|
<span v-if="phase >= 4" class="badge processing">进行中</span>
|
||||||
|
<span v-else class="badge pending">等待</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -434,8 +435,8 @@
|
||||||
<p class="api-note">POST /api/simulation/start</p>
|
<p class="api-note">POST /api/simulation/start</p>
|
||||||
<p class="description">模拟环境已准备完成,可以开始运行模拟</p>
|
<p class="description">模拟环境已准备完成,可以开始运行模拟</p>
|
||||||
|
|
||||||
<!-- 模拟轮数配置 -->
|
<!-- 模拟轮数配置 - 只有在配置生成完成且轮数计算出来后才显示 -->
|
||||||
<div class="rounds-config-section">
|
<div v-if="simulationConfig && autoGeneratedRounds" class="rounds-config-section">
|
||||||
<div class="rounds-header">
|
<div class="rounds-header">
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<span class="section-title">模拟轮数设定</span>
|
<span class="section-title">模拟轮数设定</span>
|
||||||
|
|
@ -465,10 +466,10 @@
|
||||||
type="range"
|
type="range"
|
||||||
v-model.number="customMaxRounds"
|
v-model.number="customMaxRounds"
|
||||||
min="10"
|
min="10"
|
||||||
max="120"
|
:max="autoGeneratedRounds"
|
||||||
step="5"
|
step="5"
|
||||||
class="minimal-slider"
|
class="minimal-slider"
|
||||||
:style="{ '--percent': ((customMaxRounds - 10) / (120 - 10)) * 100 + '%' }"
|
:style="{ '--percent': ((customMaxRounds - 10) / (autoGeneratedRounds - 10)) * 100 + '%' }"
|
||||||
/>
|
/>
|
||||||
<div class="range-marks">
|
<div class="range-marks">
|
||||||
<span>10</span>
|
<span>10</span>
|
||||||
|
|
@ -476,9 +477,9 @@
|
||||||
class="mark-recommend"
|
class="mark-recommend"
|
||||||
:class="{ active: customMaxRounds === 40 }"
|
:class="{ active: customMaxRounds === 40 }"
|
||||||
@click="customMaxRounds = 40"
|
@click="customMaxRounds = 40"
|
||||||
:style="{ position: 'absolute', left: 'calc(27.27% - 30px)' }"
|
:style="{ position: 'absolute', left: `calc(${(40 - 10) / (autoGeneratedRounds - 10) * 100}% - 30px)` }"
|
||||||
>40 (推荐)</span>
|
>40 (推荐)</span>
|
||||||
<span>120</span>
|
<span>{{ autoGeneratedRounds }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -665,7 +666,6 @@ const showProfilesDetail = ref(true)
|
||||||
// 模拟轮数配置
|
// 模拟轮数配置
|
||||||
const useCustomRounds = ref(false) // 默认使用自动配置轮数
|
const useCustomRounds = ref(false) // 默认使用自动配置轮数
|
||||||
const customMaxRounds = ref(40) // 默认推荐40轮
|
const customMaxRounds = ref(40) // 默认推荐40轮
|
||||||
const autoGeneratedRounds = ref(120) // 自动生成的轮数(从配置中读取)
|
|
||||||
|
|
||||||
// Watch stage to update phase
|
// Watch stage to update phase
|
||||||
watch(currentStage, (newStage) => {
|
watch(currentStage, (newStage) => {
|
||||||
|
|
@ -683,15 +683,20 @@ watch(currentStage, (newStage) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Watch simulationConfig to update autoGeneratedRounds
|
// 从配置中计算自动生成的轮数(不使用硬编码默认值)
|
||||||
watch(simulationConfig, (newConfig) => {
|
const autoGeneratedRounds = computed(() => {
|
||||||
if (newConfig?.time_config) {
|
if (!simulationConfig.value?.time_config) {
|
||||||
const totalHours = newConfig.time_config.total_simulation_hours || 120
|
return null // 配置未生成时返回 null
|
||||||
const minutesPerRound = newConfig.time_config.minutes_per_round || 60
|
|
||||||
const calculatedRounds = Math.floor((totalHours * 60) / minutesPerRound)
|
|
||||||
autoGeneratedRounds.value = calculatedRounds || 120
|
|
||||||
}
|
}
|
||||||
}, { immediate: true })
|
const totalHours = simulationConfig.value.time_config.total_simulation_hours
|
||||||
|
const minutesPerRound = simulationConfig.value.time_config.minutes_per_round
|
||||||
|
if (!totalHours || !minutesPerRound) {
|
||||||
|
return null // 配置数据不完整时返回 null
|
||||||
|
}
|
||||||
|
const calculatedRounds = Math.floor((totalHours * 60) / minutesPerRound)
|
||||||
|
// 确保最大轮数不小于40(推荐值),避免滑动条范围异常
|
||||||
|
return Math.max(calculatedRounds, 40)
|
||||||
|
})
|
||||||
|
|
||||||
// Polling timer
|
// Polling timer
|
||||||
let pollTimer = null
|
let pollTimer = null
|
||||||
|
|
@ -786,6 +791,12 @@ const startPrepareSimulation = async () => {
|
||||||
taskId.value = res.data.task_id
|
taskId.value = res.data.task_id
|
||||||
addLog(`准备任务已启动: ${res.data.task_id}`)
|
addLog(`准备任务已启动: ${res.data.task_id}`)
|
||||||
|
|
||||||
|
// 立即设置预期Agent总数(从prepare接口返回值获取)
|
||||||
|
if (res.data.expected_entities_count) {
|
||||||
|
expectedTotal.value = res.data.expected_entities_count
|
||||||
|
addLog(`预期Agent总数: ${res.data.expected_entities_count}`)
|
||||||
|
}
|
||||||
|
|
||||||
// 开始轮询进度
|
// 开始轮询进度
|
||||||
startPolling()
|
startPolling()
|
||||||
// 开始实时获取 Profiles
|
// 开始实时获取 Profiles
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue