feat(chatbot): 重构输入区与高级选项栏
This commit is contained in:
parent
3890cca114
commit
6a25d6aa3c
|
|
@ -22,7 +22,7 @@
|
|||
/* ==================== Chatbot Modal Window (High-end Minimalist) ==================== */
|
||||
|
||||
.chatbot-window {
|
||||
background: var(--color-bg-base); /* Pure white background */
|
||||
|
||||
max-width: 720px;
|
||||
width: 92vw;
|
||||
min-height: 520px;
|
||||
|
|
@ -30,7 +30,6 @@
|
|||
border-radius: 24px;
|
||||
|
||||
/* The Shadow Fix: Using variable for consistency and lightness */
|
||||
box-shadow: var(--shadow-modal);
|
||||
border: 1px solid var(--color-border-light); /* Very subtle border */
|
||||
|
||||
position: absolute;
|
||||
|
|
@ -86,6 +85,7 @@
|
|||
scroll-behavior: smooth;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -291,13 +291,13 @@ body.dark #chatbot-toast {
|
|||
/* 用户消息容器 */
|
||||
.user-message-container {
|
||||
justify-content: flex-end;
|
||||
padding-left: 20%;
|
||||
/* padding-left: 20%; */
|
||||
}
|
||||
|
||||
/* 助手消息容器 */
|
||||
.assistant-message-container {
|
||||
justify-content: flex-start;
|
||||
padding-right: 10%; /* 减少右侧留白,利用更多空间 */
|
||||
/* padding-right: 10%; */
|
||||
|
||||
/*
|
||||
IMPORTANT: No top padding here anymore.
|
||||
|
|
@ -344,6 +344,7 @@ body.dark #chatbot-toast {
|
|||
.chat-bubble.assistant {
|
||||
background: transparent;
|
||||
color: var(--color-text-primary);
|
||||
width: 100%;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
|
|
@ -493,9 +494,14 @@ body.dark #chatbot-toast {
|
|||
|
||||
/* 输入区容器 */
|
||||
.chatbot-input-container {
|
||||
padding: 16px 24px 20px 24px;
|
||||
height: 160px;
|
||||
display: flex;
|
||||
margin: 0 20px 20px;
|
||||
border-radius: 10px;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.03);
|
||||
background: rgba(255, 255, 255, 0.8); /* 稍微降低不透明度以增强毛玻璃感 */
|
||||
background: #F8F9FA; /* 稍微降低不透明度以增强毛玻璃感 */
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
flex-shrink: 0;
|
||||
|
|
@ -506,9 +512,9 @@ body.dark #chatbot-toast {
|
|||
/* 输入区内部 Wrapper */
|
||||
.chatbot-input-wrapper {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 10px;
|
||||
background: rgba(249, 250, 251, 0.8); /* var(--slate-50) with opacity */
|
||||
flex: 1;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 16px;
|
||||
padding: 8px 8px 8px 14px;
|
||||
|
|
@ -517,14 +523,107 @@ body.dark #chatbot-toast {
|
|||
}
|
||||
|
||||
.chatbot-input-wrapper:focus-within {
|
||||
background: white;
|
||||
border-color: var(--slate-200); /* 柔和的边框颜色,避免刺眼的蓝线 */
|
||||
/* background: white; */
|
||||
/* border-color: var(--slate-200); 柔和的边框颜色,避免刺眼的蓝线 */
|
||||
/*
|
||||
使用更柔和的扩散阴影,而不是实心光晕
|
||||
原先的 0 0 0 3px 会产生类似边框的实心线效果
|
||||
改为 0 0 0 4px rgba(...) 并降低透明度,使其更像光晕
|
||||
*/
|
||||
box-shadow: 0 0 0 4px rgba(224, 231, 255, 0.4);
|
||||
/* box-shadow: 0 0 0 4px rgba(224, 231, 255, 0.4); */
|
||||
}
|
||||
|
||||
/* ==================== Floating Options (Switch/Selector) ==================== */
|
||||
|
||||
#chatbot-floating-options .chatbot-floating-option {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 8px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-floating-option-label {
|
||||
font-size: 11px;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-floating-option.is-active {
|
||||
background: rgba(0, 15, 51, 0.08);
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-floating-option.is-active .chatbot-floating-option-label {
|
||||
color: #000F33;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Switch */
|
||||
#chatbot-floating-options .chatbot-floating-option-switch {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-switch {
|
||||
position: relative;
|
||||
width: 32px;
|
||||
height: 18px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-switch-input {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-switch-track {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(148, 163, 184, 0.55);
|
||||
border-radius: 999px;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-switch-thumb {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-switch-input:checked + .chatbot-switch-track {
|
||||
background: #000F33;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-switch-input:checked + .chatbot-switch-track .chatbot-switch-thumb {
|
||||
transform: translateX(14px);
|
||||
}
|
||||
|
||||
/* Selector */
|
||||
#chatbot-floating-options .chatbot-floating-option-select {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-floating-selector {
|
||||
font-size: 11px;
|
||||
height: 22px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.35);
|
||||
background: rgba(255, 255, 255, 0.75);
|
||||
color: #334155;
|
||||
padding: 0 8px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#chatbot-floating-options .chatbot-floating-option.is-active .chatbot-floating-selector {
|
||||
border-color: #000F33;
|
||||
}
|
||||
|
||||
/* 输入框 */
|
||||
|
|
@ -785,4 +884,4 @@ body.dark #chatbot-toast {
|
|||
.markdown-content table::-webkit-scrollbar-thumb {
|
||||
background: var(--slate-300);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,8 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
|||
const _chatbotOptionsConfig = [
|
||||
{ key: 'semanticGroups', texts: ['意群'], title: '查看/搜索意群', activeStyleColor: '#059669', isAction: true },
|
||||
{ key: 'useContext', texts: ['上下文:关', '上下文:开'], values: [false, true], title: '切换是否使用对话历史', activeStyleColor: '#1d4ed8' },
|
||||
{ key: 'useReActMode', texts: ['ReAct'], activeStyleColor: '#9ca3af', isDisabled: true, title: 'ReAct框架(开发中):推理+工具调用交织,智能动态构建上下文' },
|
||||
{ key: 'multiHopRetrieval', texts: ['检索Agent:关', '检索Agent:开'], values: [false, true], defaultKey: false, title: '开启后自动启用:多轮取材+流式显示+意群分析+向量搜索+重排', activeStyleColor: '#059669' },
|
||||
{ key: 'summarySource', texts: ['提供全文:OCR', '提供全文:无', '提供全文:翻译'], values: ['ocr', 'none', 'translation'], defaultKey: 'ocr', title: '切换总结时使用的文本源 (OCR/不使用文档内容/翻译)', activeStyleColor: '#1d4ed8' },
|
||||
{ key: 'interestPointsActive', texts: ['兴趣点'], activeStyleColor: '#059669', isPlaceholder: true, title: '兴趣点功能 (待实现)' },
|
||||
{ key: 'memoryManagementActive', texts: ['记忆管理'], activeStyleColor: '#059669', isPlaceholder: true, title: '记忆管理功能 (待实现)' }
|
||||
{ key: 'summarySource', texts: ['提供全文:OCR', '提供全文:无', '提供全文:翻译'], values: ['ocr', 'none', 'translation'], defaultKey: 'ocr', title: '切换总结时使用的文本源 (OCR/不使用文档内容/翻译)', activeStyleColor: '#1d4ed8' }
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -26,16 +23,16 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
|||
* @param {HTMLElement} parentElement - 选项栏将被添加到的父容器。
|
||||
* @param {function} globalUpdateUICallback - 全局UI更新回调函数,例如 window.ChatbotUI.updateChatbotUI。
|
||||
*/
|
||||
function _createFloatingOptionsBar(parentElement, globalUpdateUICallback) {
|
||||
if (!parentElement || document.getElementById('chatbot-floating-options')) {
|
||||
return; // 如果父元素不存在或选项栏已存在,则不重复创建
|
||||
}
|
||||
function _createFloatingOptionsBar(parentElement, globalUpdateUICallback) {
|
||||
if (!parentElement || document.getElementById('chatbot-floating-options')) {
|
||||
return; // 如果父元素不存在或选项栏已存在,则不重复创建
|
||||
}
|
||||
|
||||
const floatingOptionsContainer = document.createElement('div');
|
||||
floatingOptionsContainer.id = 'chatbot-floating-options';
|
||||
floatingOptionsContainer.style.cssText = `
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 4px 0 8px 0;
|
||||
gap: 5px;
|
||||
|
|
@ -44,115 +41,197 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
|||
flex-wrap: wrap;
|
||||
`;
|
||||
|
||||
_chatbotOptionsConfig.forEach((optConf, index) => {
|
||||
const optionButton = document.createElement('button');
|
||||
optionButton.id = `chatbot-option-${optConf.key}`;
|
||||
optionButton.style.cssText = `
|
||||
background: none;
|
||||
border: none;
|
||||
color: #4b5563;
|
||||
cursor: pointer;
|
||||
padding: 2px 4px;
|
||||
font-size: 11px;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s, color 0.2s;
|
||||
`;
|
||||
optionButton.title = optConf.title;
|
||||
_chatbotOptionsConfig.forEach((optConf, index) => {
|
||||
const optionEl = (function createOptionElement() {
|
||||
// useContext:switch 组件(替代“上下文:开/关”文字)
|
||||
if (optConf.key === 'useContext') {
|
||||
const wrapper = document.createElement('label');
|
||||
wrapper.id = `chatbot-option-${optConf.key}`;
|
||||
wrapper.className = 'chatbot-floating-option chatbot-floating-option-switch';
|
||||
wrapper.title = optConf.title;
|
||||
|
||||
const labelSpan = document.createElement('span');
|
||||
labelSpan.className = 'chatbot-floating-option-label';
|
||||
labelSpan.textContent = '上下文';
|
||||
|
||||
const switchWrap = document.createElement('span');
|
||||
switchWrap.className = 'chatbot-switch';
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.type = 'checkbox';
|
||||
input.id = 'chatbot-use-context-switch';
|
||||
input.className = 'chatbot-switch-input';
|
||||
window.chatbotActiveOptions = window.chatbotActiveOptions || {};
|
||||
input.checked = !!window.chatbotActiveOptions.useContext;
|
||||
wrapper.classList.toggle('is-active', !!window.chatbotActiveOptions.useContext);
|
||||
|
||||
const track = document.createElement('span');
|
||||
track.className = 'chatbot-switch-track';
|
||||
|
||||
const thumb = document.createElement('span');
|
||||
thumb.className = 'chatbot-switch-thumb';
|
||||
track.appendChild(thumb);
|
||||
|
||||
switchWrap.appendChild(input);
|
||||
switchWrap.appendChild(track);
|
||||
|
||||
wrapper.appendChild(labelSpan);
|
||||
wrapper.appendChild(switchWrap);
|
||||
|
||||
input.addEventListener('change', function() {
|
||||
window.chatbotActiveOptions = window.chatbotActiveOptions || {};
|
||||
window.chatbotActiveOptions.useContext = !!input.checked;
|
||||
wrapper.classList.toggle('is-active', !!input.checked);
|
||||
if (typeof globalUpdateUICallback === 'function') globalUpdateUICallback();
|
||||
else console.error("ChatbotFloatingOptionsUI: globalUpdateUICallback is not provided or not a function.");
|
||||
});
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// summarySource:selector 组件(替代“提供全文:xxx”循环切换按钮)
|
||||
if (optConf.key === 'summarySource') {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.id = `chatbot-option-${optConf.key}`;
|
||||
wrapper.className = 'chatbot-floating-option chatbot-floating-option-select';
|
||||
wrapper.title = optConf.title;
|
||||
|
||||
const labelSpan = document.createElement('span');
|
||||
labelSpan.className = 'chatbot-floating-option-label';
|
||||
labelSpan.textContent = '提供全文';
|
||||
|
||||
const select = document.createElement('select');
|
||||
select.id = 'chatbot-summary-source-select';
|
||||
select.className = 'chatbot-floating-selector';
|
||||
|
||||
optConf.values.forEach((val, idx) => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = val;
|
||||
const rawText = optConf.texts[idx] || String(val);
|
||||
opt.textContent = rawText.replace(/^提供全文:/, '');
|
||||
select.appendChild(opt);
|
||||
});
|
||||
|
||||
window.chatbotActiveOptions = window.chatbotActiveOptions || {};
|
||||
select.value = window.chatbotActiveOptions.summarySource || optConf.defaultKey || optConf.values[0];
|
||||
wrapper.classList.toggle('is-active', select.value !== optConf.defaultKey);
|
||||
|
||||
select.addEventListener('change', function() {
|
||||
window.chatbotActiveOptions = window.chatbotActiveOptions || {};
|
||||
window.chatbotActiveOptions.summarySource = select.value;
|
||||
wrapper.classList.toggle('is-active', select.value !== optConf.defaultKey);
|
||||
if (typeof globalUpdateUICallback === 'function') globalUpdateUICallback();
|
||||
else console.error("ChatbotFloatingOptionsUI: globalUpdateUICallback is not provided or not a function.");
|
||||
});
|
||||
|
||||
wrapper.appendChild(labelSpan);
|
||||
wrapper.appendChild(select);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// 默认:沿用按钮
|
||||
const optionButton = document.createElement('button');
|
||||
optionButton.id = `chatbot-option-${optConf.key}`;
|
||||
optionButton.style.cssText = `
|
||||
background: none;
|
||||
border: none;
|
||||
color: #4b5563;
|
||||
cursor: pointer;
|
||||
padding: 2px 4px;
|
||||
font-size: 11px;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s, color 0.2s;
|
||||
`;
|
||||
optionButton.title = optConf.title;
|
||||
|
||||
optionButton.onclick = function() {
|
||||
window.chatbotActiveOptions = window.chatbotActiveOptions || {};
|
||||
|
||||
if (optConf.isDisabled) {
|
||||
console.log(`${optConf.key} clicked, but is disabled.`);
|
||||
if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
||||
ChatbotUtils.showToast(`${optConf.texts[0]} 功能开发中,暂不可用。`, 'info', 2000);
|
||||
} else {
|
||||
alert(`${optConf.texts[0]} 功能开发中,暂不可用。`);
|
||||
}
|
||||
return; // 阻止后续逻辑执行
|
||||
}
|
||||
|
||||
if (optConf.isPlaceholder) {
|
||||
console.log(`${optConf.key} clicked, placeholder for future feature.`);
|
||||
if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
||||
ChatbotUtils.showToast(`${optConf.texts[0]} 功能正在开发中。`, 'info', 2000);
|
||||
} else {
|
||||
alert(`${optConf.texts[0]} 功能正在开发中。`);
|
||||
}
|
||||
} else if (optConf.isAction && optConf.key === 'semanticGroups') {
|
||||
if (window.SemanticGroupsUI && typeof window.SemanticGroupsUI.toggle === 'function') {
|
||||
window.SemanticGroupsUI.toggle();
|
||||
} else if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
||||
ChatbotUtils.showToast('意群面板未就绪', 'warning', 2000);
|
||||
} else {
|
||||
alert('意群面板未就绪');
|
||||
}
|
||||
} else {
|
||||
const currentValue = window.chatbotActiveOptions[optConf.key];
|
||||
if (optConf.key === 'contentLengthStrategy') {
|
||||
window.chatbotActiveOptions.contentLengthStrategy = currentValue === optConf.values[0] ? optConf.values[1] : optConf.values[0];
|
||||
} else if (optConf.key === 'multiHopRetrieval') {
|
||||
window.chatbotActiveOptions.multiHopRetrieval = !currentValue;
|
||||
// 传统多轮检索开启时,自动关闭ReAct模式(避免冲突)
|
||||
if (window.chatbotActiveOptions.multiHopRetrieval) {
|
||||
window.chatbotActiveOptions.useReActMode = false;
|
||||
}
|
||||
} else if (optConf.key === 'streamingRetrieval') {
|
||||
window.chatbotActiveOptions.streamingRetrieval = !currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof globalUpdateUICallback === 'function') {
|
||||
globalUpdateUICallback(); // 更新UI以反映选项变化
|
||||
} else {
|
||||
console.error("ChatbotFloatingOptionsUI: globalUpdateUICallback is not provided or not a function.");
|
||||
}
|
||||
};
|
||||
|
||||
return optionButton;
|
||||
})();
|
||||
|
||||
floatingOptionsContainer.appendChild(optionEl);
|
||||
|
||||
if (index < _chatbotOptionsConfig.length - 1) {
|
||||
const nextOptConf = _chatbotOptionsConfig[index + 1];
|
||||
const separator = document.createElement('span');
|
||||
separator.id = `chatbot-separator-${nextOptConf.key}`;
|
||||
separator.textContent = '丨';
|
||||
separator.style.color = '#cbd5e1';
|
||||
separator.style.margin = '0 2px';
|
||||
floatingOptionsContainer.appendChild(separator);
|
||||
}
|
||||
});
|
||||
|
||||
optionButton.onclick = function() {
|
||||
if (optConf.isDisabled) {
|
||||
console.log(`${optConf.key} clicked, but is disabled.`);
|
||||
if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
||||
ChatbotUtils.showToast(`${optConf.texts[0]} 功能开发中,暂不可用。`, 'info', 2000);
|
||||
} else {
|
||||
alert(`${optConf.texts[0]} 功能开发中,暂不可用。`);
|
||||
}
|
||||
return; // 阻止后续逻辑执行
|
||||
}
|
||||
if (optConf.isPlaceholder) {
|
||||
console.log(`${optConf.key} clicked, placeholder for future feature.`);
|
||||
if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
||||
ChatbotUtils.showToast(`${optConf.texts[0]} 功能正在开发中。`, 'info', 2000);
|
||||
} else {
|
||||
alert(`${optConf.texts[0]} 功能正在开发中。`);
|
||||
}
|
||||
} else if (optConf.isAction && optConf.key === 'semanticGroups') {
|
||||
if (window.SemanticGroupsUI && typeof window.SemanticGroupsUI.toggle === 'function') {
|
||||
window.SemanticGroupsUI.toggle();
|
||||
} else if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
||||
ChatbotUtils.showToast('意群面板未就绪', 'warning', 2000);
|
||||
} else {
|
||||
alert('意群面板未就绪');
|
||||
}
|
||||
} else {
|
||||
const currentValue = window.chatbotActiveOptions[optConf.key];
|
||||
if (optConf.key === 'useContext') {
|
||||
window.chatbotActiveOptions.useContext = !currentValue;
|
||||
} else if (optConf.key === 'useReActMode') {
|
||||
window.chatbotActiveOptions.useReActMode = !currentValue;
|
||||
// ReAct模式开启时,自动关闭传统多轮检索(避免冲突)
|
||||
if (window.chatbotActiveOptions.useReActMode) {
|
||||
window.chatbotActiveOptions.multiHopRetrieval = false;
|
||||
}
|
||||
} else if (optConf.key === 'contentLengthStrategy') {
|
||||
window.chatbotActiveOptions.contentLengthStrategy = currentValue === optConf.values[0] ? optConf.values[1] : optConf.values[0];
|
||||
} else if (optConf.key === 'multiHopRetrieval') {
|
||||
window.chatbotActiveOptions.multiHopRetrieval = !currentValue;
|
||||
// 传统多轮检索开启时,自动关闭ReAct模式(避免冲突)
|
||||
if (window.chatbotActiveOptions.multiHopRetrieval) {
|
||||
window.chatbotActiveOptions.useReActMode = false;
|
||||
}
|
||||
} else if (optConf.key === 'streamingRetrieval') {
|
||||
window.chatbotActiveOptions.streamingRetrieval = !currentValue;
|
||||
} else if (optConf.key === 'summarySource') {
|
||||
const currentIndex = optConf.values.indexOf(currentValue);
|
||||
const nextIndex = (currentIndex + 1) % optConf.values.length;
|
||||
window.chatbotActiveOptions.summarySource = optConf.values[nextIndex];
|
||||
}
|
||||
}
|
||||
if (typeof globalUpdateUICallback === 'function') {
|
||||
globalUpdateUICallback(); // 更新UI以反映选项变化
|
||||
} else {
|
||||
console.error("ChatbotFloatingOptionsUI: globalUpdateUICallback is not provided or not a function.");
|
||||
}
|
||||
};
|
||||
floatingOptionsContainer.appendChild(optionButton);
|
||||
|
||||
if (index < _chatbotOptionsConfig.length - 1) {
|
||||
const nextOptConf = _chatbotOptionsConfig[index + 1];
|
||||
const separator = document.createElement('span');
|
||||
separator.id = `chatbot-separator-${nextOptConf.key}`;
|
||||
separator.textContent = '丨';
|
||||
separator.style.color = '#cbd5e1';
|
||||
separator.style.margin = '0 2px';
|
||||
floatingOptionsContainer.appendChild(separator);
|
||||
}
|
||||
});
|
||||
|
||||
// 将创建的选项栏插入到父容器的合适位置
|
||||
const selectedImagesPreview = parentElement.querySelector('#chatbot-selected-images-preview');
|
||||
if (selectedImagesPreview) {
|
||||
parentElement.insertBefore(floatingOptionsContainer, selectedImagesPreview);
|
||||
// 将创建的选项栏插入到父容器的合适位置:放在输入框容器(chatbot-input-wrapper)后面
|
||||
const inputWrapper = parentElement.querySelector('#chatbot-input-wrapper, .chatbot-input-wrapper');
|
||||
if (inputWrapper && inputWrapper.parentNode === parentElement) {
|
||||
parentElement.insertBefore(floatingOptionsContainer, inputWrapper.nextSibling);
|
||||
} else if (inputWrapper && inputWrapper.parentNode) {
|
||||
inputWrapper.parentNode.insertBefore(floatingOptionsContainer, inputWrapper.nextSibling);
|
||||
} else {
|
||||
const mainInputDiv = parentElement.querySelector('div[style*="display:flex;align-items:center;gap:12px;"]');
|
||||
if (mainInputDiv) {
|
||||
parentElement.insertBefore(floatingOptionsContainer, mainInputDiv);
|
||||
} else {
|
||||
parentElement.appendChild(floatingOptionsContainer); // Fallback
|
||||
}
|
||||
parentElement.appendChild(floatingOptionsContainer); // Fallback
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新浮动高级选项栏中各个按钮的显示状态(文本、样式、可见性)。
|
||||
*/
|
||||
function _updateFloatingOptionsDisplay() {
|
||||
const floatingOptionsContainer = document.getElementById('chatbot-floating-options');
|
||||
if (!floatingOptionsContainer) return;
|
||||
function _updateFloatingOptionsDisplay() {
|
||||
const floatingOptionsContainer = document.getElementById('chatbot-floating-options');
|
||||
if (!floatingOptionsContainer) return;
|
||||
window.chatbotActiveOptions = window.chatbotActiveOptions || {};
|
||||
|
||||
_chatbotOptionsConfig.forEach(optConf => {
|
||||
const button = document.getElementById(`chatbot-option-${optConf.key}`);
|
||||
// 注意:分隔符ID是基于 *下一个* 选项的key来创建的,所以查找ID为 chatbot-separator-NEXT_KEY
|
||||
_chatbotOptionsConfig.forEach(optConf => {
|
||||
const button = document.getElementById(`chatbot-option-${optConf.key}`);
|
||||
// 注意:分隔符ID是基于 *下一个* 选项的key来创建的,所以查找ID为 chatbot-separator-NEXT_KEY
|
||||
// 但是其显示与否是基于 *当前* 按钮的显示状态
|
||||
|
||||
if (button) {
|
||||
|
|
@ -238,42 +317,42 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
|||
}
|
||||
});
|
||||
|
||||
// 第三遍:更新按钮文本和样式
|
||||
_chatbotOptionsConfig.forEach(optConf => {
|
||||
const button = document.getElementById(`chatbot-option-${optConf.key}`);
|
||||
// 第三遍:更新按钮文本和样式
|
||||
_chatbotOptionsConfig.forEach(optConf => {
|
||||
const button = document.getElementById(`chatbot-option-${optConf.key}`);
|
||||
|
||||
if (!button || button.style.display === 'none') {
|
||||
return; // 跳过不可见的按钮
|
||||
}
|
||||
if (!button || button.style.display === 'none') {
|
||||
return; // 跳过不可见的按钮
|
||||
}
|
||||
|
||||
const currentOptionValue = window.chatbotActiveOptions[optConf.key];
|
||||
let currentText = '';
|
||||
let color = '#4b5563';
|
||||
let fontWeight = 'normal';
|
||||
const currentOptionValue = window.chatbotActiveOptions[optConf.key];
|
||||
let currentText = '';
|
||||
let color = '#4b5563';
|
||||
let fontWeight = 'normal';
|
||||
let isActiveStyle = false;
|
||||
|
||||
if (optConf.isAction && optConf.key === 'semanticGroups') {
|
||||
const count = (window.data && Array.isArray(window.data.semanticGroups)) ? window.data.semanticGroups.length : 0;
|
||||
currentText = count > 0 ? `意群(${count})` : '意群';
|
||||
// 显示为激活风格以便更醒目(当有意群时)
|
||||
if (count > 0) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
||||
} else if (optConf.isPlaceholder) {
|
||||
currentText = optConf.texts[0];
|
||||
} else if (optConf.isDisabled) {
|
||||
// 禁用状态:固定显示灰色,无法切换
|
||||
currentText = optConf.texts[0];
|
||||
if (optConf.isAction && optConf.key === 'semanticGroups') {
|
||||
const count = (window.data && Array.isArray(window.data.semanticGroups)) ? window.data.semanticGroups.length : 0;
|
||||
currentText = count > 0 ? `意群(${count})` : '意群';
|
||||
// 显示为激活风格以便更醒目(当有意群时)
|
||||
if (count > 0) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
||||
} else if (optConf.key === 'useContext') {
|
||||
const isOn = !!currentOptionValue;
|
||||
const switchInput = document.getElementById('chatbot-use-context-switch');
|
||||
if (switchInput) switchInput.checked = isOn;
|
||||
button.classList.toggle('is-active', isOn);
|
||||
return;
|
||||
} else if (optConf.isPlaceholder) {
|
||||
currentText = optConf.texts[0];
|
||||
} else if (optConf.isDisabled) {
|
||||
// 禁用状态:固定显示灰色,无法切换
|
||||
currentText = optConf.texts[0];
|
||||
color = '#9ca3af'; // 灰色
|
||||
fontWeight = 'normal';
|
||||
isActiveStyle = false;
|
||||
button.style.opacity = '0.6'; // 降低透明度
|
||||
button.style.cursor = 'not-allowed'; // 禁用光标
|
||||
} else if (optConf.key === 'useContext') {
|
||||
currentText = currentOptionValue ? optConf.texts[1] : optConf.texts[0];
|
||||
if (currentOptionValue) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
||||
} else if (optConf.key === 'useReActMode') {
|
||||
currentText = currentOptionValue ? optConf.texts[1] : optConf.texts[0];
|
||||
if (currentOptionValue) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
||||
} else if (optConf.key === 'contentLengthStrategy') {
|
||||
} else if (optConf.key === 'contentLengthStrategy') {
|
||||
currentText = currentOptionValue === optConf.defaultKey ? optConf.texts[0] : optConf.texts[1];
|
||||
if (currentOptionValue !== optConf.defaultKey) {
|
||||
color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true;
|
||||
|
|
@ -281,20 +360,19 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
|||
} else if (optConf.key === 'multiHopRetrieval') {
|
||||
currentText = currentOptionValue ? optConf.texts[1] : optConf.texts[0];
|
||||
if (currentOptionValue) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
||||
} else if (optConf.key === 'streamingRetrieval') {
|
||||
currentText = currentOptionValue ? optConf.texts[1] : optConf.texts[0];
|
||||
if (currentOptionValue) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
||||
} else if (optConf.key === 'summarySource') {
|
||||
const currentIndex = optConf.values.indexOf(currentOptionValue);
|
||||
currentText = optConf.texts[currentIndex] || optConf.texts[0];
|
||||
// 对于 summarySource, 'ocr' (index 0) 是默认状态,'none' (index 1) 和 'translation' (index 2) 算作激活状态
|
||||
if (currentOptionValue !== optConf.defaultKey) {
|
||||
color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true;
|
||||
}
|
||||
}
|
||||
button.textContent = currentText;
|
||||
button.style.color = color;
|
||||
button.style.fontWeight = fontWeight;
|
||||
} else if (optConf.key === 'streamingRetrieval') {
|
||||
currentText = currentOptionValue ? optConf.texts[1] : optConf.texts[0];
|
||||
if (currentOptionValue) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
||||
} else if (optConf.key === 'summarySource') {
|
||||
const select = document.getElementById('chatbot-summary-source-select');
|
||||
const desiredValue = currentOptionValue || optConf.defaultKey || optConf.values[0];
|
||||
if (select && select.value !== desiredValue) select.value = desiredValue;
|
||||
button.classList.toggle('is-active', desiredValue !== optConf.defaultKey);
|
||||
return;
|
||||
}
|
||||
button.textContent = currentText;
|
||||
button.style.color = color;
|
||||
button.style.fontWeight = fontWeight;
|
||||
|
||||
if (isActiveStyle) {
|
||||
button.style.backgroundColor = 'rgba(59, 130, 246, 0.1)'; // 淡蓝色背景表示激活
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ window.ChatbotPresetQuestionsUI = {
|
|||
headerLeftGroup.style.display = 'flex';
|
||||
headerLeftGroup.style.alignItems = 'center';
|
||||
headerLeftGroup.style.gap = '8px';
|
||||
headerLeftGroup.appendChild(presetTitle);
|
||||
headerLeftGroup.appendChild(presetToggleBtn);
|
||||
newPresetHeader.appendChild(headerLeftGroup);
|
||||
// headerLeftGroup.appendChild(presetTitle);
|
||||
// headerLeftGroup.appendChild(presetToggleBtn);
|
||||
// newPresetHeader.appendChild(headerLeftGroup);
|
||||
|
||||
// 齿轮按钮(模型配置)- 始终显示
|
||||
const gearBtn = document.createElement('button');
|
||||
|
|
@ -92,8 +92,8 @@ window.ChatbotPresetQuestionsUI = {
|
|||
updateChatbotUICallback(); // 调用主UI更新
|
||||
}
|
||||
};
|
||||
newPresetHeader.appendChild(gearBtn);
|
||||
presetContainer.appendChild(newPresetHeader);
|
||||
// newPresetHeader.appendChild(gearBtn);
|
||||
// presetContainer.appendChild(newPresetHeader);
|
||||
|
||||
const newPresetBody = document.createElement('div');
|
||||
newPresetBody.id = 'chatbot-preset-body';
|
||||
|
|
@ -114,31 +114,31 @@ window.ChatbotPresetQuestionsUI = {
|
|||
|
||||
|
||||
// 填充预设问题按钮
|
||||
const presetQuestions = (window.ChatbotPreset && window.ChatbotPreset.PRESET_QUESTIONS) ? window.ChatbotPreset.PRESET_QUESTIONS : [
|
||||
'总结本文', '有哪些关键公式?', '研究背景与意义?', '研究方法及发现?',
|
||||
'应用与前景?', '用通俗语言解释全文', '生成思维导图🧠', '生成流程图🔄',
|
||||
'生成更多配图🎨'
|
||||
];
|
||||
presetQuestions.forEach(q => {
|
||||
const button = document.createElement('button');
|
||||
button.className = 'preset-btn';
|
||||
// 使用 encodeURIComponent/decodeURIComponent 来处理特殊字符
|
||||
button.onclick = function() {
|
||||
const text = decodeURIComponent(encodeURIComponent(q));
|
||||
// 对“生成更多配图”做特殊处理:只帮用户打出前缀 [加入配图],不直接发送复杂提示
|
||||
if (text.startsWith('生成更多配图')) {
|
||||
const input = document.getElementById('chatbot-input');
|
||||
if (input) {
|
||||
input.value = '[加入配图] ';
|
||||
input.focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
handlePresetQuestionCallback(text);
|
||||
};
|
||||
button.textContent = q;
|
||||
newPresetBody.appendChild(button);
|
||||
});
|
||||
// const presetQuestions = (window.ChatbotPreset && window.ChatbotPreset.PRESET_QUESTIONS) ? window.ChatbotPreset.PRESET_QUESTIONS : [
|
||||
// '总结本文', '有哪些关键公式?', '研究背景与意义?', '研究方法及发现?',
|
||||
// '应用与前景?', '用通俗语言解释全文', '生成思维导图🧠', '生成流程图🔄',
|
||||
// '生成更多配图🎨'
|
||||
// ];
|
||||
// presetQuestions.forEach(q => {
|
||||
// const button = document.createElement('button');
|
||||
// button.className = 'preset-btn';
|
||||
// // 使用 encodeURIComponent/decodeURIComponent 来处理特殊字符
|
||||
// button.onclick = function() {
|
||||
// const text = decodeURIComponent(encodeURIComponent(q));
|
||||
// // 对“生成更多配图”做特殊处理:只帮用户打出前缀 [加入配图],不直接发送复杂提示
|
||||
// if (text.startsWith('生成更多配图')) {
|
||||
// const input = document.getElementById('chatbot-input');
|
||||
// if (input) {
|
||||
// input.value = '[加入配图] ';
|
||||
// input.focus();
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// handlePresetQuestionCallback(text);
|
||||
// };
|
||||
// button.textContent = q;
|
||||
// newPresetBody.appendChild(button);
|
||||
// });
|
||||
|
||||
// 自动收起逻辑 (依赖全局状态 window.isPresetQuestionsCollapsed, window.presetAutoCollapseTriggeredForDoc, window.isModelSelectorOpen 和 ChatbotCore)
|
||||
let userMessageCount = 0;
|
||||
|
|
|
|||
|
|
@ -1190,7 +1190,7 @@ function initChatbotUI() {
|
|||
</button>
|
||||
</div>
|
||||
<!-- 标题栏 (可拖拽移动窗口) -->
|
||||
<div id="chatbot-title-bar" class="chatbot-draggable-header" style="padding:12px 24px;display:flex;align-items:center;gap:8px;border-bottom:1px dashed rgba(0,0,0,0.1);flex-shrink:0;">
|
||||
<div id="chatbot-title-bar" class="chatbot-draggable-header" style="padding:12px 24px;display:flex;justify-content:center;align-items:center;gap:8px;border-bottom:1px dashed rgba(0,0,0,0.1);flex-shrink:0;">
|
||||
<div style="width:32px;height:32px;border-radius:16px;background:linear-gradient(135deg,#3b82f6,#1d4ed8);display:flex;align-items:center;justify-content:center;display:none;">
|
||||
<i class="fa-solid fa-robot" style="font-size: 14px; color: white;"></i>
|
||||
</div>
|
||||
|
|
@ -1203,7 +1203,7 @@ function initChatbotUI() {
|
|||
</div>
|
||||
<!-- 输入区域容器 (Refactored) -->
|
||||
<div id="chatbot-input-container" class="chatbot-input-container">
|
||||
<!-- 浮动高级选项将由JS插入此处 -->
|
||||
<!-- 浮动高级选项将由JS插入到 chatbot-input-wrapper 后面 -->
|
||||
<!-- 已选图片预览区 -->
|
||||
<div id="chatbot-selected-images-preview" class="chatbot-image-preview-area">
|
||||
{/* 图片预览由 ChatbotImageUtils.updateSelectedImagesPreview 更新 */}
|
||||
|
|
@ -1223,10 +1223,10 @@ function initChatbotUI() {
|
|||
<iconify-icon icon="carbon:document-pdf" width="20"></iconify-icon>
|
||||
</button>
|
||||
<!-- 文本输入框 -->
|
||||
<input id="chatbot-input" type="text" placeholder="请输入问题..."
|
||||
<textarea id="chatbot-input" type="text" placeholder="请输入问题..."
|
||||
class="chatbot-input-field"
|
||||
onkeydown="if(event.key==='Enter'){window.handleChatbotSend();}"
|
||||
/>
|
||||
></textarea>
|
||||
<!-- 发送按钮 -->
|
||||
<button id="chatbot-send-btn"
|
||||
class="chatbot-input-btn chatbot-send-btn"
|
||||
|
|
@ -1250,12 +1250,13 @@ function initChatbotUI() {
|
|||
</button>
|
||||
</div>
|
||||
<!-- 免责声明 -->
|
||||
<div class="chatbot-disclaimer">
|
||||
<p style="margin:0;">AI助手可能会犯错。请核实重要信息。</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
// <div class="chatbot-disclaimer">
|
||||
// <p style="margin:0;">AI助手可能会犯错。请核实重要信息。</p>
|
||||
// </div>
|
||||
document.body.appendChild(modal);
|
||||
}
|
||||
|
||||
|
|
@ -1265,6 +1266,44 @@ function initChatbotUI() {
|
|||
window.ChatbotFloatingOptionsUI.createBar(inputContainerElement, updateChatbotUI);
|
||||
}
|
||||
|
||||
// 将输入栏的核心按钮移动到浮动选项栏中
|
||||
// 目标容器由 ChatbotFloatingOptionsUI.createBar 创建:#chatbot-floating-options
|
||||
(function movePrimaryButtonsIntoFloatingOptions() {
|
||||
const floatingOptionsContainer = document.getElementById('chatbot-floating-options');
|
||||
if (!floatingOptionsContainer) return;
|
||||
|
||||
const addImageBtn = document.getElementById('chatbot-add-image-btn');
|
||||
const providePdfBtn = document.getElementById('chatbot-provide-pdf-btn');
|
||||
const sendBtn = document.getElementById('chatbot-send-btn');
|
||||
|
||||
// 1) 先把“添加图片/提供PDF”放到浮动选项栏最前面
|
||||
const prefixFragment = document.createDocumentFragment();
|
||||
for (const el of [addImageBtn, providePdfBtn]) {
|
||||
if (!el) continue;
|
||||
if (el.parentElement === floatingOptionsContainer) continue;
|
||||
prefixFragment.appendChild(el);
|
||||
}
|
||||
if (prefixFragment.childNodes.length) {
|
||||
floatingOptionsContainer.insertBefore(prefixFragment, floatingOptionsContainer.firstChild);
|
||||
}
|
||||
|
||||
// 2) 再把“发送”放到 chatbot-option-summarySource 后面
|
||||
if (!sendBtn) return;
|
||||
if (sendBtn.parentElement === floatingOptionsContainer) {
|
||||
// 仍然允许重新定位(appendChild 会自动移动节点)
|
||||
}
|
||||
const summarySourceOptionBtn = document.getElementById('chatbot-option-summarySource');
|
||||
if (summarySourceOptionBtn && summarySourceOptionBtn.parentElement === floatingOptionsContainer) {
|
||||
if (summarySourceOptionBtn.nextSibling) {
|
||||
floatingOptionsContainer.insertBefore(sendBtn, summarySourceOptionBtn.nextSibling);
|
||||
} else {
|
||||
floatingOptionsContainer.appendChild(sendBtn);
|
||||
}
|
||||
} else {
|
||||
floatingOptionsContainer.appendChild(sendBtn);
|
||||
}
|
||||
})();
|
||||
|
||||
// --- 核心控制按钮事件绑定 ---
|
||||
// 浮动模式切换按钮点击事件
|
||||
document.getElementById('chatbot-float-toggle-btn').onclick = function() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue