Spaces:
Sleeping
Sleeping
<html lang="zh"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>知微小智</title> | |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> | |
<style> | |
body { | |
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
margin: 0; | |
padding: 0; | |
background-color: #f5f8fa; | |
color: #333; | |
} | |
.container { | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 20px; | |
} | |
.sidebar { | |
background-color: #fff; | |
border-radius: 8px; | |
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); | |
padding: 20px; | |
margin-bottom: 20px; | |
} | |
.chat-container { | |
display: flex; | |
height: calc(100vh - 200px); | |
min-height: 500px; | |
gap: 20px; | |
} | |
.chat-box { | |
flex: 1; | |
background-color: #fff; | |
border-radius: 8px; | |
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); | |
display: flex; | |
flex-direction: column; | |
overflow: hidden; | |
} | |
.chat-messages { | |
flex: 1; | |
overflow-y: auto; | |
padding: 20px; | |
} | |
.message { | |
margin-bottom: 16px; | |
display: flex; | |
align-items: flex-start; | |
} | |
.user-message { | |
justify-content: flex-end; | |
} | |
.assistant-message { | |
justify-content: flex-start; | |
} | |
.message-content { | |
max-width: 80%; | |
padding: 12px 16px; | |
border-radius: 18px; | |
overflow-wrap: break-word; | |
} | |
.user-message .message-content { | |
background-color: #0084ff; | |
color: white; | |
border-bottom-right-radius: 4px; | |
} | |
.assistant-message .message-content { | |
background-color: #f1f0f0; | |
color: #333; | |
border-bottom-left-radius: 4px; | |
} | |
.message-image { | |
max-width: 100%; | |
max-height: 300px; | |
border-radius: 8px; | |
margin-bottom: 8px; | |
} | |
.input-area { | |
background-color: #fff; | |
border-top: 1px solid #e6ecf0; | |
padding: 15px; | |
display: flex; | |
align-items: center; | |
gap: 10px; | |
} | |
.image-preview { | |
display: flex; | |
gap: 10px; | |
margin-bottom: 10px; | |
flex-wrap: wrap; | |
} | |
.image-preview img { | |
max-width: 100px; | |
max-height: 100px; | |
border-radius: 4px; | |
object-fit: cover; | |
} | |
.preview-container { | |
position: relative; | |
display: inline-block; | |
} | |
.remove-image { | |
position: absolute; | |
top: -5px; | |
right: -5px; | |
background-color: rgba(255, 255, 255, 0.8); | |
border-radius: 50%; | |
width: 20px; | |
height: 20px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
cursor: pointer; | |
font-size: 12px; | |
border: 1px solid #ddd; | |
} | |
textarea { | |
flex: 1; | |
border: 1px solid #e6ecf0; | |
border-radius: 20px; | |
padding: 10px 15px; | |
resize: none; | |
height: 48px; | |
font-size: 16px; | |
line-height: 1.5; | |
outline: none; | |
} | |
.send-button { | |
border: none; | |
background-color: #0084ff; | |
color: white; | |
border-radius: 50%; | |
width: 40px; | |
height: 40px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
cursor: pointer; | |
} | |
.send-button:disabled { | |
background-color: #cccccc; | |
cursor: not-allowed; | |
} | |
.clear-button { | |
background-color: #f7f7f7; | |
border: 1px solid #ddd; | |
color: #666; | |
padding: 8px 16px; | |
border-radius: 4px; | |
cursor: pointer; | |
transition: all 0.2s; | |
margin-bottom: 15px; | |
} | |
.clear-button:hover { | |
background-color: #ebebeb; | |
} | |
.system-prompt { | |
width: 100%; | |
padding: 10px; | |
border: 1px solid #e6ecf0; | |
border-radius: 4px; | |
margin-bottom: 15px; | |
min-height: 100px; | |
resize: vertical; | |
} | |
.thinking { | |
font-style: italic; | |
color: #666; | |
margin-bottom: 15px; | |
padding: 10px; | |
border-radius: 8px; | |
background-color: #f9f9f9; | |
display: inline-block; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1 class="mb-4">知微小智</h1> | |
<div class="chat-container"> | |
<div class="chat-box"> | |
<div class="chat-messages" id="chat-messages"> | |
<!-- 聊天消息将在这里动态添加 --> | |
</div> | |
<div class="input-area-container"> | |
<div class="image-preview" id="image-preview"></div> | |
<div class="input-area"> | |
<textarea id="message-input" placeholder="输入消息或按Ctrl+V粘贴图片..." onkeydown="handleKeyDown(event)"></textarea> | |
<button class="send-button" id="send-button" onclick="sendMessage()" disabled> | |
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M22 2L11 13" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
<path d="M22 2L15 22L11 13L2 9L22 2Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |
</svg> | |
</button> | |
</div> | |
</div> | |
</div> | |
<div class="sidebar" style="width: 300px;"> | |
<h5>设置</h5> | |
<label for="system-prompt">系统提示</label> | |
<textarea id="system-prompt" class="system-prompt">你是一个AI度量专家助手。你可以分析文本和图像的内容。能根据用户的需求给出度量建议和洞察</textarea> | |
<button class="clear-button" onclick="clearChat()">清除聊天记录</button> | |
<div class="mt-4"> | |
<p><strong>使用说明</strong></p> | |
<ul> | |
<li>输入文字直接提问</li> | |
<li>使用Ctrl+V粘贴图片</li> | |
<li>图片和文字可以一起发送</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
// 全局变量 | |
let chatHistory = []; | |
let currentImageData = null; | |
// 页面加载时初始化 | |
document.addEventListener('DOMContentLoaded', function() { | |
// 监听粘贴事件 | |
document.addEventListener('paste', handlePaste); | |
// 监听输入框变化 | |
const messageInput = document.getElementById('message-input'); | |
messageInput.addEventListener('input', function() { | |
document.getElementById('send-button').disabled = !messageInput.value.trim() && !currentImageData; | |
}); | |
}); | |
// 处理粘贴事件 | |
function handlePaste(event) { | |
const items = (event.clipboardData || event.originalEvent.clipboardData).items; | |
for (let i = 0; i < items.length; i++) { | |
if (items[i].type.indexOf('image') !== -1) { | |
const blob = items[i].getAsFile(); | |
const reader = new FileReader(); | |
reader.onload = function(e) { | |
// 设置当前图片数据 | |
currentImageData = e.target.result; | |
// 显示图片预览 | |
const imagePreview = document.getElementById('image-preview'); | |
imagePreview.innerHTML = ` | |
<div class="preview-container"> | |
<img src="${e.target.result}" alt="粘贴的图片"> | |
<div class="remove-image" onclick="removeImage()">×</div> | |
</div> | |
`; | |
// 启用发送按钮 | |
document.getElementById('send-button').disabled = false; | |
// 发送图片到服务器保存 | |
saveImageToServer(currentImageData); | |
}; | |
reader.readAsDataURL(blob); | |
} | |
} | |
} | |
// 移除图片 | |
function removeImage() { | |
currentImageData = null; | |
document.getElementById('image-preview').innerHTML = ''; | |
// 如果消息输入框也是空的,禁用发送按钮 | |
const messageInput = document.getElementById('message-input'); | |
document.getElementById('send-button').disabled = !messageInput.value.trim(); | |
} | |
// 保存图片到服务器 | |
function saveImageToServer(imageData) { | |
fetch('/api/paste_image', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ image_data: imageData }) | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
if (data.status === 'success') { | |
// 成功保存,可以在这里做一些处理,比如更新图片预览的src为服务器返回的URL | |
console.log('图片已保存到服务器:', data.image_url); | |
} else { | |
console.error('保存图片错误:', data.message); | |
} | |
}) | |
.catch(error => { | |
console.error('保存图片请求错误:', error); | |
}); | |
} | |
// 发送消息的键盘处理 | |
function handleKeyDown(event) { | |
if (event.key === 'Enter' && !event.shiftKey) { | |
event.preventDefault(); | |
sendMessage(); | |
} | |
} | |
// 发送消息 | |
function sendMessage() { | |
const messageInput = document.getElementById('message-input'); | |
const message = messageInput.value.trim(); | |
// 如果没有消息文本也没有图片,不发送 | |
if (!message && !currentImageData) { | |
return; | |
} | |
// 添加用户消息到聊天窗口 | |
addMessageToChat('user', message, currentImageData); | |
// 准备请求数据 | |
const systemPrompt = document.getElementById('system-prompt').value.trim(); | |
let history = [...chatHistory]; | |
// 确保历史记录中有系统提示 | |
const hasSystemPrompt = history.some(msg => msg.role === 'system'); | |
if (!hasSystemPrompt && systemPrompt) { | |
history.unshift({ | |
role: 'system', | |
content: systemPrompt | |
}); | |
} | |
// 显示思考中状态 | |
const thinkingEl = document.createElement('div'); | |
thinkingEl.className = 'message assistant-message'; | |
thinkingEl.innerHTML = '<div class="thinking">思考中...</div>'; | |
document.getElementById('chat-messages').appendChild(thinkingEl); | |
// 发送请求到后端 | |
fetch('/api/chat', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
message: message, | |
image: currentImageData, | |
history: history | |
}) | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
// 移除思考中状态 | |
document.getElementById('chat-messages').removeChild(thinkingEl); | |
if (data.status === 'success') { | |
// 添加助手响应到聊天窗口 | |
addMessageToChat('assistant', data.response); | |
} else { | |
// 显示错误消息 | |
addMessageToChat('assistant', `错误: ${data.message}`); | |
} | |
}) | |
.catch(error => { | |
// 移除思考中状态 | |
document.getElementById('chat-messages').removeChild(thinkingEl); | |
// 显示错误消息 | |
addMessageToChat('assistant', `请求错误: ${error}`); | |
}); | |
// 清空输入 | |
messageInput.value = ''; | |
removeImage(); | |
// 禁用发送按钮 | |
document.getElementById('send-button').disabled = true; | |
} | |
// 添加消息到聊天窗口和历史记录 | |
function addMessageToChat(role, content, image = null) { | |
const chatMessages = document.getElementById('chat-messages'); | |
// 创建消息元素 | |
const messageEl = document.createElement('div'); | |
messageEl.className = `message ${role}-message`; | |
let messageContent = ''; | |
// 如果有图片,添加图片 | |
if (image) { | |
messageContent += `<img src="${image}" alt="用户上传的图片" class="message-image"><br>`; | |
} | |
// 添加文本内容 | |
if (content) { | |
messageContent += content.replace(/\n/g, '<br>'); | |
} | |
messageEl.innerHTML = `<div class="message-content">${messageContent}</div>`; | |
chatMessages.appendChild(messageEl); | |
// 滚动到底部 | |
chatMessages.scrollTop = chatMessages.scrollHeight; | |
// 添加到历史记录 | |
chatHistory.push({ | |
role: role, | |
content: content | |
}); | |
} | |
// 清除聊天记录 | |
function clearChat() { | |
chatHistory = []; | |
document.getElementById('chat-messages').innerHTML = ''; | |
removeImage(); | |
} | |
</script> | |
</body> | |
</html> |