Files
dsProject/dsLightRag/static/deepseek_huaxue_iframe.html
2025-08-14 15:45:08 +08:00

408 lines
14 KiB
HTML
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.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>物体的浮沉条件是什么?</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Microsoft YaHei', Arial, sans-serif;
}
body {
background-color: #f5f5f5;
height: 100vh;
display: flex;
flex-direction: column;
}
.container {
display: flex;
flex: 1;
overflow: hidden;
}
.simulation-panel {
flex: 1;
border: 1px solid #ddd;
overflow: hidden;
background-color: white;
}
.chat-panel {
flex: 0 0 400px;
display: flex;
flex-direction: column;
border: 1px solid #ddd;
background-color: white;
box-shadow: -2px 0 5px rgba(0,0,0,0.1);
}
.chat-header {
padding: 15px;
background-color: #2196F3; /* 改为蓝色 */
color: white;
font-size: 18px;
font-weight: bold;
}
.chat-messages {
flex: 1;
padding: 15px;
overflow-y: auto;
}
.message {
margin-bottom: 15px;
max-width: 85%;
padding: 10px 15px;
border-radius: 18px;
word-break: break-word;
}
.user-message {
background-color: #E3F2FD; /* 改为浅蓝色 */
margin-left: auto;
border-top-right-radius: 4px;
}
.ai-message {
background-color: #E5E5EA;
border-top-left-radius: 4px;
}
.message-content {
line-height: 1.5;
}
.chat-input {
display: flex;
padding: 10px;
border-top: 1px solid #ddd;
}
.chat-input input {
flex: 1;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 20px;
outline: none;
}
.chat-input button {
margin-left: 10px;
padding: 0 15px;
background-color: #2196F3; /* 改为蓝色 */
color: white;
border: none;
border-radius: 20px;
cursor: pointer;
font-weight: bold;
}
.chat-input button:hover {
background-color: #1976D2; /* 改为深蓝色 */
}
.loading-indicator {
display: flex;
align-items: center;
margin: 10px 0;
}
.loading-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #666;
margin: 0 4px;
animation: pulse 1.4s infinite ease-in-out both;
}
.loading-dot:nth-child(1) {
animation-delay: -0.32s;
}
.loading-dot:nth-child(2) {
animation-delay: -0.16s;
}
@keyframes pulse {
0%, 80%, 100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
iframe {
width: 100%;
height: 100%;
border: none;
}
/* 响应式设计 */
@media (max-width: 900px) {
.container {
flex-direction: column;
}
.simulation-panel {
height: 50vh;
}
.chat-panel {
flex: 1;
width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<div class="simulation-panel">
<iframe src="deepseek_html_20250812_5fd0ec.html"></iframe>
</div>
<div class="chat-panel">
<div class="chat-header">AI 助手</div>
<div class="chat-messages" id="chat-messages">
<div class="message ai-message">
<div class="message-content">提示词:
开发一个高中化学讲解的课件,要求如下:
左侧控制面板:
标题:岩盐结构
描述NaCl晶体模型交互演示
离子半径设置:
钠离子半径0.3
氯离子半径0.45
视图控制:
显示/隐藏离子:一个复选框,用于控制是否显示离子。
显示/隐藏晶胞:一个复选框,用于控制是否显示晶胞。
显示八面体:一个按钮,用于显示八面体结构。
仅显示八面体:一个按钮,用于仅显示八面体结构。
切八分之一晶胞:一个按钮,用于显示晶胞的八分之一。
重置视图:一个按钮,用于重置视图到默认状态。
观察视角:
X轴、Y轴、Z轴三个按钮用于调整观察的三维视角。
右侧主展示区:
标题:氯化钠晶胞结构学演示
描述:高中化学交互式教学演示
氯化钠晶胞结构图:
展示了氯化钠的晶胞结构,其中绿色球代表氯离子,蓝色球代表钠离子。晶胞的边缘用红色线条连接,形成一个立方体结构。
交互提示:
提示用户可以使用鼠标拖拽旋转视角,滚轮缩放,平行投影等操作来观察晶胞结构。
这个网页的主要功能是通过交互式的方式,让用户能够观察和学习氯化钠的晶胞结构,并通过调整离子半径和视角来获得更深入的理解。</div>
</div>
</div>
<div class="chat-input">
<input type="text" id="user-input" placeholder="输入你的问题..." value="氯化钠晶胞结构是什么样的?">
<button id="send-btn">发送</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const chatMessages = document.getElementById('chat-messages');
const userInput = document.getElementById('user-input');
const sendBtn = document.getElementById('send-btn');
let sseConnection = null;
let isLoading = false;
// 发送消息
function sendMessage() {
const message = userInput.value.trim();
if (!message || isLoading) return;
// 添加用户消息
addMessage(message, 'user');
userInput.value = '';
// 显示加载中
showLoading();
// 关闭当前可能存在的SSE连接
if (sseConnection) {
sseConnection.close();
sseConnection = null;
}
// 发送POST请求到/api/llm
fetch('/api/llm', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ question: message })
})
.then(response => {
if (!response.ok) {
throw new Error('HTTP error! status: ' + response.status);
}
// 处理流式响应
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
let aiMessageElement = null;
let aiMessageContentElement = null;
function processChunk({ done, value }) {
if (done) {
// 处理最后一块数据
if (buffer) {
handleSSEMessage(buffer, aiMessageElement, aiMessageContentElement);
}
hideLoading();
return;
}
// 解码接收到的数据
const chunk = decoder.decode(value, { stream: true });
buffer += chunk;
// 按行分割数据
const lines = buffer.split('\n');
buffer = lines.pop(); // 保存不完整的行
// 如果还没有创建AI消息元素则创建
if (!aiMessageElement) {
aiMessageElement = document.createElement('div');
aiMessageElement.className = 'message ai-message';
aiMessageContentElement = document.createElement('div');
aiMessageContentElement.className = 'message-content';
aiMessageElement.appendChild(aiMessageContentElement);
chatMessages.appendChild(aiMessageElement);
scrollToBottom();
}
// 处理每一行
for (const line of lines) {
if (line.trim()) {
handleSSEMessage(line, aiMessageElement, aiMessageContentElement);
}
}
// 继续读取
return reader.read().then(processChunk);
}
// 开始读取响应体
return reader.read().then(processChunk);
})
.catch(error => {
console.error('发送请求失败:', error);
hideLoading();
addMessage('抱歉,请求失败: ' + error.message, 'ai');
});
}
// 处理SSE消息
function handleSSEMessage(line, aiMessageElement, aiMessageContentElement) {
// 检查是否是SSE格式 (以'data: '开头)
if (line.startsWith('data: ')) {
const data = line.substring(6).trim();
// 检查是否是结束信号
if (data === 'DONE') {
hideLoading();
return;
}
try {
// 解析JSON
const jsonData = JSON.parse(data);
// 提取content字段
if (jsonData.content) {
aiMessageContentElement.textContent += jsonData.content;
scrollToBottom();
}
} catch (error) {
console.error('解析JSON失败:', error, '数据:', data);
// 如果解析失败,尝试直接添加文本
aiMessageContentElement.textContent += data;
scrollToBottom();
}
} else if (line) {
// 如果不是标准SSE格式尝试直接解析
try {
const jsonData = JSON.parse(line);
if (jsonData.content) {
aiMessageContentElement.textContent += jsonData.content;
scrollToBottom();
}
} catch (error) {
console.error('解析非标准SSE数据失败:', error, '数据:', line);
// 如果解析失败,直接添加文本
aiMessageContentElement.textContent += line;
scrollToBottom();
}
}
}
// 添加消息到聊天框
function addMessage(message, sender) {
const messageElement = document.createElement('div');
messageElement.className = `message ${sender}-message`;
const contentElement = document.createElement('div');
contentElement.className = 'message-content';
contentElement.textContent = message;
messageElement.appendChild(contentElement);
chatMessages.appendChild(messageElement);
scrollToBottom();
}
// 显示加载中
function showLoading() {
if (isLoading) return;
isLoading = true;
const loadingElement = document.createElement('div');
loadingElement.className = 'loading-indicator';
loadingElement.id = 'loading-indicator';
for (let i = 0; i < 3; i++) {
const dot = document.createElement('div');
dot.className = 'loading-dot';
loadingElement.appendChild(dot);
}
chatMessages.appendChild(loadingElement);
scrollToBottom();
}
// 隐藏加载中
function hideLoading() {
if (!isLoading) return;
isLoading = false;
const loadingElement = document.getElementById('loading-indicator');
if (loadingElement) {
loadingElement.remove();
}
}
// 滚动到底部
function scrollToBottom() {
chatMessages.scrollTop = chatMessages.scrollHeight;
}
// 发送按钮点击事件
sendBtn.addEventListener('click', sendMessage);
// 输入框回车事件
userInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
});
</script>
</body>
</html>