|
|
|
@ -84,16 +84,6 @@
|
|
|
|
|
margin-right: 5px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loader {
|
|
|
|
|
border: 4px solid #f3f3f3;
|
|
|
|
|
border-top: 4px solid #3498db;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
width: 30px;
|
|
|
|
|
height: 30px;
|
|
|
|
|
animation: spin 2s linear infinite;
|
|
|
|
|
margin: 20px auto;
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes spin {
|
|
|
|
|
0% {
|
|
|
|
@ -193,8 +183,7 @@
|
|
|
|
|
|
|
|
|
|
<div class="input-area">
|
|
|
|
|
<label for="questionInput"></label><textarea id="questionInput" placeholder="请输入您的问题..."></textarea>
|
|
|
|
|
|
|
|
|
|
<div class="examples">
|
|
|
|
|
<div class="examples">
|
|
|
|
|
<div class="example-category">
|
|
|
|
|
<h3>知识库内问题示例:</h3>
|
|
|
|
|
<div class="example-list">
|
|
|
|
@ -239,37 +228,36 @@
|
|
|
|
|
<button id="clearBtn" onclick="clearAll()"><span class="icon">🗑️</span>清空</button>
|
|
|
|
|
<button id="saveWordBtn" onclick="saveToWord()"><span class="icon">📄</span>保存为Word</button>
|
|
|
|
|
|
|
|
|
|
<div class="loader" id="loader"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
// 禁用所有按钮
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
const buttons = document.querySelectorAll('button');
|
|
|
|
|
buttons.forEach(btn => btn.disabled = true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
MathJax = {
|
|
|
|
|
tex: {
|
|
|
|
|
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
|
|
|
|
displayMath: [['$$', '$$'], ['\\[', '\\]']]
|
|
|
|
|
},
|
|
|
|
|
svg: {
|
|
|
|
|
fontCache: 'global'
|
|
|
|
|
},
|
|
|
|
|
startup: {
|
|
|
|
|
pageReady: () => {
|
|
|
|
|
return MathJax.startup.defaultPageReady().then(() => {
|
|
|
|
|
console.log('MathJax initialized');
|
|
|
|
|
// 启用所有按钮
|
|
|
|
|
const buttons = document.querySelectorAll('button');
|
|
|
|
|
buttons.forEach(btn => btn.disabled = false);
|
|
|
|
|
return MathJax.typesetPromise();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// 禁用所有按钮
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
|
const buttons = document.querySelectorAll('button');
|
|
|
|
|
buttons.forEach(btn => btn.disabled = true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
MathJax = {
|
|
|
|
|
tex: {
|
|
|
|
|
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
|
|
|
|
displayMath: [['$$', '$$'], ['\\[', '\\]']]
|
|
|
|
|
},
|
|
|
|
|
svg: {
|
|
|
|
|
fontCache: 'global'
|
|
|
|
|
},
|
|
|
|
|
startup: {
|
|
|
|
|
pageReady: () => {
|
|
|
|
|
return MathJax.startup.defaultPageReady().then(() => {
|
|
|
|
|
console.log('MathJax initialized');
|
|
|
|
|
// 启用所有按钮
|
|
|
|
|
const buttons = document.querySelectorAll('button');
|
|
|
|
|
buttons.forEach(btn => btn.disabled = false);
|
|
|
|
|
return MathJax.typesetPromise();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
<!--国内可以访问的JS,不要使用静态的本地的,因为文件不全的话没有好的显示效果!-->
|
|
|
|
|
<script src="https://cdn.bootcdn.net/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js" id="MathJax-script" async></script>
|
|
|
|
@ -282,29 +270,27 @@
|
|
|
|
|
function submitQuestion() {
|
|
|
|
|
const question = document.getElementById('questionInput').value.trim();
|
|
|
|
|
const checkboxes = document.querySelectorAll('input[name="tags"]:checked');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!question) {
|
|
|
|
|
alert('请输入问题!');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (checkboxes.length === 0) {
|
|
|
|
|
alert('请至少选择一个原稿!');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const selectedDocs = Array.from(checkboxes).map(cb => cb.value);
|
|
|
|
|
const loader = document.getElementById('loader');
|
|
|
|
|
const answerArea = document.getElementById('answerArea');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
answerArea.innerHTML = '';
|
|
|
|
|
loader.style.display = 'block';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const data = {
|
|
|
|
|
query: question,
|
|
|
|
|
tags: selectedDocs
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fetch('/api/rag', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
@ -313,51 +299,47 @@
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify(data)
|
|
|
|
|
})
|
|
|
|
|
.then(response => {
|
|
|
|
|
const reader = response.body.getReader();
|
|
|
|
|
const decoder = new TextDecoder();
|
|
|
|
|
let buffer = '';
|
|
|
|
|
let accumulatedContent = '';
|
|
|
|
|
|
|
|
|
|
function processChunk() {
|
|
|
|
|
return reader.read().then(({done, value}) => {
|
|
|
|
|
if (done) {
|
|
|
|
|
loader.style.display = 'none';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer += decoder.decode(value, {stream: true});
|
|
|
|
|
const lines = buffer.split('\n');
|
|
|
|
|
buffer = lines.pop();
|
|
|
|
|
|
|
|
|
|
for (const line of lines) {
|
|
|
|
|
if (line.includes('data:')) {
|
|
|
|
|
const jsonStr = line.replace(/^data:\s*/, '').replace(/^data:\s*/, '').trim();
|
|
|
|
|
if (jsonStr) {
|
|
|
|
|
try {
|
|
|
|
|
const data = JSON.parse(jsonStr);
|
|
|
|
|
if (data.reply) {
|
|
|
|
|
accumulatedContent += data.reply;
|
|
|
|
|
answerArea.innerHTML = marked.parse(accumulatedContent);
|
|
|
|
|
MathJax.typesetPromise();
|
|
|
|
|
.then(response => {
|
|
|
|
|
const reader = response.body.getReader();
|
|
|
|
|
const decoder = new TextDecoder();
|
|
|
|
|
let buffer = '';
|
|
|
|
|
let accumulatedContent = '';
|
|
|
|
|
|
|
|
|
|
function processChunk() {
|
|
|
|
|
return reader.read().then(({done, value}) => {
|
|
|
|
|
if (done) return;
|
|
|
|
|
|
|
|
|
|
buffer += decoder.decode(value, {stream: true});
|
|
|
|
|
const lines = buffer.split('\n');
|
|
|
|
|
buffer = lines.pop();
|
|
|
|
|
|
|
|
|
|
for (const line of lines) {
|
|
|
|
|
if (line.includes('data:')) {
|
|
|
|
|
const jsonStr = line.replace(/^data:\s*/, '').replace(/^data:\s*/, '').trim();
|
|
|
|
|
if (jsonStr) {
|
|
|
|
|
try {
|
|
|
|
|
const data = JSON.parse(jsonStr);
|
|
|
|
|
if (data.reply) {
|
|
|
|
|
accumulatedContent += data.reply;
|
|
|
|
|
answerArea.innerHTML = marked.parse(accumulatedContent);
|
|
|
|
|
MathJax.typesetPromise();
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.log('忽略解析错误:', e);
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.log('忽略解析错误:', e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return processChunk();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return processChunk();
|
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
loader.style.display = 'none';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return processChunk();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return processChunk();
|
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function clearAll() {
|
|
|
|
@ -380,9 +362,6 @@
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const loader = document.getElementById('loader');
|
|
|
|
|
|
|
|
|
|
loader.style.display = 'block';
|
|
|
|
|
|
|
|
|
|
fetch('/api/save-word', {
|
|
|
|
|
method: 'POST',
|
|
|
|
@ -395,7 +374,6 @@
|
|
|
|
|
})
|
|
|
|
|
.then(response => response.blob())
|
|
|
|
|
.then(blob => {
|
|
|
|
|
loader.style.display = 'none';
|
|
|
|
|
const url = window.URL.createObjectURL(blob);
|
|
|
|
|
const a = document.createElement('a');
|
|
|
|
|
a.href = url;
|
|
|
|
@ -406,7 +384,6 @@
|
|
|
|
|
document.body.removeChild(a);
|
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
loader.style.display = 'none';
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
alert('保存失败,请稍后再试!');
|
|
|
|
|
});
|
|
|
|
|