咨询台接 Ragflow 检索与示例知识库,支持追问、判定、引用和留资。 Co-authored-by: haijd <haijd@163.com>
145 lines
5.1 KiB
JavaScript
145 lines
5.1 KiB
JavaScript
let sessionId = null;
|
|
|
|
const logEl = document.getElementById("log");
|
|
const slotsEl = document.getElementById("slots");
|
|
const schemeEl = document.getElementById("scheme");
|
|
const metaEl = document.getElementById("meta");
|
|
const form = document.getElementById("form");
|
|
const input = document.getElementById("input");
|
|
const statusEl = document.getElementById("status");
|
|
|
|
function addBubble(role, text) {
|
|
const div = document.createElement("div");
|
|
div.className = `bubble ${role}`;
|
|
div.textContent = text;
|
|
logEl.appendChild(div);
|
|
logEl.scrollTop = logEl.scrollHeight;
|
|
}
|
|
|
|
async function ensureSession() {
|
|
if (sessionId) return sessionId;
|
|
const res = await fetch("/api/sessions", { method: "POST" });
|
|
const data = await res.json();
|
|
sessionId = data.session_id;
|
|
metaEl.textContent = `会话 ${sessionId.slice(0, 8)}`;
|
|
return sessionId;
|
|
}
|
|
|
|
async function sendMessage(message) {
|
|
await ensureSession();
|
|
addBubble("user", message);
|
|
const res = await fetch("/api/chat", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ session_id: sessionId, message }),
|
|
});
|
|
if (!res.ok) {
|
|
addBubble("bot", `请求失败:${res.status}`);
|
|
return;
|
|
}
|
|
const data = await res.json();
|
|
addBubble("bot", data.reply);
|
|
slotsEl.textContent = JSON.stringify(data.slots || {}, null, 2);
|
|
schemeEl.textContent = data.scheme ? JSON.stringify(data.scheme, null, 2) : "还没到出方案这一步";
|
|
metaEl.textContent = `会话 ${sessionId.slice(0, 8)} · ${data.phase}`;
|
|
}
|
|
|
|
form.addEventListener("submit", async (event) => {
|
|
event.preventDefault();
|
|
const text = input.value.trim();
|
|
if (!text) return;
|
|
input.value = "";
|
|
form.querySelector("button").disabled = true;
|
|
try {
|
|
await sendMessage(text);
|
|
} finally {
|
|
form.querySelector("button").disabled = false;
|
|
input.focus();
|
|
}
|
|
});
|
|
|
|
document.getElementById("reset").addEventListener("click", () => {
|
|
sessionId = null;
|
|
logEl.innerHTML = "";
|
|
slotsEl.textContent = "{}";
|
|
schemeEl.textContent = "还没到出方案这一步";
|
|
metaEl.textContent = "";
|
|
addBubble("bot", "新会话。可以直接说:「产线检测,偏向 B 类」。");
|
|
input.focus();
|
|
});
|
|
|
|
document.getElementById("handoff").addEventListener("submit", async (event) => {
|
|
event.preventDefault();
|
|
const msg = document.getElementById("handoff-msg");
|
|
if (!sessionId) {
|
|
msg.textContent = "请先开始一段咨询。";
|
|
return;
|
|
}
|
|
const body = Object.fromEntries(new FormData(event.target).entries());
|
|
const res = await fetch("/api/handoff", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ session_id: sessionId, ...body }),
|
|
});
|
|
const data = await res.json();
|
|
msg.textContent = res.ok ? `已记录,编号 ${data.lead_id}` : "提交失败";
|
|
if (res.ok) loadLeads();
|
|
});
|
|
|
|
document.querySelectorAll(".tab").forEach((button) => {
|
|
button.addEventListener("click", () => {
|
|
document.querySelectorAll(".tab").forEach((item) => item.classList.remove("active"));
|
|
document.querySelectorAll(".pane").forEach((item) => item.classList.remove("active"));
|
|
button.classList.add("active");
|
|
document.getElementById(button.dataset.tab).classList.add("active");
|
|
if (button.dataset.tab === "knowledge") loadKnowledge();
|
|
if (button.dataset.tab === "leads") loadLeads();
|
|
});
|
|
});
|
|
|
|
async function loadHealth() {
|
|
try {
|
|
const data = await (await fetch("/api/health")).json();
|
|
const ragOk = data.ragflow && data.ragflow.ok && data.dataset_ids_configured;
|
|
statusEl.textContent = ragOk ? "Ragflow 已接入" : "Ragflow 未就绪,出方案时会标明检索失败";
|
|
statusEl.className = `status ${ragOk ? "ok" : "bad"}`;
|
|
if (data.ragflow_web) document.getElementById("ragflow-link").href = data.ragflow_web;
|
|
} catch {
|
|
statusEl.textContent = "咨询服务未连通";
|
|
statusEl.className = "status bad";
|
|
}
|
|
}
|
|
|
|
async function loadKnowledge() {
|
|
const box = document.getElementById("ragflow-status");
|
|
const files = document.getElementById("files");
|
|
const status = await (await fetch("/api/ragflow/status")).json();
|
|
box.textContent = JSON.stringify(status, null, 2);
|
|
const list = await (await fetch("/api/knowledge/files")).json();
|
|
files.innerHTML = "";
|
|
(list.files || []).forEach((file) => {
|
|
const li = document.createElement("li");
|
|
li.textContent = `${file.name} · ${file.bytes} 字节`;
|
|
files.appendChild(li);
|
|
});
|
|
}
|
|
|
|
async function loadLeads() {
|
|
const box = document.getElementById("lead-list");
|
|
const data = await (await fetch("/api/leads")).json();
|
|
if (!data.leads || !data.leads.length) {
|
|
box.textContent = "暂无";
|
|
return;
|
|
}
|
|
box.innerHTML = "";
|
|
data.leads.forEach((lead) => {
|
|
const div = document.createElement("div");
|
|
div.className = "lead";
|
|
div.textContent = `#${lead.id} ${lead.name} ${lead.phone} · ${lead.note || "无备注"} · ${lead.created_at}`;
|
|
box.appendChild(div);
|
|
});
|
|
}
|
|
|
|
addBubble("bot", "你好,我是鲜境方案客服。先问清技术路线和场景,再给出产品组合草稿,并附上知识库依据。\n试试:「户外监测,指标还不确定」。");
|
|
loadHealth();
|