⚡ NVIDIA CYBER AI
/gi, "");
}
// 渲染Markdown工具
function renderMd(text){
try{
return safeHtml(marked.parse(text));
}catch(e){
return text;
}
}
function appendMsg(role, text) {
const wrap = document.createElement("div");
wrap.className = "msg " + role;
const bubble = document.createElement("div");
bubble.className = "bubble";
if(role === "user"){
bubble.textContent = text;
}else{
bubble.innerHTML = renderMd(text);
}
wrap.appendChild(bubble);
chatEl.appendChild(wrap);
chatEl.scrollTop = chatEl.scrollHeight;
return bubble;
}
function clearChat() {
chatEl.innerHTML = "";
messages = [];
inputEl.value = "";
}
async function send() {
const text = inputEl.value.trim();
if (!text) return;
sendBtn.disabled = true;
sendBtn.classList.add("loading");
const useStream = document.getElementById("stream").checked;
const model = document.getElementById("model").value;
messages.push({ role: "user", content: text });
appendMsg("user", text);
inputEl.value = "";
try {
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model,
messages: [...messages],
stream: useStream,
}),
});
if (!res.ok) {
const err = await res.json().catch(() => ({ error: "服务异常" }));
appendMsg("assistant", "❌ " + (err.error || "请求失败,状态码:" + res.status));
return;
}
if (useStream) {
const reader = res.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";
const aiBubble = appendMsg("assistant", "▌");
let fullText = "";
while (true) {
const { value, done } = await reader.read();
if (done) {
aiBubble.innerHTML = renderMd(fullText);
break;
}
buffer += decoder.decode(value, { stream: true });
// 修复关键:改为单斜杠换行分割
const lines = buffer.split("
");
buffer = lines.pop();
for (const line of lines) {
const trimLine = line.trim();
if (!trimLine.startsWith("data:")) continue;
const dataStr = trimLine.replace("data:", "").trim();
if (dataStr === "[DONE]") continue;
try {
const chunk = JSON.parse(dataStr);
const delta = chunk.choices?.[0]?.delta?.content || "";
fullText += delta;
aiBubble.innerHTML = renderMd(fullText + "▌");
} catch (e) {}
}
}
messages.push({ role: "assistant", content: fullText });
} else {
const data = await res.json();
const reply = data.choices?.[0]?.message?.content || "无返回内容";
appendMsg("assistant", reply);
messages.push({ role: "assistant", content: reply });
}
} catch (err) {
appendMsg("assistant", "❌ 网络请求失败:" + err.message);
} finally {
sendBtn.disabled = false;
sendBtn.classList.remove("loading");
}
}