修复快捷咨询串入人工会话及上下文切换
This commit is contained in:
+247
-87
@@ -10,6 +10,15 @@ let uploadVersion = 0;
|
||||
let followLatest = true;
|
||||
let creatingConv = null;
|
||||
let sendPreparing = false;
|
||||
let conversationVersion = 0;
|
||||
let activeQuickTopic = null;
|
||||
let humanConvId = null;
|
||||
let humanStatus = '';
|
||||
let humanRequestToken = null;
|
||||
let humanPollTimer = null;
|
||||
let humanSendingToken = null;
|
||||
let humanClosing = false;
|
||||
window.humanSid = 0;
|
||||
SupportUI.initEmoji(document.getElementById('emoji-toggle'), document.getElementById('emoji-panel'), inputDom, function(){ autoGrow(); });
|
||||
document.getElementById('notifications-toggle').onclick = function(){ SupportUI.enableNotifications(this); };
|
||||
|
||||
@@ -175,6 +184,17 @@ const I18N = {
|
||||
offlineSaved: "留言已提交,工作时间(8:00-22:00)会尽快回复您。",
|
||||
humanClosed: "人工客服已结束,您可以继续向 AI 提问。",
|
||||
humanReply: "客服回复",
|
||||
humanConnecting: "正在为您连接人工客服…",
|
||||
humanWaiting: "正在排队,消息将由人工客服接入后回复。您也可以返回 AI 继续咨询。",
|
||||
humanActive: "人工客服接待中,消息将发送给人工客服。",
|
||||
returnAI: "返回 AI 问答",
|
||||
humanSent: "已发送给人工客服",
|
||||
humanSending: "正在发送给人工客服…",
|
||||
humanSendFailed: "消息未发送成功,内容已保留,请重试。",
|
||||
humanConnectFailed: "人工客服连接失败,请稍后重试。",
|
||||
humanPollFailed: "人工客服连接中断,正在重试。您可以返回 AI 继续咨询。",
|
||||
humanReturnFailed: "暂时无法结束人工会话,请重试。",
|
||||
historyLoading: "正在加载这段会话,请稍候…",
|
||||
recalled: "该消息已撤回",
|
||||
ratingQuestion: "本次服务满意吗?",
|
||||
ratingThanks: "感谢您的评价!",
|
||||
@@ -248,6 +268,17 @@ const I18N = {
|
||||
offlineSaved: "Message submitted. Our team will reply during service hours (08:00–22:00).",
|
||||
humanClosed: "This support session has ended. You can continue chatting with the AI assistant.",
|
||||
humanReply: "Support reply",
|
||||
humanConnecting: "Connecting you to our support team…",
|
||||
humanWaiting: "You are in the queue. A team member will reply after joining, or you can return to AI chat.",
|
||||
humanActive: "You are chatting with our support team. Messages will be sent to a team member.",
|
||||
returnAI: "Return to AI chat",
|
||||
humanSent: "Sent to our support team",
|
||||
humanSending: "Sending to our support team…",
|
||||
humanSendFailed: "Message not sent. Your text has been kept. Please retry.",
|
||||
humanConnectFailed: "Could not connect to our support team. Please try again.",
|
||||
humanPollFailed: "Support connection lost. Retrying, or you can return to AI chat.",
|
||||
humanReturnFailed: "Could not end the support session. Please try again.",
|
||||
historyLoading: "Loading this conversation. Please wait…",
|
||||
recalled: "This message was recalled",
|
||||
ratingQuestion: "How was your support experience?",
|
||||
ratingThanks: "Thank you for your feedback!",
|
||||
@@ -339,6 +370,7 @@ function applyLanguage(lang){
|
||||
if(tb) tb.title = dict.toBottom;
|
||||
const tg = document.querySelector(".toggle-divider");
|
||||
if(tg) tg.title = tg.getAttribute('aria-expanded') === 'false' ? dict.sideExpand : dict.sideCollapse;
|
||||
updateHumanMode();
|
||||
|
||||
// 欢迎页(若当前显示的是欢迎页则重绘)
|
||||
if(chatDom.querySelector(".ai-welcome-card")){
|
||||
@@ -495,12 +527,19 @@ function welcomeHTML(){
|
||||
if(clearAllBtn){
|
||||
clearAllBtn.onclick = function(){
|
||||
if(!confirm(t("confirmClear"))) return;
|
||||
if(cancelActive){ cancelActive(); cancelActive = null; }
|
||||
const version = resetConversation(null);
|
||||
openingConv = 'clearing';
|
||||
fetch("/api/clear_all", {method:"DELETE"})
|
||||
.then(()=>{
|
||||
currentConvId = null;
|
||||
.then(response=>{
|
||||
if(!response.ok) throw new Error('Clear failed');
|
||||
if(version !== conversationVersion) return;
|
||||
openingConv = null;
|
||||
chatDom.innerHTML = welcomeHTML();
|
||||
loadHistory();
|
||||
}).catch(function(){
|
||||
if(version !== conversationVersion) return;
|
||||
openingConv = null;
|
||||
setComposerStatus(t('networkFail'), true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -508,13 +547,11 @@ clearAllBtn.onclick = function(){
|
||||
// 新建对话:只清界面,等用户开口时再建会话
|
||||
if(newChatBtn){
|
||||
newChatBtn.onclick = function(){
|
||||
if(cancelActive){ cancelActive(); cancelActive = null; }
|
||||
if(sseInstance){ sseInstance.close(); sseInstance = null; }
|
||||
resetConversation(null);
|
||||
inputDom.value = "";
|
||||
autoGrow();
|
||||
clearAttachment();
|
||||
setComposerStatus("");
|
||||
currentConvId = null;
|
||||
chatDom.innerHTML = welcomeHTML();
|
||||
chatDom.scrollTop = 0;
|
||||
followLatest = true;
|
||||
@@ -647,33 +684,56 @@ function renderRecentChat(){
|
||||
function ensureConv(){
|
||||
if(currentConvId) return Promise.resolve(currentConvId);
|
||||
if(creatingConv) return creatingConv;
|
||||
creatingConv = fetch("/api/new_chat", {method:"POST"})
|
||||
const version = conversationVersion;
|
||||
const pending = fetch("/api/new_chat", {method:"POST"})
|
||||
.then(async function(res){
|
||||
const data = await res.json();
|
||||
if(!res.ok || !data.id) throw new Error('Session failed');
|
||||
return data;
|
||||
})
|
||||
.then(data=>{
|
||||
if(version !== conversationVersion){
|
||||
const error = new Error('Conversation changed');
|
||||
error.name = 'AbortError';
|
||||
throw error;
|
||||
}
|
||||
currentConvId = data.id;
|
||||
if(data.welcome) addMsg(t('autoWelcome'), false);
|
||||
return currentConvId;
|
||||
}).finally(function(){ creatingConv = null; });
|
||||
return creatingConv;
|
||||
}).finally(function(){ if(creatingConv === pending) creatingConv = null; });
|
||||
creatingConv = pending;
|
||||
return pending;
|
||||
}
|
||||
|
||||
function resetConversation(id){
|
||||
if(cancelActive){ cancelActive(); cancelActive = null; }
|
||||
if(sseInstance){ sseInstance.close(); sseInstance = null; }
|
||||
conversationVersion += 1;
|
||||
stopHumanMode();
|
||||
currentConvId = id;
|
||||
openingConv = null;
|
||||
creatingConv = null;
|
||||
sendPreparing = false;
|
||||
activeQuickTopic = null;
|
||||
setBusy(false);
|
||||
setComposerStatus('');
|
||||
return conversationVersion;
|
||||
}
|
||||
|
||||
// 打开历史会话:还原整段对话,而不是把标题重发一遍
|
||||
let openingConv = null;
|
||||
function openConversation(id){
|
||||
if(openingConv === id) return; // 防连点
|
||||
const version = resetConversation(id);
|
||||
openingConv = id;
|
||||
if(cancelActive){ cancelActive(); cancelActive = null; }
|
||||
if(sseInstance){ sseInstance.close(); sseInstance = null; }
|
||||
currentConvId = id;
|
||||
setComposerStatus(t('historyLoading'));
|
||||
renderSideHistory();
|
||||
fetch("/api/get_messages?conv_id=" + id)
|
||||
.then(res=>res.json())
|
||||
.then(res=>{ if(!res.ok) throw new Error('History failed'); return res.json(); })
|
||||
.then(msgs=>{
|
||||
if(version !== conversationVersion) return;
|
||||
openingConv = null;
|
||||
setComposerStatus('');
|
||||
chatDom.innerHTML = "";
|
||||
if(!msgs.length){
|
||||
chatDom.innerHTML = welcomeHTML();
|
||||
@@ -693,7 +753,11 @@ function openConversation(id){
|
||||
});
|
||||
// 等渲染完再滚到底部
|
||||
requestAnimationFrame(function(){ scrollChatToEnd(true); });
|
||||
})["catch"](function(){ openingConv = null; });
|
||||
}).catch(function(){
|
||||
if(version !== conversationVersion) return;
|
||||
openingConv = null;
|
||||
setComposerStatus(t('networkFail'), true);
|
||||
});
|
||||
}
|
||||
|
||||
const CARD_PREFIX = "__CARD__";
|
||||
@@ -749,12 +813,12 @@ function fillTrackCard(el, card){
|
||||
}
|
||||
}
|
||||
|
||||
function createMessageRow(isUser){
|
||||
function createMessageRow(isUser, authorRole){
|
||||
const row = document.createElement("div");
|
||||
row.className = "msg-row " + (isUser ? "user-line" : "robot-line");
|
||||
const author = document.createElement("div");
|
||||
author.className = "message-author";
|
||||
const role = isUser ? "you" : (window.humanSid ? "humanAgent" : "assistant");
|
||||
const role = isUser ? "you" : (authorRole || "assistant");
|
||||
author.innerHTML = (isUser ? "" : '<span class="author-mark">' + welcomeIcon("box") + '</span>') + '<span data-i18n="' + role + '">' + t(role) + '</span>';
|
||||
row.appendChild(author);
|
||||
return row;
|
||||
@@ -775,19 +839,20 @@ loadHistory();
|
||||
|
||||
window.fillInput = function(words){
|
||||
inputDom.value = words;
|
||||
doSend();
|
||||
return doSend();
|
||||
}
|
||||
|
||||
// 点快捷问题:另起一个会话,不同话题就不会堆进同一条历史
|
||||
window.askNewTopic = function(words){
|
||||
if(cancelActive){ cancelActive(); cancelActive = null; }
|
||||
currentConvId = null; // 下次发送时自动新建会话
|
||||
if(activeQuickTopic === words && (sendPreparing || window.__busy)) return;
|
||||
resetConversation(null);
|
||||
activeQuickTopic = words;
|
||||
// 新话题先重置界面,发送第一条消息时再收起欢迎内容。
|
||||
if(!chatDom.querySelector('.ai-welcome-card')){
|
||||
chatDom.innerHTML = welcomeHTML();
|
||||
}
|
||||
inputDom.value = words;
|
||||
doSend();
|
||||
return doSend();
|
||||
}
|
||||
|
||||
window.sendOrder = function(){
|
||||
@@ -816,64 +881,161 @@ function myOrders(){
|
||||
.catch(function(){ addMsg("查询失败,请重试", false); });
|
||||
}
|
||||
|
||||
function updateHumanMode(){
|
||||
const banner = document.getElementById('human-session');
|
||||
const label = document.getElementById('human-session-label');
|
||||
const button = document.getElementById('return-ai');
|
||||
if(banner) banner.hidden = !window.humanSid && !humanRequestToken;
|
||||
const text = t(humanRequestToken ? 'humanConnecting' : humanStatus === 'active' ? 'humanActive' : 'humanWaiting');
|
||||
if(label && label.textContent !== text) label.textContent = text;
|
||||
if(button){
|
||||
button.textContent = t('returnAI');
|
||||
button.disabled = Boolean(humanRequestToken || humanClosing || humanSendingToken);
|
||||
}
|
||||
sendBtn.disabled = Boolean(humanRequestToken || humanClosing || humanSendingToken);
|
||||
}
|
||||
|
||||
function stopHumanMode(){
|
||||
if(humanPollTimer !== null) clearInterval(humanPollTimer);
|
||||
humanPollTimer = null;
|
||||
humanConvId = null;
|
||||
humanStatus = '';
|
||||
humanRequestToken = null;
|
||||
humanSendingToken = null;
|
||||
humanClosing = false;
|
||||
window.humanSid = 0;
|
||||
const typing = document.getElementById('human-typing');
|
||||
if(typing) typing.remove();
|
||||
updateHumanMode();
|
||||
}
|
||||
|
||||
async function humanRequest(path, data){
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(function(){ controller.abort(); }, 10000);
|
||||
try{
|
||||
const response = await fetch(path, {method:data ? 'POST' : 'GET',
|
||||
headers:data ? {'Content-Type':'application/json'} : {},
|
||||
body:data ? JSON.stringify(data) : undefined, signal:controller.signal});
|
||||
const result = await response.json();
|
||||
if(!response.ok){
|
||||
const error = new Error('Human request failed');
|
||||
error.status = response.status;
|
||||
throw error;
|
||||
}
|
||||
return result;
|
||||
}finally{ clearTimeout(timer); }
|
||||
}
|
||||
|
||||
window.showHuman = async function(){
|
||||
if(window.humanSid){
|
||||
addMsg("您已在人工客服会话中,请直接提问。", false);
|
||||
return;
|
||||
if(humanRequestToken || humanClosing) return;
|
||||
if(window.humanSid && humanConvId === currentConvId){ updateHumanMode(); return; }
|
||||
if(window.humanSid) stopHumanMode();
|
||||
const hour = new Date().getHours();
|
||||
if(hour < 8 || hour >= 22) return leaveOfflineMessage();
|
||||
const token = {version:conversationVersion};
|
||||
humanRequestToken = token;
|
||||
if(cancelActive){ cancelActive(); cancelActive = null; }
|
||||
setBusy(false);
|
||||
updateHumanMode();
|
||||
try{
|
||||
const cid = await ensureConv();
|
||||
if(humanRequestToken !== token || token.version !== conversationVersion) return;
|
||||
const data = await humanRequest('/api/human/request', {conv_id:cid});
|
||||
if(humanRequestToken !== token || token.version !== conversationVersion) return;
|
||||
if(data.closed){ await leaveOfflineMessage(); return; }
|
||||
if(!data.ok || !data.session_id) throw new Error('Human session failed');
|
||||
window.humanSid = data.session_id;
|
||||
humanConvId = cid;
|
||||
humanStatus = 'waiting';
|
||||
addMsg(t('humanWaiting'), false);
|
||||
startHumanPoll();
|
||||
}catch(error){
|
||||
if(humanRequestToken === token && token.version === conversationVersion) setComposerStatus(t('humanConnectFailed'), true);
|
||||
}finally{
|
||||
if(humanRequestToken === token){ humanRequestToken = null; updateHumanMode(); }
|
||||
}
|
||||
};
|
||||
|
||||
async function returnToAI(){
|
||||
if(!window.humanSid || humanClosing || humanSendingToken) return;
|
||||
const sid = window.humanSid, version = conversationVersion;
|
||||
humanClosing = true;
|
||||
updateHumanMode();
|
||||
try{
|
||||
const result = await humanRequest('/api/human/close', {sid:sid});
|
||||
if(!result.ok) throw new Error('Close failed');
|
||||
if(version !== conversationVersion || window.humanSid !== sid) return;
|
||||
stopHumanMode();
|
||||
setComposerStatus('');
|
||||
addMsg(t('humanClosed'), false);
|
||||
inputDom.focus();
|
||||
}catch(error){
|
||||
if(version === conversationVersion) setComposerStatus(t('humanReturnFailed'), true);
|
||||
}finally{
|
||||
if(version === conversationVersion){ humanClosing = false; updateHumanMode(); }
|
||||
}
|
||||
}
|
||||
const returnAIButton = document.getElementById('return-ai');
|
||||
if(returnAIButton) returnAIButton.onclick = returnToAI;
|
||||
|
||||
async function sendHumanMessage(content){
|
||||
if(humanSendingToken || humanClosing) return;
|
||||
const sid = window.humanSid, cid = currentConvId, version = conversationVersion;
|
||||
const draft = inputDom.value, attachment = window.__pendingImg;
|
||||
const token = {};
|
||||
humanSendingToken = token;
|
||||
updateHumanMode();
|
||||
setComposerStatus(t('humanSending'));
|
||||
try{
|
||||
const result = await humanRequest('/api/human/send', {sid:sid, conv_id:cid, side:'customer', content:content});
|
||||
if(!result.ok) throw new Error('Send failed');
|
||||
if(version !== conversationVersion || humanSendingToken !== token) return;
|
||||
addMsg(content, true);
|
||||
if(inputDom.value === draft){ inputDom.value = ''; autoGrow(); }
|
||||
if(window.__pendingImg === attachment) clearAttachment();
|
||||
setComposerStatus(t(humanStatus === 'active' ? 'humanSent' : 'humanWaiting'));
|
||||
inputDom.focus();
|
||||
}catch(error){
|
||||
if(version !== conversationVersion || humanSendingToken !== token) return;
|
||||
if(error.status === 404 || error.status === 409) stopHumanMode();
|
||||
setComposerStatus(t('humanSendFailed'), true);
|
||||
}finally{
|
||||
if(humanSendingToken === token){ humanSendingToken = null; updateHumanMode(); }
|
||||
}
|
||||
var now = new Date();
|
||||
var h = now.getHours();
|
||||
var work = h >= 8 && h < 22;
|
||||
if(!work){
|
||||
leaveOfflineMessage();
|
||||
return;
|
||||
}
|
||||
addMsg("正在为您转接人工客服...", false);
|
||||
if(!currentConvId){
|
||||
try{ await ensureConv(); }catch(e){ setComposerStatus(t('sessionFail'), true); return; }
|
||||
}
|
||||
fetch("/api/human/request",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({conv_id:currentConvId||0})})
|
||||
.then(function(r){return r.json()})
|
||||
.then(function(d){
|
||||
if(d.ok){
|
||||
window.humanSid = d.session_id;
|
||||
addMsg("您已加入人工排队,请稍候...", false);
|
||||
startHumanPoll();
|
||||
}else if(d.closed){
|
||||
leaveOfflineMessage();
|
||||
}else{
|
||||
addMsg("转接失败,请稍后再试。", false);
|
||||
}
|
||||
})
|
||||
.catch(function(){
|
||||
addMsg("网络错误,请稍后再试。", false);
|
||||
});
|
||||
}
|
||||
window.humanSid = 0;
|
||||
async function leaveOfflineMessage(){
|
||||
const version = conversationVersion;
|
||||
addMsg(t('humanHours'), false);
|
||||
const message = window.prompt(t('offlinePrompt'));
|
||||
if(!message) return;
|
||||
try{
|
||||
const response = await fetch('/api/ticket', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({content:message, phone:''})});
|
||||
const data = await response.json();
|
||||
if(!response.ok || !data.ok) throw new Error('Ticket failed');
|
||||
addMsg(t('offlineSaved'), false);
|
||||
}catch(error){ setComposerStatus(t('networkFail'), true); }
|
||||
const data = await humanRequest('/api/ticket', {content:message, phone:''});
|
||||
if(!data.ok) throw new Error('Ticket failed');
|
||||
if(version === conversationVersion) addMsg(t('offlineSaved'), false);
|
||||
}catch(error){
|
||||
if(version !== conversationVersion) return;
|
||||
if(!inputDom.value) inputDom.value = message;
|
||||
setComposerStatus(t('networkFail'), true);
|
||||
}
|
||||
}
|
||||
|
||||
function startHumanPoll(){
|
||||
let last=0;
|
||||
let polling=false;
|
||||
const sid=window.humanSid;
|
||||
const cid=humanConvId, version=conversationVersion;
|
||||
let hadPollError=false;
|
||||
if(humanPollTimer !== null) clearInterval(humanPollTimer);
|
||||
const pollTimer=setInterval(()=>{
|
||||
if(window.humanSid !== sid){ clearInterval(pollTimer); return; }
|
||||
if(window.humanSid !== sid || version !== conversationVersion || currentConvId !== cid){ clearInterval(pollTimer); return; }
|
||||
if(polling) return;
|
||||
polling=true;
|
||||
fetch("/api/human/poll?sid="+sid+"&after="+last)
|
||||
.then(r=>r.json())
|
||||
humanRequest("/api/human/poll?sid="+sid+"&after="+last)
|
||||
.then(d=>{
|
||||
if(window.humanSid !== sid) return;
|
||||
if(window.humanSid !== sid || version !== conversationVersion || currentConvId !== cid) return;
|
||||
if(hadPollError){ setComposerStatus(''); hadPollError=false; }
|
||||
humanStatus=d.status;
|
||||
updateHumanMode();
|
||||
d.messages.forEach(m=>{
|
||||
if(m.id <= last) return;
|
||||
last = m.id;
|
||||
@@ -888,7 +1050,7 @@ function startHumanPoll(){
|
||||
system.textContent = m.content;
|
||||
chatDom.appendChild(system);
|
||||
}else if(m.side === 'agent'){
|
||||
const bubble = addMsg(m.content, false);
|
||||
const bubble = addMsg(m.content, false, 'humanAgent');
|
||||
bubble.closest('.msg-row').setAttribute('data-human-message-id', String(m.id));
|
||||
SupportUI.notify(t('humanReply'), m.content.substring(0, 50));
|
||||
}
|
||||
@@ -896,12 +1058,9 @@ function startHumanPoll(){
|
||||
if(typing) typing.remove();
|
||||
});
|
||||
if(d.status==="closed"){
|
||||
clearInterval(pollTimer);
|
||||
window.humanSid=0;
|
||||
window.__busy=false;
|
||||
if(typeof setBusy==="function") setBusy(false);
|
||||
const typing = document.getElementById('human-typing');
|
||||
if(typing) typing.remove();
|
||||
if(humanClosing) return;
|
||||
stopHumanMode();
|
||||
setBusy(false);
|
||||
addMsg(t('humanClosed'), false);
|
||||
SupportUI.addRating(chatDom, sid, {question:t('ratingQuestion'), thanks:t('ratingThanks'), failed:t('ratingFailed')});
|
||||
scrollChatToEnd();
|
||||
@@ -920,13 +1079,18 @@ function startHumanPoll(){
|
||||
oldT.remove();
|
||||
}
|
||||
})
|
||||
.catch(()=>{}).finally(function(){ polling=false; });
|
||||
.catch(function(){
|
||||
if(version !== conversationVersion || window.humanSid !== sid) return;
|
||||
hadPollError=true;
|
||||
setComposerStatus(t('humanPollFailed'), true);
|
||||
}).finally(function(){ polling=false; });
|
||||
}, 1000);
|
||||
humanPollTimer = pollTimer;
|
||||
}
|
||||
|
||||
function addMsg(content, isUser){
|
||||
function addMsg(content, isUser, authorRole){
|
||||
if(chatDom.querySelector('.ai-welcome-card')) chatDom.innerHTML = "";
|
||||
const rowDiv = createMessageRow(isUser);
|
||||
const rowDiv = createMessageRow(isUser, authorRole);
|
||||
let robotMsg;
|
||||
// 检测图片附件
|
||||
let imgUrl = null;
|
||||
@@ -1134,35 +1298,31 @@ async function doSend(retryText){
|
||||
return;
|
||||
}
|
||||
if(uploadPending){ setComposerStatus(t("uploading")); return; }
|
||||
if(humanSendingToken || humanClosing) return;
|
||||
var fullContent = sendWord;
|
||||
if(imgUrl) fullContent += (fullContent ? " " : "") + tag + imgUrl;
|
||||
setComposerStatus("");
|
||||
if(openingConv !== null){ setComposerStatus(t('historyLoading')); return; }
|
||||
if(humanRequestToken || humanClosing){ updateHumanMode(); return; }
|
||||
// 人工客服模式:直接发给客服,不走AI
|
||||
if(window.humanSid){
|
||||
var content = sendWord;
|
||||
if(imgUrl) content += (content ? " " : "") + tag + imgUrl;
|
||||
if(!isRetry) addMsg(content, true);
|
||||
inputDom.value = "";
|
||||
autoGrow();
|
||||
window.__pendingImg = ""; window.__pendingTag = "[图片]";
|
||||
var p = document.getElementById("imgPreview"); if(p) p.remove();
|
||||
inputDom.focus();
|
||||
fetch("/api/human/send",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sid:window.humanSid,side:"customer",content:content})});
|
||||
return;
|
||||
}
|
||||
if(window.humanSid && humanConvId === currentConvId) return sendHumanMessage(fullContent);
|
||||
if(window.humanSid) stopHumanMode();
|
||||
|
||||
if(sendPreparing || (window.__busy && !retryText)) return; // 防连点
|
||||
if(cancelActive){ cancelActive(); cancelActive = null; }
|
||||
|
||||
sendPreparing = true;
|
||||
const version = conversationVersion;
|
||||
let convId;
|
||||
try{
|
||||
await ensureConv();
|
||||
convId = await ensureConv();
|
||||
}catch(error){
|
||||
setComposerStatus(t('sessionFail'), true);
|
||||
if(version === conversationVersion) setComposerStatus(t('sessionFail'), true);
|
||||
return;
|
||||
}finally{
|
||||
sendPreparing = false;
|
||||
if(version === conversationVersion) sendPreparing = false;
|
||||
}
|
||||
if(version !== conversationVersion || humanRequestToken) return;
|
||||
if(!isRetry){
|
||||
addMsg(fullContent, true);
|
||||
inputDom.value = "";
|
||||
@@ -1257,7 +1417,7 @@ async function doSend(retryText){
|
||||
cancelActive = stop;
|
||||
|
||||
function handleFrame(dataText){
|
||||
if(settled) return;
|
||||
if(settled || version !== conversationVersion) return;
|
||||
let obj;
|
||||
try{
|
||||
obj = JSON.parse(dataText);
|
||||
@@ -1309,7 +1469,7 @@ async function doSend(retryText){
|
||||
fetch("/stream_chat", {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify({msg: fullContent, conv_id: currentConvId}),
|
||||
body: JSON.stringify({msg: fullContent, conv_id: convId}),
|
||||
signal: controller.signal
|
||||
}).then(function(res){
|
||||
if(!res.ok){ throw new Error("HTTP " + res.status); }
|
||||
|
||||
Reference in New Issue
Block a user