SPC/static/script.js

273 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const uploadArea = document.getElementById('upload-area');
const fileInput = document.getElementById('file-input');
const documentList = document.getElementById('document-list');
const chatMessages = document.getElementById('chat-messages');
const questionInput = document.getElementById('question-input');
const docCount = document.getElementById('doc-count');
const charCount = document.getElementById('char-count');
const toast = document.getElementById('toast');
function showToast(message, duration = 3000) {
toast.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, duration);
}
uploadArea.addEventListener('click', () => fileInput.click());
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.style.borderColor = '#1e3c72';
uploadArea.style.background = '#e8f0fe';
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.style.borderColor = '#cbd5e0';
uploadArea.style.background = 'transparent';
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.style.borderColor = '#cbd5e0';
uploadArea.style.background = 'transparent';
const files = e.dataTransfer.files;
if (files.length > 0) {
uploadFile(files[0]);
}
});
fileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
uploadFile(e.target.files[0]);
}
});
async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
try {
showToast('⏳ 正在上传文档...');
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.error) {
showToast(`${data.error}`);
return;
}
loadDocuments();
showToast(`✅ 文档 "${data.name}" 上传成功,正在处理中...`);
addMessage('bot', `📄 文档 "${data.name}" 已上传,系统正在智能解析文档内容...`);
setTimeout(() => {
loadDocuments();
}, 2000);
} catch (error) {
showToast('❌ 上传失败,请重试');
console.error(error);
}
}
async function loadDocuments() {
try {
const response = await fetch('/api/documents');
const documents = await response.json();
docCount.textContent = `${documents.length} 个文档`;
if (documents.length === 0) {
documentList.innerHTML = `
<div class="empty-state">
<div class="empty-icon">📭</div>
<p>暂无文档</p>
<p class="empty-hint">上传文档后即可开始问答</p>
</div>
`;
return;
}
documentList.innerHTML = documents.map(doc => `
<div class="document-item">
<div class="document-info">
<div class="document-name">📄 ${doc.name}</div>
<div class="document-status ${doc.status}">
${doc.status === 'processing' ? '⏳ 处理中...' : '✅ 已完成'}
</div>
</div>
<button class="delete-btn" onclick="deleteDocument('${doc.id}')">🗑️ 删除</button>
</div>
`).join('');
} catch (error) {
console.error(error);
showToast('❌ 加载文档列表失败');
}
}
async function deleteDocument(docId) {
if (!confirm('确定要删除这个文档吗?')) {
return;
}
try {
showToast('⏳ 正在删除文档...');
await fetch(`/api/documents/${docId}`, {
method: 'DELETE'
});
loadDocuments();
showToast('✅ 文档已删除');
addMessage('bot', '🗑️ 文档已从知识库中删除');
} catch (error) {
showToast('❌ 删除失败,请重试');
console.error(error);
}
}
async function askQuestion() {
const question = questionInput.value.trim();
if (!question) {
showToast('⚠️ 请输入问题');
questionInput.focus();
return;
}
if (question.length < 3) {
showToast('⚠️ 问题太短请输入至少3个字符');
questionInput.focus();
return;
}
addMessage('user', question);
questionInput.value = '';
updateCharCount();
try {
showToast('🤖 正在思考中...');
const response = await fetch('/api/ask', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ question })
});
const data = await response.json();
if (data.error) {
showToast(`${data.error}`);
addMessage('bot', `❌ 抱歉,${data.error}`);
return;
}
let answerHtml = `<p>${data.answer}</p>`;
if (data.sources && data.sources.length > 0) {
answerHtml += `
<div class="sources">
<div class="sources-title">📚 参考来源:</div>
${data.sources.map(source => `
<div class="source-item">📄 ${source.name} (第${source.page}页)</div>
`).join('')}
</div>
`;
}
showToast('✅ 回答完成');
addMessage('bot', answerHtml);
} catch (error) {
showToast('❌ 回答问题时出错了,请重试');
addMessage('bot', '❌ 抱歉,回答问题时出错了,请重试');
console.error(error);
}
}
function addMessage(type, content) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${type}`;
messageDiv.innerHTML = `
<div class="message-content">
${content}
</div>
`;
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function updateCharCount() {
const length = questionInput.value.length;
charCount.textContent = `${length}`;
if (length > 500) {
charCount.style.color = '#e53e3e';
} else if (length > 300) {
charCount.style.color = '#d69e2e';
} else {
charCount.style.color = '#718096';
}
}
async function loadConversationHistory() {
try {
const response = await fetch('/api/conversations');
const conversations = await response.json();
if (conversations.length === 0) {
addMessage('bot', '👋 欢迎使用智能知识库问答系统!上传文档后,您可以向我提问任何与文档相关的问题。');
return;
}
conversations.forEach(conv => {
addMessage('user', conv.question);
let answerHtml = `<p>${conv.answer}</p>`;
if (conv.sources && conv.sources.length > 0) {
answerHtml += `
<div class="sources">
<div class="sources-title">📚 参考来源:</div>
${conv.sources.map(source => `
<div class="source-item">📄 ${source.name} (第${source.page}页)</div>
`).join('')}
</div>
`;
}
addMessage('bot', answerHtml);
});
} catch (error) {
console.error(error);
addMessage('bot', '👋 欢迎使用智能知识库问答系统!上传文档后,您可以向我提问任何与文档相关的问题。');
}
}
questionInput.addEventListener('input', updateCharCount);
questionInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
askQuestion();
}
});
loadDocuments();
loadConversationHistory();