feat(chatbot): 重构输入区与高级选项栏
This commit is contained in:
parent
3890cca114
commit
6a25d6aa3c
|
|
@ -22,7 +22,7 @@
|
||||||
/* ==================== Chatbot Modal Window (High-end Minimalist) ==================== */
|
/* ==================== Chatbot Modal Window (High-end Minimalist) ==================== */
|
||||||
|
|
||||||
.chatbot-window {
|
.chatbot-window {
|
||||||
background: var(--color-bg-base); /* Pure white background */
|
|
||||||
max-width: 720px;
|
max-width: 720px;
|
||||||
width: 92vw;
|
width: 92vw;
|
||||||
min-height: 520px;
|
min-height: 520px;
|
||||||
|
|
@ -30,7 +30,6 @@
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
|
|
||||||
/* The Shadow Fix: Using variable for consistency and lightness */
|
/* The Shadow Fix: Using variable for consistency and lightness */
|
||||||
box-shadow: var(--shadow-modal);
|
|
||||||
border: 1px solid var(--color-border-light); /* Very subtle border */
|
border: 1px solid var(--color-border-light); /* Very subtle border */
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -86,6 +85,7 @@
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -291,13 +291,13 @@ body.dark #chatbot-toast {
|
||||||
/* 用户消息容器 */
|
/* 用户消息容器 */
|
||||||
.user-message-container {
|
.user-message-container {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding-left: 20%;
|
/* padding-left: 20%; */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 助手消息容器 */
|
/* 助手消息容器 */
|
||||||
.assistant-message-container {
|
.assistant-message-container {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
padding-right: 10%; /* 减少右侧留白,利用更多空间 */
|
/* padding-right: 10%; */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
IMPORTANT: No top padding here anymore.
|
IMPORTANT: No top padding here anymore.
|
||||||
|
|
@ -344,6 +344,7 @@ body.dark #chatbot-toast {
|
||||||
.chat-bubble.assistant {
|
.chat-bubble.assistant {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--color-text-primary);
|
color: var(--color-text-primary);
|
||||||
|
width: 100%;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|
@ -493,9 +494,14 @@ body.dark #chatbot-toast {
|
||||||
|
|
||||||
/* 输入区容器 */
|
/* 输入区容器 */
|
||||||
.chatbot-input-container {
|
.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);
|
border-top: 1px solid rgba(0, 0, 0, 0.03);
|
||||||
background: rgba(255, 255, 255, 0.8); /* 稍微降低不透明度以增强毛玻璃感 */
|
background: #F8F9FA; /* 稍微降低不透明度以增强毛玻璃感 */
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
-webkit-backdrop-filter: blur(20px);
|
-webkit-backdrop-filter: blur(20px);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
@ -506,9 +512,9 @@ body.dark #chatbot-toast {
|
||||||
/* 输入区内部 Wrapper */
|
/* 输入区内部 Wrapper */
|
||||||
.chatbot-input-wrapper {
|
.chatbot-input-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
background: rgba(249, 250, 251, 0.8); /* var(--slate-50) with opacity */
|
background: rgba(249, 250, 251, 0.8); /* var(--slate-50) with opacity */
|
||||||
|
flex: 1;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
padding: 8px 8px 8px 14px;
|
padding: 8px 8px 8px 14px;
|
||||||
|
|
@ -517,14 +523,107 @@ body.dark #chatbot-toast {
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatbot-input-wrapper:focus-within {
|
.chatbot-input-wrapper:focus-within {
|
||||||
background: white;
|
/* background: white; */
|
||||||
border-color: var(--slate-200); /* 柔和的边框颜色,避免刺眼的蓝线 */
|
/* border-color: var(--slate-200); 柔和的边框颜色,避免刺眼的蓝线 */
|
||||||
/*
|
/*
|
||||||
使用更柔和的扩散阴影,而不是实心光晕
|
使用更柔和的扩散阴影,而不是实心光晕
|
||||||
原先的 0 0 0 3px 会产生类似边框的实心线效果
|
原先的 0 0 0 3px 会产生类似边框的实心线效果
|
||||||
改为 0 0 0 4px rgba(...) 并降低透明度,使其更像光晕
|
改为 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 输入框 */
|
/* 输入框 */
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,8 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
const _chatbotOptionsConfig = [
|
const _chatbotOptionsConfig = [
|
||||||
{ key: 'semanticGroups', texts: ['意群'], title: '查看/搜索意群', activeStyleColor: '#059669', isAction: true },
|
{ key: 'semanticGroups', texts: ['意群'], title: '查看/搜索意群', activeStyleColor: '#059669', isAction: true },
|
||||||
{ key: 'useContext', texts: ['上下文:关', '上下文:开'], values: [false, true], title: '切换是否使用对话历史', activeStyleColor: '#1d4ed8' },
|
{ 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: '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: '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: '记忆管理功能 (待实现)' }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -35,7 +32,7 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
floatingOptionsContainer.id = 'chatbot-floating-options';
|
floatingOptionsContainer.id = 'chatbot-floating-options';
|
||||||
floatingOptionsContainer.style.cssText = `
|
floatingOptionsContainer.style.cssText = `
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 4px 0 8px 0;
|
padding: 4px 0 8px 0;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
|
@ -45,6 +42,94 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
`;
|
`;
|
||||||
|
|
||||||
_chatbotOptionsConfig.forEach((optConf, index) => {
|
_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');
|
const optionButton = document.createElement('button');
|
||||||
optionButton.id = `chatbot-option-${optConf.key}`;
|
optionButton.id = `chatbot-option-${optConf.key}`;
|
||||||
optionButton.style.cssText = `
|
optionButton.style.cssText = `
|
||||||
|
|
@ -60,6 +145,8 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
optionButton.title = optConf.title;
|
optionButton.title = optConf.title;
|
||||||
|
|
||||||
optionButton.onclick = function() {
|
optionButton.onclick = function() {
|
||||||
|
window.chatbotActiveOptions = window.chatbotActiveOptions || {};
|
||||||
|
|
||||||
if (optConf.isDisabled) {
|
if (optConf.isDisabled) {
|
||||||
console.log(`${optConf.key} clicked, but is disabled.`);
|
console.log(`${optConf.key} clicked, but is disabled.`);
|
||||||
if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
||||||
|
|
@ -69,6 +156,7 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
}
|
}
|
||||||
return; // 阻止后续逻辑执行
|
return; // 阻止后续逻辑执行
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optConf.isPlaceholder) {
|
if (optConf.isPlaceholder) {
|
||||||
console.log(`${optConf.key} clicked, placeholder for future feature.`);
|
console.log(`${optConf.key} clicked, placeholder for future feature.`);
|
||||||
if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
if (typeof ChatbotUtils !== 'undefined' && ChatbotUtils.showToast) {
|
||||||
|
|
@ -86,15 +174,7 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const currentValue = window.chatbotActiveOptions[optConf.key];
|
const currentValue = window.chatbotActiveOptions[optConf.key];
|
||||||
if (optConf.key === 'useContext') {
|
if (optConf.key === 'contentLengthStrategy') {
|
||||||
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];
|
window.chatbotActiveOptions.contentLengthStrategy = currentValue === optConf.values[0] ? optConf.values[1] : optConf.values[0];
|
||||||
} else if (optConf.key === 'multiHopRetrieval') {
|
} else if (optConf.key === 'multiHopRetrieval') {
|
||||||
window.chatbotActiveOptions.multiHopRetrieval = !currentValue;
|
window.chatbotActiveOptions.multiHopRetrieval = !currentValue;
|
||||||
|
|
@ -104,19 +184,20 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
}
|
}
|
||||||
} else if (optConf.key === 'streamingRetrieval') {
|
} else if (optConf.key === 'streamingRetrieval') {
|
||||||
window.chatbotActiveOptions.streamingRetrieval = !currentValue;
|
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') {
|
if (typeof globalUpdateUICallback === 'function') {
|
||||||
globalUpdateUICallback(); // 更新UI以反映选项变化
|
globalUpdateUICallback(); // 更新UI以反映选项变化
|
||||||
} else {
|
} else {
|
||||||
console.error("ChatbotFloatingOptionsUI: globalUpdateUICallback is not provided or not a function.");
|
console.error("ChatbotFloatingOptionsUI: globalUpdateUICallback is not provided or not a function.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
floatingOptionsContainer.appendChild(optionButton);
|
|
||||||
|
return optionButton;
|
||||||
|
})();
|
||||||
|
|
||||||
|
floatingOptionsContainer.appendChild(optionEl);
|
||||||
|
|
||||||
if (index < _chatbotOptionsConfig.length - 1) {
|
if (index < _chatbotOptionsConfig.length - 1) {
|
||||||
const nextOptConf = _chatbotOptionsConfig[index + 1];
|
const nextOptConf = _chatbotOptionsConfig[index + 1];
|
||||||
|
|
@ -129,19 +210,16 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 将创建的选项栏插入到父容器的合适位置
|
// 将创建的选项栏插入到父容器的合适位置:放在输入框容器(chatbot-input-wrapper)后面
|
||||||
const selectedImagesPreview = parentElement.querySelector('#chatbot-selected-images-preview');
|
const inputWrapper = parentElement.querySelector('#chatbot-input-wrapper, .chatbot-input-wrapper');
|
||||||
if (selectedImagesPreview) {
|
if (inputWrapper && inputWrapper.parentNode === parentElement) {
|
||||||
parentElement.insertBefore(floatingOptionsContainer, selectedImagesPreview);
|
parentElement.insertBefore(floatingOptionsContainer, inputWrapper.nextSibling);
|
||||||
} else {
|
} else if (inputWrapper && inputWrapper.parentNode) {
|
||||||
const mainInputDiv = parentElement.querySelector('div[style*="display:flex;align-items:center;gap:12px;"]');
|
inputWrapper.parentNode.insertBefore(floatingOptionsContainer, inputWrapper.nextSibling);
|
||||||
if (mainInputDiv) {
|
|
||||||
parentElement.insertBefore(floatingOptionsContainer, mainInputDiv);
|
|
||||||
} else {
|
} else {
|
||||||
parentElement.appendChild(floatingOptionsContainer); // Fallback
|
parentElement.appendChild(floatingOptionsContainer); // Fallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新浮动高级选项栏中各个按钮的显示状态(文本、样式、可见性)。
|
* 更新浮动高级选项栏中各个按钮的显示状态(文本、样式、可见性)。
|
||||||
|
|
@ -149,6 +227,7 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
function _updateFloatingOptionsDisplay() {
|
function _updateFloatingOptionsDisplay() {
|
||||||
const floatingOptionsContainer = document.getElementById('chatbot-floating-options');
|
const floatingOptionsContainer = document.getElementById('chatbot-floating-options');
|
||||||
if (!floatingOptionsContainer) return;
|
if (!floatingOptionsContainer) return;
|
||||||
|
window.chatbotActiveOptions = window.chatbotActiveOptions || {};
|
||||||
|
|
||||||
_chatbotOptionsConfig.forEach(optConf => {
|
_chatbotOptionsConfig.forEach(optConf => {
|
||||||
const button = document.getElementById(`chatbot-option-${optConf.key}`);
|
const button = document.getElementById(`chatbot-option-${optConf.key}`);
|
||||||
|
|
@ -257,6 +336,12 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
currentText = count > 0 ? `意群(${count})` : '意群';
|
currentText = count > 0 ? `意群(${count})` : '意群';
|
||||||
// 显示为激活风格以便更醒目(当有意群时)
|
// 显示为激活风格以便更醒目(当有意群时)
|
||||||
if (count > 0) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
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) {
|
} else if (optConf.isPlaceholder) {
|
||||||
currentText = optConf.texts[0];
|
currentText = optConf.texts[0];
|
||||||
} else if (optConf.isDisabled) {
|
} else if (optConf.isDisabled) {
|
||||||
|
|
@ -267,12 +352,6 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
isActiveStyle = false;
|
isActiveStyle = false;
|
||||||
button.style.opacity = '0.6'; // 降低透明度
|
button.style.opacity = '0.6'; // 降低透明度
|
||||||
button.style.cursor = 'not-allowed'; // 禁用光标
|
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];
|
currentText = currentOptionValue === optConf.defaultKey ? optConf.texts[0] : optConf.texts[1];
|
||||||
if (currentOptionValue !== optConf.defaultKey) {
|
if (currentOptionValue !== optConf.defaultKey) {
|
||||||
|
|
@ -285,12 +364,11 @@ if (typeof window.ChatbotFloatingOptionsScriptLoaded === 'undefined') {
|
||||||
currentText = currentOptionValue ? optConf.texts[1] : optConf.texts[0];
|
currentText = currentOptionValue ? optConf.texts[1] : optConf.texts[0];
|
||||||
if (currentOptionValue) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
if (currentOptionValue) { color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true; }
|
||||||
} else if (optConf.key === 'summarySource') {
|
} else if (optConf.key === 'summarySource') {
|
||||||
const currentIndex = optConf.values.indexOf(currentOptionValue);
|
const select = document.getElementById('chatbot-summary-source-select');
|
||||||
currentText = optConf.texts[currentIndex] || optConf.texts[0];
|
const desiredValue = currentOptionValue || optConf.defaultKey || optConf.values[0];
|
||||||
// 对于 summarySource, 'ocr' (index 0) 是默认状态,'none' (index 1) 和 'translation' (index 2) 算作激活状态
|
if (select && select.value !== desiredValue) select.value = desiredValue;
|
||||||
if (currentOptionValue !== optConf.defaultKey) {
|
button.classList.toggle('is-active', desiredValue !== optConf.defaultKey);
|
||||||
color = optConf.activeStyleColor; fontWeight = '600'; isActiveStyle = true;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
button.textContent = currentText;
|
button.textContent = currentText;
|
||||||
button.style.color = color;
|
button.style.color = color;
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,9 @@ window.ChatbotPresetQuestionsUI = {
|
||||||
headerLeftGroup.style.display = 'flex';
|
headerLeftGroup.style.display = 'flex';
|
||||||
headerLeftGroup.style.alignItems = 'center';
|
headerLeftGroup.style.alignItems = 'center';
|
||||||
headerLeftGroup.style.gap = '8px';
|
headerLeftGroup.style.gap = '8px';
|
||||||
headerLeftGroup.appendChild(presetTitle);
|
// headerLeftGroup.appendChild(presetTitle);
|
||||||
headerLeftGroup.appendChild(presetToggleBtn);
|
// headerLeftGroup.appendChild(presetToggleBtn);
|
||||||
newPresetHeader.appendChild(headerLeftGroup);
|
// newPresetHeader.appendChild(headerLeftGroup);
|
||||||
|
|
||||||
// 齿轮按钮(模型配置)- 始终显示
|
// 齿轮按钮(模型配置)- 始终显示
|
||||||
const gearBtn = document.createElement('button');
|
const gearBtn = document.createElement('button');
|
||||||
|
|
@ -92,8 +92,8 @@ window.ChatbotPresetQuestionsUI = {
|
||||||
updateChatbotUICallback(); // 调用主UI更新
|
updateChatbotUICallback(); // 调用主UI更新
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
newPresetHeader.appendChild(gearBtn);
|
// newPresetHeader.appendChild(gearBtn);
|
||||||
presetContainer.appendChild(newPresetHeader);
|
// presetContainer.appendChild(newPresetHeader);
|
||||||
|
|
||||||
const newPresetBody = document.createElement('div');
|
const newPresetBody = document.createElement('div');
|
||||||
newPresetBody.id = 'chatbot-preset-body';
|
newPresetBody.id = 'chatbot-preset-body';
|
||||||
|
|
@ -114,31 +114,31 @@ window.ChatbotPresetQuestionsUI = {
|
||||||
|
|
||||||
|
|
||||||
// 填充预设问题按钮
|
// 填充预设问题按钮
|
||||||
const presetQuestions = (window.ChatbotPreset && window.ChatbotPreset.PRESET_QUESTIONS) ? window.ChatbotPreset.PRESET_QUESTIONS : [
|
// const presetQuestions = (window.ChatbotPreset && window.ChatbotPreset.PRESET_QUESTIONS) ? window.ChatbotPreset.PRESET_QUESTIONS : [
|
||||||
'总结本文', '有哪些关键公式?', '研究背景与意义?', '研究方法及发现?',
|
// '总结本文', '有哪些关键公式?', '研究背景与意义?', '研究方法及发现?',
|
||||||
'应用与前景?', '用通俗语言解释全文', '生成思维导图🧠', '生成流程图🔄',
|
// '应用与前景?', '用通俗语言解释全文', '生成思维导图🧠', '生成流程图🔄',
|
||||||
'生成更多配图🎨'
|
// '生成更多配图🎨'
|
||||||
];
|
// ];
|
||||||
presetQuestions.forEach(q => {
|
// presetQuestions.forEach(q => {
|
||||||
const button = document.createElement('button');
|
// const button = document.createElement('button');
|
||||||
button.className = 'preset-btn';
|
// button.className = 'preset-btn';
|
||||||
// 使用 encodeURIComponent/decodeURIComponent 来处理特殊字符
|
// // 使用 encodeURIComponent/decodeURIComponent 来处理特殊字符
|
||||||
button.onclick = function() {
|
// button.onclick = function() {
|
||||||
const text = decodeURIComponent(encodeURIComponent(q));
|
// const text = decodeURIComponent(encodeURIComponent(q));
|
||||||
// 对“生成更多配图”做特殊处理:只帮用户打出前缀 [加入配图],不直接发送复杂提示
|
// // 对“生成更多配图”做特殊处理:只帮用户打出前缀 [加入配图],不直接发送复杂提示
|
||||||
if (text.startsWith('生成更多配图')) {
|
// if (text.startsWith('生成更多配图')) {
|
||||||
const input = document.getElementById('chatbot-input');
|
// const input = document.getElementById('chatbot-input');
|
||||||
if (input) {
|
// if (input) {
|
||||||
input.value = '[加入配图] ';
|
// input.value = '[加入配图] ';
|
||||||
input.focus();
|
// input.focus();
|
||||||
}
|
// }
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
handlePresetQuestionCallback(text);
|
// handlePresetQuestionCallback(text);
|
||||||
};
|
// };
|
||||||
button.textContent = q;
|
// button.textContent = q;
|
||||||
newPresetBody.appendChild(button);
|
// newPresetBody.appendChild(button);
|
||||||
});
|
// });
|
||||||
|
|
||||||
// 自动收起逻辑 (依赖全局状态 window.isPresetQuestionsCollapsed, window.presetAutoCollapseTriggeredForDoc, window.isModelSelectorOpen 和 ChatbotCore)
|
// 自动收起逻辑 (依赖全局状态 window.isPresetQuestionsCollapsed, window.presetAutoCollapseTriggeredForDoc, window.isModelSelectorOpen 和 ChatbotCore)
|
||||||
let userMessageCount = 0;
|
let userMessageCount = 0;
|
||||||
|
|
|
||||||
|
|
@ -1190,7 +1190,7 @@ function initChatbotUI() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</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;">
|
<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>
|
<i class="fa-solid fa-robot" style="font-size: 14px; color: white;"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1203,7 +1203,7 @@ function initChatbotUI() {
|
||||||
</div>
|
</div>
|
||||||
<!-- 输入区域容器 (Refactored) -->
|
<!-- 输入区域容器 (Refactored) -->
|
||||||
<div id="chatbot-input-container" class="chatbot-input-container">
|
<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">
|
<div id="chatbot-selected-images-preview" class="chatbot-image-preview-area">
|
||||||
{/* 图片预览由 ChatbotImageUtils.updateSelectedImagesPreview 更新 */}
|
{/* 图片预览由 ChatbotImageUtils.updateSelectedImagesPreview 更新 */}
|
||||||
|
|
@ -1223,10 +1223,10 @@ function initChatbotUI() {
|
||||||
<iconify-icon icon="carbon:document-pdf" width="20"></iconify-icon>
|
<iconify-icon icon="carbon:document-pdf" width="20"></iconify-icon>
|
||||||
</button>
|
</button>
|
||||||
<!-- 文本输入框 -->
|
<!-- 文本输入框 -->
|
||||||
<input id="chatbot-input" type="text" placeholder="请输入问题..."
|
<textarea id="chatbot-input" type="text" placeholder="请输入问题..."
|
||||||
class="chatbot-input-field"
|
class="chatbot-input-field"
|
||||||
onkeydown="if(event.key==='Enter'){window.handleChatbotSend();}"
|
onkeydown="if(event.key==='Enter'){window.handleChatbotSend();}"
|
||||||
/>
|
></textarea>
|
||||||
<!-- 发送按钮 -->
|
<!-- 发送按钮 -->
|
||||||
<button id="chatbot-send-btn"
|
<button id="chatbot-send-btn"
|
||||||
class="chatbot-input-btn chatbot-send-btn"
|
class="chatbot-input-btn chatbot-send-btn"
|
||||||
|
|
@ -1250,12 +1250,13 @@ function initChatbotUI() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- 免责声明 -->
|
<!-- 免责声明 -->
|
||||||
<div class="chatbot-disclaimer">
|
|
||||||
<p style="margin:0;">AI助手可能会犯错。请核实重要信息。</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
// <div class="chatbot-disclaimer">
|
||||||
|
// <p style="margin:0;">AI助手可能会犯错。请核实重要信息。</p>
|
||||||
|
// </div>
|
||||||
document.body.appendChild(modal);
|
document.body.appendChild(modal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1265,6 +1266,44 @@ function initChatbotUI() {
|
||||||
window.ChatbotFloatingOptionsUI.createBar(inputContainerElement, updateChatbotUI);
|
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() {
|
document.getElementById('chatbot-float-toggle-btn').onclick = function() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue