functioncall / index-缺显示搜索结果.html
mistpe's picture
Rename index.html to index-缺显示搜索结果.html
4daaa0e verified
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI 对话系统</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css">
<style>
:root {
--primary-color: #3498db;
--secondary-color: #2ecc71;
--background-color: #f5f5f5;
--chat-background: #ffffff;
--text-color: #333333;
--chat-bubble-user: #e8f5fe;
--chat-bubble-ai: #f0f0f0;
--sidebar-background: #ffffff;
--input-background: #ffffff;
--send-button-color: #4CAF50;
--console-background: #f8f9fa;
--console-text: #495057;
--fold-background: #f8f9fa;
--fold-text: #495057;
--border-color: transparent;
--search-result-background: #f8f9fa;
}
.dark-mode {
--primary-color: #3498db;
--secondary-color: #2ecc71;
--background-color: #1e2124;
--chat-background: #36393f;
--text-color: #dcddde;
--chat-bubble-user: #4e5d94;
--chat-bubble-ai: #40444b;
--sidebar-background: #2f3136;
--input-background: #40444b;
--send-button-color: #7289da;
--console-background: #2f3136;
--console-text: #dcddde;
--fold-background: #2f3136;
--fold-text: #dcddde;
--border-color: #ffffff;
--search-result-background: #2f3136;
}
body {
background-color: var(--background-color);
color: var(--text-color);
transition: all 0.3s ease;
}
.chat-container {
background-color: var(--chat-background);
transition: all 0.3s ease;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.chat-bubble {
max-width: 80%;
padding: 12px;
border-radius: 12px;
margin-bottom: 12px;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
transition: all 0.3s ease;
}
.user-bubble {
background-color: var(--chat-bubble-user);
color: var(--text-color);
margin-left: auto;
border-bottom-right-radius: 4px;
}
.ai-bubble {
background-color: var(--chat-bubble-ai);
color: var(--text-color);
margin-right: auto;
border-bottom-left-radius: 4px;
}
.dark-mode .chat-bubble {
border: 1px solid var(--border-color);
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
margin-right: 8px;
transition: all 0.3s ease;
}
.status-active {
background-color: var(--secondary-color);
}
.status-inactive {
background-color: #95a5a6;
}
.sidebar {
background-color: var(--sidebar-background);
transition: all 0.3s ease;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
#user-input {
background-color: var(--input-background);
color: var(--text-color);
transition: all 0.3s ease;
border-radius: 8px;
padding-right: 40px;
}
#send-btn {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
color: var(--send-button-color);
font-size: 20px;
cursor: pointer;
transition: all 0.3s ease;
}
#send-btn:hover {
opacity: 0.8;
}
.console {
background-color: var(--console-background);
color: var(--console-text);
transition: all 0.3s ease;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
#status-log {
background-color: var(--console-background);
color: var(--console-text);
transition: all 0.3s ease;
border: 1px solid var(--border-color);
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: var(--chat-background);
}
::-webkit-scrollbar-thumb {
background: var(--primary-color);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--secondary-color);
}
/* 代码块样式 */
.hljs {
background: var(--fold-background) !important;
color: var(--fold-text) !important;
}
.search-results {
background-color: var(--search-result-background);
color: var(--text-color);
border: 1px solid var(--border-color);
}
.search-results summary {
cursor: pointer;
font-weight: bold;
}
.search-results ul {
list-style-type: none;
padding-left: 0;
}
.search-results li {
background-color: var(--chat-bubble-ai);
border: 1px solid var(--border-color);
}
/* 控制台消息条目样式 */
#status-log div {
background-color: var(--console-background);
color: var(--console-text);
border: 1px solid var(--border-color);
}
@media (max-width: 768px) {
.sidebar {
position: fixed;
right: -300px;
top: 0;
bottom: 0;
width: 300px;
z-index: 1000;
transition: right 0.3s ease-in-out;
}
.sidebar.open {
right: 0;
}
.sidebar-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
}
.sidebar-overlay.show {
display: block;
}
}
</style>
<body class="h-screen flex flex-col md:flex-row p-4">
<!-- 主聊天窗口 -->
<div class="chat-container flex-grow md:w-3/4 p-4 flex flex-col h-screen mr-4">
<div id="chat-window" class="flex-grow overflow-y-auto mb-4 p-4 rounded-lg shadow-inner"></div>
<div class="relative">
<input id="user-input" type="text" class="w-full border p-2" placeholder="输入您的问题...">
<button id="send-btn" class="text-2xl">
<i class="fas fa-paper-plane"></i>
</button>
</div>
</div>
<!-- 右侧控制台 -->
<div class="sidebar console md:w-1/4 p-4 h-screen overflow-y-auto">
<h2 class="text-xl font-bold mb-4">运行状态</h2>
<div class="mb-4">
<div class="model-status">
<span class="status-indicator" id="main-model-status"></span>
<span class="model-name">主模型</span>
<span class="model-action" id="main-model-action"></span>
</div>
<div class="model-status">
<span class="status-indicator" id="sub-model-1-status"></span>
<span class="model-name">次级模型1</span>
<span class="model-action" id="sub-model-1-action"></span>
</div>
<div class="model-status">
<span class="status-indicator" id="sub-model-2-status"></span>
<span class="model-name">次级模型2</span>
<span class="model-action" id="sub-model-2-action"></span>
</div>
<div class="model-status">
<span class="status-indicator" id="arbitration-model-status"></span>
<span class="model-name">裁决模型</span>
<span class="model-action" id="arbitration-model-action"></span>
</div>
<div class="model-status">
<span class="status-indicator" id="search-status"></span>
<span class="model-name">搜索</span>
<span class="model-action" id="search-action"></span>
</div>
<div class="model-status">
<span class="status-indicator" id="email-status"></span>
<span class="model-name">邮件发送</span>
<span class="model-action" id="email-action"></span>
</div>
</div>
<div id="status-log" class="p-2 rounded h-64 overflow-y-auto mb-4"></div>
<button id="settings-btn" class="w-full bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-white px-4 py-2 rounded hover:bg-gray-400 dark:hover:bg-gray-500 transition duration-200">
<i class="fas fa-cog"></i> 设置
</button>
</div>
<!-- 移动端侧边栏切换按钮 -->
<button id="sidebar-toggle" class="md:hidden fixed top-4 right-4 bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-white p-2 rounded-full shadow-lg hover:bg-gray-400 dark:hover:bg-gray-500 transition duration-200 z-50">
<i class="fas fa-bars"></i>
</button>
<!-- 移动端侧边栏遮罩 -->
<div id="sidebar-overlay" class="sidebar-overlay"></div>
<!-- 暗色模式切换按钮 -->
<button id="dark-mode-toggle" class="fixed top-4 left-4 bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-white p-2 rounded-full shadow-lg hover:bg-gray-400 dark:hover:bg-gray-500 transition duration-200">
<i class="fas fa-moon"></i>
</button>
<!-- 设置对话框 -->
<div id="settings-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden flex items-center justify-center z-50">
<div class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-xl">
<h2 class="text-xl font-bold mb-4">设置</h2>
<div class="mb-4">
<label for="max-history" class="block mb-2">保留对话轮数:</label>
<input type="number" id="max-history" class="border rounded p-2 w-full dark:bg-gray-700 dark:text-white" min="1" max="50" value="10">
</div>
<div class="flex justify-end">
<button id="save-settings" class="bg-blue-500 text-white px-4 py-2 rounded mr-2 hover:bg-blue-600 transition duration-200">保存</button>
<button id="cancel-settings" class="bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-white px-4 py-2 rounded hover:bg-gray-400 dark:hover:bg-gray-500 transition duration-200">取消</button>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
<script>
const chatWindow = document.getElementById('chat-window');
const userInput = document.getElementById('user-input');
const sendBtn = document.getElementById('send-btn');
const statusLog = document.getElementById('status-log');
const settingsBtn = document.getElementById('settings-btn');
const settingsModal = document.getElementById('settings-modal');
const saveSettingsBtn = document.getElementById('save-settings');
const cancelSettingsBtn = document.getElementById('cancel-settings');
const maxHistoryInput = document.getElementById('max-history');
const darkModeToggle = document.getElementById('dark-mode-toggle');
const sidebarToggle = document.getElementById('sidebar-toggle');
const sidebar = document.querySelector('.sidebar');
const sidebarOverlay = document.getElementById('sidebar-overlay');
let conversationHistory = [];
let maxHistory = 10;
function addMessage(content, isUser) {
const bubble = document.createElement('div');
bubble.className = `chat-bubble ${isUser ? 'user-bubble' : 'ai-bubble'}`;
bubble.innerHTML = isUser ? content : marked.parse(content);
chatWindow.appendChild(bubble);
chatWindow.scrollTop = chatWindow.scrollHeight;
bubble.querySelectorAll('pre code').forEach((block) => {
hljs.highlightBlock(block);
});
conversationHistory.push({
role: isUser ? 'user' : 'assistant',
content: content
});
if (conversationHistory.length > maxHistory * 2) {
conversationHistory = conversationHistory.slice(-maxHistory * 2);
}
}
function updateStatus(main, sub1, sub2, arbitration, search, email) {
updateModelStatus('main-model', main);
updateModelStatus('sub-model-1', sub1);
updateModelStatus('sub-model-2', sub2);
updateModelStatus('arbitration-model', arbitration);
updateModelStatus('search', search);
updateModelStatus('email', email);
}
function updateModelStatus(modelId, isActive, action = '') {
const statusElement = document.getElementById(`${modelId}-status`);
const actionElement = document.getElementById(`${modelId}-action`);
statusElement.className = `status-indicator ${isActive ? 'status-active' : 'status-inactive'}`;
actionElement.textContent = action;
}
function addStatusLog(message) {
const logEntry = document.createElement('div');
logEntry.className = 'mb-2 p-2 bg-white dark:bg-gray-700 rounded shadow';
logEntry.textContent = message;
statusLog.appendChild(logEntry);
statusLog.scrollTop = statusLog.scrollHeight;
}
function displaySearchResults(results, type) {
const searchResults = document.createElement('details');
searchResults.className = 'search-results mb-2 p-2 rounded';
const summary = document.createElement('summary');
summary.textContent = type === 'papers' ? '论文搜索结果' : '搜索结果';
searchResults.appendChild(summary);
const resultsList = document.createElement('ul');
resultsList.className = 'mt-2';
results.forEach(result => {
const li = document.createElement('li');
li.className = 'mb-2 p-2 rounded';
if (type === 'papers') {
li.innerHTML = `
<strong>标题:</strong> ${result.标题}<br>
<strong>作者:</strong> ${result.作者}<br>
<strong>DOI:</strong> ${result.DOI}<br>
<strong>ISBN:</strong> ${result.ISBN}<br>
<strong>摘要:</strong> ${result.摘要}
`;
} else {
li.innerHTML = `<strong>${result.title}</strong><br>${result.body}`;
}
resultsList.appendChild(li);
});
searchResults.appendChild(resultsList);
chatWindow.appendChild(searchResults);
}
function updateStatusFromLog(log) {
if (log.includes("主模型:")) {
updateModelStatus('main-model', true, log.split("主模型:")[1]);
} else if (log.includes("次级模型1:")) {
updateModelStatus('sub-model-1', true, log.split("次级模型1:")[1]);
} else if (log.includes("次级模型2:")) {
updateModelStatus('sub-model-2', true, log.split("次级模型2:")[1]);
} else if (log.includes("裁决模型:")) {
updateModelStatus('arbitration-model', true, log.split("裁决模型:")[1]);
} else if (log.includes("搜索:")) {
updateModelStatus('search', true, log.split("搜索:")[1]);
} else if (log.includes("邮件:")) {
updateModelStatus('email', true, log.split("邮件:")[1]);
}
}
async function sendMessage() {
const question = userInput.value.trim();
if (!question) return;
addMessage(question, true);
userInput.value = '';
updateStatus(false, false, false, false, false, false);
statusLog.innerHTML = '';
addStatusLog('开始处理问题...');
try {
const response = await fetch('/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
question,
history: conversationHistory.slice(-maxHistory * 2 + 1)
})
});
const data = await response.json();
data.status_log.forEach(log => {
addStatusLog(log);
updateStatusFromLog(log);
});
if (data.search_results) {
if (Array.isArray(data.search_results) && data.search_results.length > 0 && 'DOI' in data.search_results[0]) {
displaySearchResults(data.search_results, 'papers');
} else {
displaySearchResults(data.search_results, 'web');
}
}
addMessage(data.response, false);
addStatusLog('回答完成');
} catch (error) {
console.error('Error:', error);
addMessage('发生错误,请稍后再试。', false);
updateStatus(false, false, false, false, false, false);
addStatusLog('发生错误');
}
}
sendBtn.addEventListener('click', sendMessage);
userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
settingsBtn.addEventListener('click', () => {
settingsModal.classList.remove('hidden');
maxHistoryInput.value = maxHistory;
});
saveSettingsBtn.addEventListener('click', async () => {
const newMaxHistory = parseInt(maxHistoryInput.value);
if (newMaxHistory >= 1 && newMaxHistory <= 50) {
maxHistory = newMaxHistory;
try {
const response = await fetch('/settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ max_history: maxHistory })
});
const data = await response.json();
if (data.status === 'success') {
alert('设置已保存');
} else {
alert('保存设置时出错');
}
} catch (error) {
console.error('Error:', error);
alert('保存设置时出错');
}
settingsModal.classList.add('hidden');
} else {
alert('请输入1到50之间的数字');
}
});
cancelSettingsBtn.addEventListener('click', () => {
settingsModal.classList.add('hidden');
});
darkModeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
updateDarkModeIcon();
});
function updateDarkModeIcon() {
const icon = darkModeToggle.querySelector('i');
if (document.body.classList.contains('dark-mode')) {
icon.classList.remove('fa-moon');
icon.classList.add('fa-sun');
} else {
icon.classList.remove('fa-sun');
icon.classList.add('fa-moon');
}
}
function initDarkMode() {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.body.classList.add('dark-mode');
}
updateDarkModeIcon();
}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (e.matches) {
document.body.classList.add('dark-mode');
} else {
document.body.classList.remove('dark-mode');
}
updateDarkModeIcon();
});
sidebarToggle.addEventListener('click', () => {
sidebar.classList.toggle('open');
sidebarOverlay.classList.toggle('show');
});
sidebarOverlay.addEventListener('click', () => {
sidebar.classList.remove('open');
sidebarOverlay.classList.remove('show');
});
window.addEventListener('load', () => {
initDarkMode();
});
window.addEventListener('resize', () => {
if (window.innerWidth >= 768) {
sidebar.classList.remove('open');
sidebarOverlay.classList.remove('show');
}
});
// 可以在这里添加任何其他需要的 JavaScript 功能
</script>
</body>
</html>