|
<!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 rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"> |
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css"> |
|
<style> |
|
:root { |
|
--primary-color: #4361ee; |
|
--secondary-color: #3f37c9; |
|
--accent-color: #4cc9f0; |
|
--success-color: #4caf50; |
|
--warning-color: #ff9800; |
|
--danger-color: #f44336; |
|
--light-color: #f8f9fa; |
|
--dark-color: #212529; |
|
--border-color: #dee2e6; |
|
--border-radius: 0.375rem; |
|
} |
|
|
|
body { |
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|
margin: 0; |
|
padding: 0; |
|
height: 100vh; |
|
background-color: #f5f7fa; |
|
color: #333; |
|
display: flex; |
|
flex-direction: column; |
|
} |
|
|
|
.header { |
|
background-color: #fff; |
|
border-bottom: 1px solid var(--border-color); |
|
padding: 1rem; |
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); |
|
} |
|
|
|
.header-content { |
|
max-width: 1600px; |
|
margin: 0 auto; |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
} |
|
|
|
.header h1 { |
|
margin: 0; |
|
font-size: 1.5rem; |
|
color: var(--primary-color); |
|
} |
|
|
|
.main-container { |
|
flex: 1; |
|
display: flex; |
|
max-width: 1600px; |
|
margin: 0 auto; |
|
padding: 1rem; |
|
width: 100%; |
|
box-sizing: border-box; |
|
height: calc(100vh - 70px); |
|
overflow: hidden; |
|
} |
|
|
|
.chat-container { |
|
flex: 1; |
|
display: flex; |
|
flex-direction: column; |
|
background-color: #fff; |
|
border-radius: var(--border-radius); |
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); |
|
border: 1px solid var(--border-color); |
|
overflow: hidden; |
|
height: 100%; |
|
max-width: 800px; |
|
margin: 0 auto; |
|
} |
|
|
|
|
|
.main-container.with-plugin .chat-container { |
|
margin: 0; |
|
max-width: 350px; |
|
} |
|
|
|
.chat-messages { |
|
flex: 1; |
|
overflow-y: auto; |
|
padding: 1rem; |
|
display: flex; |
|
flex-direction: column; |
|
} |
|
|
|
.message { |
|
max-width: 90%; |
|
margin-bottom: 1rem; |
|
padding: 0.75rem 1rem; |
|
border-radius: var(--border-radius); |
|
position: relative; |
|
} |
|
|
|
.user-message { |
|
background-color: #e3f2fd; |
|
align-self: flex-end; |
|
color: #0d47a1; |
|
} |
|
|
|
.bot-message { |
|
background-color: #f5f5f5; |
|
align-self: flex-start; |
|
color: #333; |
|
border-left: 3px solid var(--primary-color); |
|
} |
|
|
|
.input-container { |
|
padding: 1rem; |
|
border-top: 1px solid var(--border-color); |
|
background-color: #f9f9f9; |
|
} |
|
|
|
.input-row { |
|
display: flex; |
|
gap: 0.5rem; |
|
} |
|
|
|
.input-field { |
|
flex: 1; |
|
padding: 0.75rem 1rem; |
|
border: 1px solid var(--border-color); |
|
border-radius: var(--border-radius); |
|
resize: none; |
|
font-size: 0.95rem; |
|
} |
|
|
|
.input-field:focus { |
|
outline: none; |
|
border-color: var(--primary-color); |
|
box-shadow: 0 0 0 2px rgba(67, 97, 238, 0.1); |
|
} |
|
|
|
.send-button { |
|
padding: 0.75rem 1.5rem; |
|
background-color: var(--primary-color); |
|
color: white; |
|
border: none; |
|
border-radius: var(--border-radius); |
|
cursor: pointer; |
|
font-weight: 500; |
|
transition: background-color 0.2s; |
|
} |
|
|
|
.send-button:hover { |
|
background-color: var(--secondary-color); |
|
} |
|
|
|
.send-button:disabled { |
|
background-color: #ccc; |
|
cursor: not-allowed; |
|
} |
|
|
|
.plugin-container { |
|
display: none; |
|
flex-direction: column; |
|
background-color: #fff; |
|
border-radius: var(--border-radius); |
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); |
|
border: 1px solid var(--border-color); |
|
overflow: hidden; |
|
height: 100%; |
|
flex: 2; |
|
margin-left: 1rem; |
|
} |
|
|
|
.plugin-header { |
|
padding: 0.75rem 1rem; |
|
border-bottom: 1px solid var(--border-color); |
|
background-color: #f9f9f9; |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
} |
|
|
|
.plugin-title { |
|
margin: 0; |
|
font-size: 1rem; |
|
font-weight: 500; |
|
} |
|
|
|
.plugin-close { |
|
background: none; |
|
border: none; |
|
cursor: pointer; |
|
font-size: 1rem; |
|
color: #777; |
|
} |
|
|
|
.plugin-content { |
|
flex: 1; |
|
overflow-y: auto; |
|
} |
|
|
|
|
|
.code-plugin .plugin-content { |
|
padding: 0; |
|
} |
|
|
|
|
|
.visualization-plugin .visualization-form { |
|
margin-bottom: 1rem; |
|
padding: 1rem; |
|
} |
|
|
|
.visualization-plugin .visualization-result { |
|
margin-top: 1rem; |
|
text-align: center; |
|
padding: 0 1rem; |
|
} |
|
|
|
.visualization-plugin .visualization-image { |
|
max-width: 100%; |
|
border-radius: var(--border-radius); |
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
|
|
.mindmap-plugin .mindmap-form { |
|
margin-bottom: 1rem; |
|
padding: 1rem; |
|
} |
|
|
|
.mindmap-plugin .mindmap-result { |
|
margin-top: 1rem; |
|
text-align: center; |
|
padding: 0 1rem; |
|
} |
|
|
|
.mindmap-plugin .mindmap-image { |
|
max-width: 100%; |
|
border-radius: var(--border-radius); |
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
|
|
.reference-container { |
|
margin-top: 10px; |
|
border-top: 1px dashed #ddd; |
|
padding-top: 10px; |
|
} |
|
|
|
.reference-toggle { |
|
color: #666; |
|
font-size: 0.9rem; |
|
cursor: pointer; |
|
display: flex; |
|
align-items: center; |
|
} |
|
|
|
.reference-content { |
|
display: none; |
|
margin-top: 10px; |
|
padding: 10px; |
|
background-color: #f9f9f9; |
|
border-radius: 5px; |
|
font-size: 0.85rem; |
|
} |
|
|
|
|
|
pre { |
|
background-color: #f8f9fa; |
|
border-radius: 5px; |
|
padding: 12px; |
|
margin: 10px 0; |
|
overflow-x: auto; |
|
border: 1px solid #eee; |
|
} |
|
|
|
code { |
|
font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace; |
|
font-size: 14px; |
|
} |
|
|
|
|
|
@media (max-width: 1200px) { |
|
.main-container.with-plugin .chat-container { |
|
max-width: 300px; |
|
} |
|
} |
|
|
|
@media (max-width: 992px) { |
|
.main-container { |
|
flex-direction: column; |
|
} |
|
|
|
.main-container.with-plugin .chat-container { |
|
max-width: 100%; |
|
margin-bottom: 1rem; |
|
height: 40vh; |
|
} |
|
|
|
.plugin-container { |
|
margin-left: 0; |
|
height: calc(60vh - 32px); |
|
} |
|
} |
|
|
|
@media (max-width: 768px) { |
|
.main-container { |
|
padding: 0.5rem; |
|
} |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<header class="header"> |
|
<div class="header-content"> |
|
<h1>{{ agent_name }}</h1> |
|
<div> |
|
<span class="badge bg-primary">AI学习助手</span> |
|
</div> |
|
</div> |
|
</header> |
|
|
|
<div class="main-container" id="main-container"> |
|
<div class="chat-container"> |
|
<div class="chat-messages" id="chat-messages"> |
|
<div class="message bot-message"> |
|
<p>你好!我是{{ agent_name }},有什么可以帮助你的吗?</p> |
|
{% if agent_description %} |
|
<p>{{ agent_description }}</p> |
|
{% endif %} |
|
</div> |
|
</div> |
|
|
|
<div class="input-container"> |
|
<div class="input-row"> |
|
<textarea class="input-field" id="user-input" placeholder="输入您的问题..." rows="2"></textarea> |
|
<button class="send-button" id="send-button"> |
|
<i class="bi bi-send"></i> |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="plugin-container code-plugin" id="code-plugin"> |
|
<div class="plugin-header"> |
|
<h3 class="plugin-title">Python代码执行</h3> |
|
<button class="plugin-close" id="close-code-plugin"> |
|
<i class="bi bi-x-lg"></i> |
|
</button> |
|
</div> |
|
<div class="plugin-content"> |
|
<iframe id="code-execution-frame" src="" style="width: 100%; height: 100%; border: none;"></iframe> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="plugin-container visualization-plugin" id="visualization-plugin"> |
|
<div class="plugin-header"> |
|
<h3 class="plugin-title">3D可视化</h3> |
|
<button class="plugin-close" id="close-visualization-plugin"> |
|
<i class="bi bi-x-lg"></i> |
|
</button> |
|
</div> |
|
<div class="plugin-content"> |
|
<div class="visualization-result" id="visualization-result"> |
|
<div class="text-center py-4"> |
|
<div class="spinner-border text-primary" role="status"> |
|
<span class="visually-hidden">加载中...</span> |
|
</div> |
|
<p class="mt-3">正在准备3D可视化...</p> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="plugin-container mindmap-plugin" id="mindmap-plugin"> |
|
<div class="plugin-header"> |
|
<h3 class="plugin-title">思维导图</h3> |
|
<button class="plugin-close" id="close-mindmap-plugin"> |
|
<i class="bi bi-x-lg"></i> |
|
</button> |
|
</div> |
|
<div class="plugin-content"> |
|
<div class="mindmap-result" id="mindmap-result"> |
|
<div class="text-center py-4"> |
|
<div class="spinner-border text-primary" role="status"> |
|
<span class="visually-hidden">加载中...</span> |
|
</div> |
|
<p class="mt-3">正在生成思维导图...</p> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
|
|
const agentId = "{{ agent_id }}"; |
|
const token = "{{ token }}"; |
|
let executionContext = null; |
|
const mainContainer = document.getElementById('main-container'); |
|
|
|
|
|
const chatMessages = document.getElementById('chat-messages'); |
|
const userInput = document.getElementById('user-input'); |
|
const sendButton = document.getElementById('send-button'); |
|
|
|
|
|
const codePlugin = document.getElementById('code-plugin'); |
|
const closeCodePlugin = document.getElementById('close-code-plugin'); |
|
const codeExecutionFrame = document.getElementById('code-execution-frame'); |
|
|
|
|
|
const visualizationPlugin = document.getElementById('visualization-plugin'); |
|
const closeVisualizationPlugin = document.getElementById('close-visualization-plugin'); |
|
const visualizationResult = document.getElementById('visualization-result'); |
|
|
|
|
|
const mindmapPlugin = document.getElementById('mindmap-plugin'); |
|
const closeMindmapPlugin = document.getElementById('close-mindmap-plugin'); |
|
const mindmapResult = document.getElementById('mindmap-result'); |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
sendButton.addEventListener('click', sendMessage); |
|
|
|
|
|
userInput.addEventListener('keypress', function(e) { |
|
if (e.key === 'Enter' && !e.shiftKey) { |
|
e.preventDefault(); |
|
sendMessage(); |
|
} |
|
}); |
|
|
|
|
|
closeCodePlugin.addEventListener('click', () => { |
|
codePlugin.style.display = 'none'; |
|
|
|
codeExecutionFrame.src = ''; |
|
updateMainContainerLayout(); |
|
}); |
|
|
|
closeVisualizationPlugin.addEventListener('click', () => { |
|
visualizationPlugin.style.display = 'none'; |
|
updateMainContainerLayout(); |
|
}); |
|
|
|
closeMindmapPlugin.addEventListener('click', () => { |
|
mindmapPlugin.style.display = 'none'; |
|
updateMainContainerLayout(); |
|
}); |
|
}); |
|
|
|
|
|
function updateMainContainerLayout() { |
|
|
|
const isAnyPluginVisible = |
|
codePlugin.style.display === 'flex' || |
|
visualizationPlugin.style.display === 'flex' || |
|
mindmapPlugin.style.display === 'flex'; |
|
|
|
|
|
if (isAnyPluginVisible) { |
|
mainContainer.classList.add('with-plugin'); |
|
} else { |
|
mainContainer.classList.remove('with-plugin'); |
|
} |
|
} |
|
|
|
|
|
async function sendMessage() { |
|
const message = userInput.value.trim(); |
|
if (!message) return; |
|
|
|
|
|
addMessage(message, true); |
|
|
|
|
|
userInput.value = ''; |
|
|
|
|
|
sendButton.disabled = true; |
|
|
|
try { |
|
|
|
const response = await fetch(`/api/student/chat/${agentId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ |
|
message: message, |
|
token: token |
|
}) |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
|
|
const processedContent = processResponseContent(data.message); |
|
|
|
|
|
const messageElement = addMessage(processedContent, false); |
|
|
|
|
|
if (data.references && data.references.length > 0) { |
|
addReferences(messageElement, data.references); |
|
} |
|
|
|
|
|
if (data.tools && data.tools.length > 0) { |
|
|
|
hideAllPlugins(); |
|
|
|
|
|
activatePlugins(data.message, data.tools); |
|
} |
|
} else { |
|
|
|
addMessage(`错误: ${data.message}`, false); |
|
} |
|
} catch (error) { |
|
console.error('发送请求出错:', error); |
|
addMessage('发送请求时出错,请重试', false); |
|
} finally { |
|
|
|
sendButton.disabled = false; |
|
} |
|
} |
|
|
|
|
|
function processResponseContent(content) { |
|
|
|
return content.replace(/===参考来源开始===[\s\S]*?===参考来源结束===/, ''); |
|
} |
|
|
|
|
|
function addReferences(messageElement, references) { |
|
|
|
const referenceContainer = document.createElement('div'); |
|
referenceContainer.className = 'reference-container'; |
|
|
|
|
|
const toggleButton = document.createElement('div'); |
|
toggleButton.className = 'reference-toggle'; |
|
toggleButton.textContent = '参考来源'; |
|
toggleButton.style.color = '#666'; |
|
toggleButton.style.fontSize = '0.9rem'; |
|
toggleButton.style.cursor = 'pointer'; |
|
toggleButton.style.display = 'flex'; |
|
toggleButton.style.alignItems = 'center'; |
|
|
|
|
|
const referenceContent = document.createElement('div'); |
|
referenceContent.className = 'reference-content'; |
|
|
|
|
|
references.forEach(ref => { |
|
const refItem = document.createElement('div'); |
|
refItem.style.marginBottom = '8px'; |
|
refItem.style.paddingBottom = '8px'; |
|
refItem.style.borderBottom = '1px solid #eee'; |
|
|
|
refItem.innerHTML = ` |
|
<div><strong>[${ref.index}]</strong> ${ref.summary}</div> |
|
<div><small>来源: ${ref.file_name}</small></div> |
|
`; |
|
|
|
referenceContent.appendChild(refItem); |
|
}); |
|
|
|
|
|
toggleButton.addEventListener('click', () => { |
|
if (referenceContent.style.display === 'none') { |
|
referenceContent.style.display = 'block'; |
|
toggleButton.textContent = '折叠参考来源'; |
|
} else { |
|
referenceContent.style.display = 'none'; |
|
toggleButton.textContent = '参考来源'; |
|
} |
|
}); |
|
|
|
|
|
referenceContainer.appendChild(toggleButton); |
|
referenceContainer.appendChild(referenceContent); |
|
messageElement.appendChild(referenceContainer); |
|
} |
|
|
|
|
|
function addMessage(content, isUser) { |
|
const messageDiv = document.createElement('div'); |
|
messageDiv.className = isUser ? 'message user-message' : 'message bot-message'; |
|
|
|
|
|
const processedContent = processMessageContent(content); |
|
messageDiv.innerHTML = processedContent; |
|
|
|
chatMessages.appendChild(messageDiv); |
|
|
|
|
|
chatMessages.scrollTop = chatMessages.scrollHeight; |
|
|
|
|
|
if (!isUser) { |
|
applySyntaxHighlighting(messageDiv); |
|
} |
|
|
|
return messageDiv; |
|
} |
|
|
|
|
|
function processMessageContent(content) { |
|
|
|
const codeBlocks = []; |
|
let processedContent = content.replace(/```(\w*)\n([\s\S]*?)\n```/g, function(match, language, code) { |
|
const id = codeBlocks.length; |
|
codeBlocks.push({ language, code }); |
|
return `__CODE_BLOCK_${id}__`; |
|
}); |
|
|
|
|
|
processedContent = processedContent.replace(/\n/g, '<br>'); |
|
|
|
|
|
processedContent = processedContent.replace(/__CODE_BLOCK_(\d+)__/g, function(match, id) { |
|
const { language, code } = codeBlocks[id]; |
|
const langClass = language ? ` class="language-${language}"` : ''; |
|
return `<pre><code${langClass}>${escapeHtml(code)}</code></pre>`; |
|
}); |
|
|
|
return processedContent; |
|
} |
|
|
|
|
|
function applySyntaxHighlighting(element) { |
|
|
|
if (typeof hljs !== 'undefined') { |
|
|
|
element.querySelectorAll('pre code').forEach((block) => { |
|
hljs.highlightBlock(block); |
|
}); |
|
} |
|
} |
|
|
|
|
|
function escapeHtml(text) { |
|
return text |
|
.replace(/&/g, "&") |
|
.replace(/</g, "<") |
|
.replace(/>/g, ">") |
|
.replace(/"/g, """) |
|
.replace(/'/g, "'"); |
|
} |
|
|
|
|
|
function hideAllPlugins() { |
|
codePlugin.style.display = 'none'; |
|
visualizationPlugin.style.display = 'none'; |
|
mindmapPlugin.style.display = 'none'; |
|
updateMainContainerLayout(); |
|
} |
|
|
|
|
|
function extractCodeBlocks(message) { |
|
const codeBlocks = []; |
|
const codeRegex = /```python\n([\s\S]*?)\n```/g; |
|
|
|
let match; |
|
while ((match = codeRegex.exec(message)) !== null) { |
|
codeBlocks.push(match[1]); |
|
} |
|
|
|
return codeBlocks; |
|
} |
|
|
|
|
|
function extract3DVisualizationCode(message) { |
|
|
|
const codeRegex = /```python\s*(import[\s\S]*?def create_3d_plot\(\):[\s\S]*?return[\s\S]*?})\s*```/i; |
|
const match = codeRegex.exec(message); |
|
|
|
if (match) { |
|
return match[1].trim(); |
|
} |
|
|
|
return null; |
|
} |
|
|
|
|
|
function extractMindmapContent(message) { |
|
|
|
const mindmapRegex = /@startmindmap\n([\s\S]*?)@endmindmap/; |
|
const match = mindmapRegex.exec(message); |
|
|
|
if (match) { |
|
return `@startmindmap\n${match[1]}\n@endmindmap`; |
|
} |
|
|
|
return null; |
|
} |
|
|
|
|
|
function activateCodePlugin(message) { |
|
|
|
const codeBlocks = extractCodeBlocks(message); |
|
|
|
if (codeBlocks.length > 0) { |
|
const isAlreadyVisible = codePlugin.style.display === 'flex'; |
|
|
|
|
|
codePlugin.style.display = 'flex'; |
|
updateMainContainerLayout(); |
|
|
|
|
|
const iframe = document.getElementById('code-execution-frame'); |
|
|
|
|
|
if (isAlreadyVisible && iframe.contentWindow) { |
|
|
|
iframe.contentWindow.postMessage({ |
|
type: 'setCode', |
|
code: codeBlocks[0] |
|
}, '*'); |
|
} else { |
|
|
|
let src = '/code_execution.html'; |
|
if (codeBlocks.length > 0) { |
|
src += `?code=${encodeURIComponent(codeBlocks[0])}`; |
|
} |
|
|
|
iframe.src = src; |
|
|
|
|
|
iframe.onload = function() { |
|
if (codeBlocks.length > 0) { |
|
iframe.contentWindow.postMessage({ |
|
type: 'setCode', |
|
code: codeBlocks[0] |
|
}, '*'); |
|
} |
|
}; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
function activate3DVisualization(message) { |
|
const code = extract3DVisualizationCode(message); |
|
|
|
if (code) { |
|
|
|
visualizationPlugin.style.display = 'flex'; |
|
updateMainContainerLayout(); |
|
|
|
|
|
visualizationResult.innerHTML = ` |
|
<div class="text-center py-4"> |
|
<div class="spinner-border text-primary" role="status"> |
|
<span class="visually-hidden">生成中...</span> |
|
</div> |
|
<p class="mt-3">正在生成3D图形,请稍候...</p> |
|
</div> |
|
`; |
|
|
|
|
|
fetch('/api/visualization/3d-surface', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ code: code }) |
|
}) |
|
.then(response => response.json()) |
|
.then(data => { |
|
if (data.success) { |
|
|
|
visualizationResult.innerHTML = ` |
|
<div class="visualization-iframe-container" style="width:100%; height:500px;"> |
|
<iframe src="${data.html_url}" style="width:100%; height:100%; border:none;"></iframe> |
|
</div> |
|
<div class="text-center mt-3"> |
|
<p>3D图形生成成功</p> |
|
<a href="${data.html_url}" class="btn btn-sm btn-outline-primary" target="_blank"> |
|
<i class="bi bi-arrows-fullscreen"></i> 全屏查看 |
|
</a> |
|
</div> |
|
`; |
|
} else { |
|
visualizationResult.innerHTML = ` |
|
<div class="alert alert-danger"> |
|
<i class="bi bi-exclamation-triangle-fill me-2"></i> |
|
生成失败: ${data.message} |
|
</div> |
|
`; |
|
} |
|
}) |
|
.catch(error => { |
|
console.error('生成3D图形出错:', error); |
|
visualizationResult.innerHTML = ` |
|
<div class="alert alert-danger"> |
|
<i class="bi bi-exclamation-triangle-fill me-2"></i> |
|
生成3D图形时发生错误,请重试 |
|
</div> |
|
`; |
|
}); |
|
} |
|
} |
|
|
|
function activateMindmap(message) { |
|
const content = extractMindmapContent(message); |
|
|
|
if (content) { |
|
|
|
mindmapPlugin.style.display = 'flex'; |
|
updateMainContainerLayout(); |
|
|
|
|
|
mindmapResult.innerHTML = ` |
|
<div class="text-center py-4"> |
|
<div class="spinner-border text-primary" role="status"> |
|
<span class="visually-hidden">生成中...</span> |
|
</div> |
|
<p class="mt-3">正在生成思维导图,请稍候...</p> |
|
</div> |
|
`; |
|
|
|
|
|
fetch('/api/visualization/mindmap', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ content: content }) |
|
}) |
|
.then(response => response.json()) |
|
.then(data => { |
|
if (data.success) { |
|
mindmapResult.innerHTML = ` |
|
<div class="text-center"> |
|
<img src="${data.url}" class="mindmap-image" alt="思维导图"> |
|
<p class="mt-3">生成成功!</p> |
|
</div> |
|
`; |
|
} |
|
else { |
|
mindmapResult.innerHTML = ` |
|
<div class="alert alert-danger"> |
|
<i class="bi bi-exclamation-triangle-fill me-2"></i> |
|
生成失败: ${data.message} |
|
</div> |
|
`; |
|
} |
|
}) |
|
.catch(error => { |
|
console.error('生成思维导图出错:', error); |
|
mindmapResult.innerHTML = ` |
|
<div class="alert alert-danger"> |
|
<i class="bi bi-exclamation-triangle-fill me-2"></i> |
|
生成思维导图时发生错误,请重试 |
|
</div> |
|
`; |
|
}); |
|
} |
|
} |
|
|
|
|
|
function activatePlugins(message, tools) { |
|
|
|
if (tools.includes('code') && message.includes('```python')) { |
|
activateCodePlugin(message); |
|
} |
|
|
|
|
|
if (tools.includes('visualization') && |
|
(message.includes('def create_3d_plot') || |
|
message.includes('3D') || message.includes('可视化'))) { |
|
activate3DVisualization(message); |
|
} |
|
|
|
|
|
if (tools.includes('mindmap') && |
|
(message.includes('@startmindmap') || |
|
message.includes('思维导图'))) { |
|
activateMindmap(message); |
|
} |
|
} |
|
</script> |
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/python.min.js"></script> |
|
<script> |
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
if (typeof hljs !== 'undefined') { |
|
hljs.configure({ |
|
languages: ['python'] |
|
}); |
|
} |
|
}); |
|
</script> |
|
</body> |
|
</html> |