feat: 用 Ragflow 搭建鲜境方案客服
咨询台接 Ragflow 检索与示例知识库,支持追问、判定、引用和留资。 Co-authored-by: haijd <haijd@163.com>
This commit is contained in:
+84
-13
@@ -6,7 +6,7 @@ const schemeEl = document.getElementById("scheme");
|
||||
const metaEl = document.getElementById("meta");
|
||||
const form = document.getElementById("form");
|
||||
const input = document.getElementById("input");
|
||||
const resetBtn = document.getElementById("reset");
|
||||
const statusEl = document.getElementById("status");
|
||||
|
||||
function addBubble(role, text) {
|
||||
const div = document.createElement("div");
|
||||
@@ -21,7 +21,7 @@ async function ensureSession() {
|
||||
const res = await fetch("/api/sessions", { method: "POST" });
|
||||
const data = await res.json();
|
||||
sessionId = data.session_id;
|
||||
metaEl.textContent = `session: ${sessionId.slice(0, 8)}…`;
|
||||
metaEl.textContent = `会话 ${sessionId.slice(0, 8)}`;
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
@@ -34,20 +34,18 @@ async function sendMessage(message) {
|
||||
body: JSON.stringify({ session_id: sessionId, message }),
|
||||
});
|
||||
if (!res.ok) {
|
||||
addBubble("sys", `错误:${res.status}`);
|
||||
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 = `session: ${sessionId.slice(0, 8)}… · phase: ${data.phase}`;
|
||||
schemeEl.textContent = data.scheme ? JSON.stringify(data.scheme, null, 2) : "还没到出方案这一步";
|
||||
metaEl.textContent = `会话 ${sessionId.slice(0, 8)} · ${data.phase}`;
|
||||
}
|
||||
|
||||
form.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
form.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
const text = input.value.trim();
|
||||
if (!text) return;
|
||||
input.value = "";
|
||||
@@ -60,14 +58,87 @@ form.addEventListener("submit", async (e) => {
|
||||
}
|
||||
});
|
||||
|
||||
resetBtn.addEventListener("click", () => {
|
||||
document.getElementById("reset").addEventListener("click", () => {
|
||||
sessionId = null;
|
||||
logEl.innerHTML = "";
|
||||
slotsEl.textContent = "{}";
|
||||
schemeEl.textContent = "尚未生成";
|
||||
schemeEl.textContent = "还没到出方案这一步";
|
||||
metaEl.textContent = "";
|
||||
addBubble("bot", "新会话已开始。可以直接说场景,例如:「产线检测,偏向 B 类」。");
|
||||
addBubble("bot", "新会话。可以直接说:「产线检测,偏向 B 类」。");
|
||||
input.focus();
|
||||
});
|
||||
|
||||
addBubble("bot", "你好,我是鲜境方案引擎原型。先收集几个关键信息,再给出产品组合草稿。\n试试:「我们在户外做监测,指标还不确定」。");
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user