From 5b60ed12eaa00a46d8e75357985cf990abcdbe60 Mon Sep 17 00:00:00 2001 From: wangwei Date: Tue, 16 Jun 2026 16:27:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20add=20LLM=20role-assignment=20panel=20t?= =?UTF-8?q?o=20=E6=96=B0=E5=BB=BA=E8=AF=84=E4=BC=B0=20view?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapp/static/js/runner.js | 56 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/webapp/static/js/runner.js b/webapp/static/js/runner.js index b448f03..c524e1d 100644 --- a/webapp/static/js/runner.js +++ b/webapp/static/js/runner.js @@ -1,8 +1,9 @@ -// runner.js — 新建评估视图:列出场景、触发评估、轮询任务状态与日志。 +// runner.js — 新建评估视图:列出场景、LLM角色配置、触发评估、轮询任务状态与日志。 const Runner = { selectedScenario: null, pollTimer: null, + lastRunId: null, // 绑定运行按钮。 init() { @@ -32,6 +33,27 @@ const Runner = { } catch (err) { list.innerHTML = `

加载失败:${App.escape(err.message)}

`; } + // 同时加载 profiles 供角色选择 + Runner._populateProfileSelects(); + }, + + // 填充三个角色下拉框 + async _populateProfileSelects() { + const cached = Profiles.getAll(); + const profiles = cached.length > 0 + ? cached + : (await API.profiles().catch(() => ({ profiles: [] }))).profiles; + + ["role-judge", "role-answer", "role-dataset"].forEach(id => { + const sel = document.getElementById(id); + sel.innerHTML = ''; + profiles.forEach(p => { + const opt = document.createElement("option"); + opt.value = p.profile_id; + opt.textContent = `${p.name} (${p.model})`; + sel.appendChild(opt); + }); + }); }, // 构造单个场景条目。 @@ -64,12 +86,14 @@ const Runner = { Runner.selectedScenario = sc.path; document.getElementById("selected-scenario").textContent = sc.path; document.getElementById("run-btn").disabled = false; + // 显示 LLM 角色面板 + document.getElementById("llm-assignment-panel").hidden = false; }); } return item; }, - // 触发评估并开始轮询。 + // 触发评估:先 apply profiles(若选了),再触发任务。 async trigger() { if (!Runner.selectedScenario) return; const runBtn = document.getElementById("run-btn"); @@ -85,15 +109,41 @@ const Runner = { Runner._setStatus(statusBadge, "queued"); try { + // Step 1: apply LLM profiles to YAML if any selected + await Runner._applyProfilesIfNeeded(logBox); + + // Step 2: trigger evaluation const resp = await API.triggerEvaluation(Runner.selectedScenario); Runner.poll(resp.task_id); } catch (err) { Runner._setStatus(statusBadge, "failed"); - logBox.textContent = `触发失败:${err.message}`; + logBox.textContent = (logBox.textContent ? logBox.textContent + "\n" : "") + `触发失败:${err.message}`; runBtn.disabled = false; } }, + // 如果用户选了 profile,就先 apply 写回 YAML + async _applyProfilesIfNeeded(logBox) { + const judgeId = document.getElementById("role-judge").value; + const answerId = document.getElementById("role-answer").value; + const datasetId = document.getElementById("role-dataset").value; + + if (!judgeId && !answerId && !datasetId) return; // 全空,跳过 + + logBox.textContent = "正在将 LLM 配置写入场景文件…\n"; + const body = { + scenario_path: Runner.selectedScenario, + judge_profile_id: judgeId || null, + answer_profile_id: answerId || null, + dataset_profile_id: datasetId || null, + }; + const result = await API.applyProfiles(body); + const fields = (result.patched_fields || []).join(", "); + logBox.textContent += fields + ? `✓ 已更新字段:${fields}\n` + : "(未找到可更新的字段,继续运行)\n"; + }, + // 周期性轮询任务状态,刷新日志与徽标。 poll(taskId) { const logBox = document.getElementById("task-log");