feat: 添加浏览器favicon,优化消息操作按钮(复制+重新生成)
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>AI 对话系统 v2.0</title>
|
<title>AI 对话系统 v2.0</title>
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🤖</text></svg>">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/github-markdown-css@5.2.0/github-markdown-light.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/github-markdown-css@5.2.0/github-markdown-light.min.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
@@ -49,11 +51,14 @@
|
|||||||
/* 用户消息样式 */
|
/* 用户消息样式 */
|
||||||
.user-message-text { background: #f0f0f0; padding: 12px 16px; border-radius: 12px; font-size: 15px; }
|
.user-message-text { background: #f0f0f0; padding: 12px 16px; border-radius: 12px; font-size: 15px; }
|
||||||
|
|
||||||
/* 复制按钮 */
|
/* 消息操作按钮 */
|
||||||
.copy-btn { position: absolute; top: 8px; right: 8px; padding: 4px 8px; background: rgba(0,0,0,0.05); border: 1px solid #ddd; border-radius: 4px; cursor: pointer; font-size: 12px; color: #666; opacity: 0; transition: opacity 0.2s; }
|
.message-actions { display: flex; gap: 8px; margin-top: 8px; opacity: 0; transition: opacity 0.2s; }
|
||||||
.message-content:hover .copy-btn { opacity: 1; }
|
.message-content:hover + .message-actions,
|
||||||
.copy-btn:hover { background: rgba(0,0,0,0.1); }
|
.message-actions:hover { opacity: 1; }
|
||||||
.copy-btn.copied { color: #10a37f; border-color: #10a37f; }
|
.action-btn { padding: 6px 12px; background: #f5f5f5; border: 1px solid #e0e0e0; border-radius: 6px; cursor: pointer; font-size: 12px; color: #666; display: flex; align-items: center; gap: 4px; transition: all 0.2s; }
|
||||||
|
.action-btn:hover { background: #e8e8e8; border-color: #ccc; }
|
||||||
|
.action-btn.copied { color: #10a37f; border-color: #10a37f; background: #e8f5e9; }
|
||||||
|
.action-btn.regenerate:hover { color: #667eea; border-color: #667eea; }
|
||||||
|
|
||||||
/* 思考内容样式 */
|
/* 思考内容样式 */
|
||||||
.thinking-block { background: #f8f9fa; border-left: 3px solid #667eea; padding: 12px 16px; margin: 8px 0 16px 0; font-size: 14px; color: #666; border-radius: 4px; position: relative; }
|
.thinking-block { background: #f8f9fa; border-left: 3px solid #667eea; padding: 12px 16px; margin: 8px 0 16px 0; font-size: 14px; color: #666; border-radius: 4px; position: relative; }
|
||||||
@@ -167,6 +172,7 @@
|
|||||||
let currentAgentId = null;
|
let currentAgentId = null;
|
||||||
let agents = [];
|
let agents = [];
|
||||||
let quickPhrases = [];
|
let quickPhrases = [];
|
||||||
|
let lastUserMessage = null; // 存储最后一条用户消息,用于重新生成
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
loadAgents();
|
loadAgents();
|
||||||
@@ -234,7 +240,10 @@
|
|||||||
case 'new_conversation': currentConversationId = data.conversation_id; loadConversations(); clearMessages(); break;
|
case 'new_conversation': currentConversationId = data.conversation_id; loadConversations(); clearMessages(); break;
|
||||||
case 'agent_switched': currentAgentId = data.agent_id; break;
|
case 'agent_switched': currentAgentId = data.agent_id; break;
|
||||||
case 'stream_end': document.getElementById('sendBtn').disabled = false; break;
|
case 'stream_end': document.getElementById('sendBtn').disabled = false; break;
|
||||||
case 'user_message': appendMessage('user', data.message.content); break;
|
case 'user_message':
|
||||||
|
lastUserMessage = data.message.content; // 存储最后一条用户消息
|
||||||
|
appendMessage('user', data.message.content);
|
||||||
|
break;
|
||||||
case 'assistant_message': appendMessage('assistant', data.message.content, data.message.thinking_content, data.message.agent_name); document.getElementById('sendBtn').disabled = false; break;
|
case 'assistant_message': appendMessage('assistant', data.message.content, data.message.thinking_content, data.message.agent_name); document.getElementById('sendBtn').disabled = false; break;
|
||||||
case 'error': showError(data.message); document.getElementById('sendBtn').disabled = false; break;
|
case 'error': showError(data.message); document.getElementById('sendBtn').disabled = false; break;
|
||||||
}
|
}
|
||||||
@@ -269,9 +278,15 @@
|
|||||||
} else {
|
} else {
|
||||||
html += `<div class="user-message-text">${escapeHtml(content)}</div>`;
|
html += `<div class="user-message-text">${escapeHtml(content)}</div>`;
|
||||||
}
|
}
|
||||||
// 复制按钮 - 使用隐藏input存储原始内容
|
html += `</div>`;
|
||||||
|
|
||||||
|
// 操作按钮 - 使用隐藏input存储原始内容
|
||||||
html += `<input type="hidden" class="copy-source" value="${content.replace(/"/g, '"')}">`;
|
html += `<input type="hidden" class="copy-source" value="${content.replace(/"/g, '"')}">`;
|
||||||
html += `<button class="copy-btn" onclick="copyMessage(this)"><i class="ri-file-copy-line"></i> 复制</button>`;
|
html += `<div class="message-actions">`;
|
||||||
|
html += `<button class="action-btn" onclick="copyMessage(this)"><i class="ri-file-copy-line"></i> 复制</button>`;
|
||||||
|
if (role === 'assistant') {
|
||||||
|
html += `<button class="action-btn regenerate" onclick="regenerateMessage()"><i class="ri-refresh-line"></i> 重新生成</button>`;
|
||||||
|
}
|
||||||
html += `</div>`;
|
html += `</div>`;
|
||||||
|
|
||||||
// Agent信息
|
// Agent信息
|
||||||
@@ -300,38 +315,47 @@
|
|||||||
|
|
||||||
function copyMessage(btn) {
|
function copyMessage(btn) {
|
||||||
// 从隐藏input获取原始内容
|
// 从隐藏input获取原始内容
|
||||||
const hiddenInput = btn.parentElement.querySelector('.copy-source');
|
const hiddenInput = btn.closest('.message-body').querySelector('.copy-source');
|
||||||
if (!hiddenInput) {
|
if (!hiddenInput) {
|
||||||
console.error('找不到复制源');
|
console.error('找不到复制源');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const text = hiddenInput.value;
|
const text = hiddenInput.value;
|
||||||
|
|
||||||
// 创建临时textarea复制
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
const textarea = document.createElement('textarea');
|
btn.innerHTML = '<i class="ri-check-line"></i> 已复制';
|
||||||
textarea.value = text;
|
btn.classList.add('copied');
|
||||||
textarea.style.position = 'fixed';
|
setTimeout(() => {
|
||||||
textarea.style.left = '-9999px';
|
btn.innerHTML = '<i class="ri-file-copy-line"></i> 复制';
|
||||||
document.body.appendChild(textarea);
|
btn.classList.remove('copied');
|
||||||
textarea.select();
|
}, 2000);
|
||||||
|
}).catch(err => {
|
||||||
try {
|
|
||||||
const success = document.execCommand('copy');
|
|
||||||
if (success) {
|
|
||||||
btn.innerHTML = '<i class="ri-check-line"></i> 已复制';
|
|
||||||
btn.classList.add('copied');
|
|
||||||
setTimeout(() => {
|
|
||||||
btn.innerHTML = '<i class="ri-file-copy-line"></i> 复制';
|
|
||||||
btn.classList.remove('copied');
|
|
||||||
}, 2000);
|
|
||||||
} else {
|
|
||||||
btn.innerHTML = '<i class="ri-error-line"></i> 失败';
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('复制失败:', err);
|
console.error('复制失败:', err);
|
||||||
|
btn.innerHTML = '<i class="ri-error-line"></i> 失败';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function regenerateMessage() {
|
||||||
|
if (!lastUserMessage) {
|
||||||
|
alert('没有可重新生成的消息');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 移除最后一条助手消息
|
||||||
|
const container = document.getElementById('messagesContainer');
|
||||||
|
const messages = container.querySelectorAll('.message.assistant');
|
||||||
|
if (messages.length > 0) {
|
||||||
|
messages[messages.length - 1].remove();
|
||||||
|
}
|
||||||
|
// 重新发送最后一条用户消息
|
||||||
|
document.getElementById('sendBtn').disabled = true;
|
||||||
|
if (ws?.readyState === WebSocket.OPEN) {
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
action: 'chat',
|
||||||
|
message: lastUserMessage,
|
||||||
|
conversation_id: currentConversationId,
|
||||||
|
agent_id: currentAgentId
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.removeChild(textarea);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHtml(text) {
|
function escapeHtml(text) {
|
||||||
|
|||||||
Reference in New Issue
Block a user