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

384 lines
13 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_fulishiyanshi.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">你好我是你的AI助手可以帮助你理解浮力仿真实验。请随时提问。</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>