Files
siemens_ragas/webapp/static/js/profiles.js
wangwei 1dc7ab9727 fix: restore LLM profile test connectivity buttons (lost from git)
Frontend test functionality was implemented but never committed to git.
Re-adds:
- profiles.js: testCard(), testForm(), _showTestResult(), test btn in renderCard
- api.js: testProfile(id) and probeConnectivity(body) methods
- index.html: 测试连通性 button + result div in profile form
- app.css: .btn-test and .profile-test-result styles

Backend /probe and /{id}/test endpoints were already present in llm_profiles.py.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 13:58:43 +08:00

184 lines
7.2 KiB
JavaScript
Raw Permalink 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.

// profiles.js — LLM 配置管理页面逻辑
const Profiles = {
_data: [],
// 初始化:绑定按钮事件
init() {
document.getElementById("add-profile-btn").addEventListener("click", () => Profiles.showForm());
document.getElementById("save-profile-btn").addEventListener("click", () => Profiles.save());
document.getElementById("cancel-profile-btn").addEventListener("click", () => Profiles.hideForm());
document.getElementById("test-profile-btn").addEventListener("click", () => Profiles.testForm());
},
// 加载并渲染 Profile 列表
async load() {
const grid = document.getElementById("profile-cards");
const empty = document.getElementById("profiles-empty");
grid.innerHTML = '<p class="muted">加载中…</p>';
try {
const data = await API.profiles();
Profiles._data = data.profiles || [];
grid.innerHTML = "";
if (Profiles._data.length === 0) {
empty.hidden = false;
} else {
empty.hidden = true;
Profiles._data.forEach(p => grid.appendChild(Profiles.renderCard(p)));
}
} catch (err) {
grid.innerHTML = `<p class="muted">加载失败:${App.escape(err.message)}</p>`;
}
},
// 渲染单个 Profile 卡片
renderCard(p) {
const card = document.createElement("div");
card.className = "profile-card";
card.dataset.id = p.profile_id;
card.innerHTML = `
<div class="profile-card-head">
<div class="profile-card-name">${App.escape(p.name)}</div>
<div class="profile-card-actions">
<button class="btn btn-sm btn-test" data-action="test">测试</button>
<button class="btn btn-sm" data-action="edit">编辑</button>
<button class="btn btn-sm btn-danger" data-action="delete">删除</button>
</div>
</div>
<div class="profile-card-field"><span class="field-label">模型</span> <code>${App.escape(p.model)}</code></div>
<div class="profile-card-field"><span class="field-label">Base URL</span> <code>${App.escape(p.base_url)}</code></div>
<div class="profile-card-field"><span class="field-label">超时</span> ${p.timeout_seconds}s</div>
<div class="profile-test-result" data-result hidden></div>
`;
card.querySelector("[data-action=test]").addEventListener("click", () => Profiles.testCard(p, card));
card.querySelector("[data-action=edit]").addEventListener("click", () => Profiles.showForm(p));
card.querySelector("[data-action=delete]").addEventListener("click", () => Profiles.remove(p.profile_id, p.name));
return card;
},
// 测试已保存的 profile卡片上的测试按钮
async testCard(p, card) {
const btn = card.querySelector("[data-action=test]");
const resultEl = card.querySelector("[data-result]");
btn.disabled = true;
btn.textContent = "测试中…";
resultEl.hidden = true;
resultEl.className = "profile-test-result";
try {
const res = await API.testProfile(p.profile_id);
Profiles._showTestResult(resultEl, res);
} catch (err) {
Profiles._showTestResult(resultEl, { ok: false, message: err.message });
} finally {
btn.disabled = false;
btn.textContent = "测试";
}
},
// 测试表单中当前填写的参数(保存前即可测试)
async testForm() {
const body = {
model: document.getElementById("pf-model").value.trim(),
base_url: document.getElementById("pf-base-url").value.trim(),
api_key: document.getElementById("pf-api-key").value.trim(),
timeout_seconds: parseInt(document.getElementById("pf-timeout").value, 10) || 30,
};
const errEl = document.getElementById("profile-form-error");
if (!body.model || !body.base_url || !body.api_key) {
errEl.textContent = "请先填写模型名称、Base URL 和 API Key";
return;
}
errEl.textContent = "";
const testBtn = document.getElementById("test-profile-btn");
const resultEl = document.getElementById("profile-form-test-result");
testBtn.disabled = true;
testBtn.textContent = "测试中…";
resultEl.hidden = true;
resultEl.className = "profile-test-result";
try {
const res = await API.probeConnectivity(body);
Profiles._showTestResult(resultEl, res);
} catch (err) {
Profiles._showTestResult(resultEl, { ok: false, message: err.message });
} finally {
testBtn.disabled = false;
testBtn.textContent = "测试连通性";
}
},
// 渲染测试结果到指定元素
_showTestResult(el, res) {
el.hidden = false;
el.classList.add(res.ok ? "ok" : "fail");
const latency = res.latency_ms != null ? ` (${res.latency_ms}ms)` : "";
el.textContent = res.ok ? `✓ 连接成功${latency}` : `${res.message}`;
},
// 显示新建或编辑表单
showForm(profile = null) {
const panel = document.getElementById("profile-form-panel");
const title = document.getElementById("profile-form-title");
panel.hidden = false;
title.textContent = profile ? "编辑 LLM 配置" : "新建 LLM 配置";
document.getElementById("edit-profile-id").value = profile ? profile.profile_id : "";
document.getElementById("pf-name").value = profile ? profile.name : "";
document.getElementById("pf-model").value = profile ? profile.model : "";
document.getElementById("pf-base-url").value = profile ? profile.base_url : "";
document.getElementById("pf-api-key").value = profile ? profile.api_key : "";
document.getElementById("pf-timeout").value = profile ? profile.timeout_seconds : 30;
document.getElementById("profile-form-error").textContent = "";
const resultEl = document.getElementById("profile-form-test-result");
resultEl.hidden = true;
resultEl.className = "profile-test-result";
panel.scrollIntoView({ behavior: "smooth", block: "start" });
},
hideForm() {
document.getElementById("profile-form-panel").hidden = true;
},
// 保存(新建 or 更新)
async save() {
const id = document.getElementById("edit-profile-id").value;
const body = {
name: document.getElementById("pf-name").value.trim(),
model: document.getElementById("pf-model").value.trim(),
base_url: document.getElementById("pf-base-url").value.trim(),
api_key: document.getElementById("pf-api-key").value.trim(),
timeout_seconds: parseInt(document.getElementById("pf-timeout").value, 10) || 30,
};
const errEl = document.getElementById("profile-form-error");
if (!body.name || !body.model || !body.base_url || !body.api_key) {
errEl.textContent = "请填写所有必填字段名称、模型、Base URL、API Key";
return;
}
try {
if (id) {
await API.updateProfile(id, body);
} else {
await API.createProfile(body);
}
Profiles.hideForm();
await Profiles.load();
} catch (err) {
errEl.textContent = `保存失败:${err.message}`;
}
},
// 删除 Profile
async remove(profileId, name) {
if (!confirm(`确认删除配置「${name}」?`)) return;
try {
await API.deleteProfile(profileId);
await Profiles.load();
} catch (err) {
alert(`删除失败:${err.message}`);
}
},
// 获取当前已加载的 profiles供 runner.js 使用)
getAll() {
return Profiles._data;
},
};