diff --git a/core/web_api.py b/core/web_api.py index b4cb425..4b7456c 100644 --- a/core/web_api.py +++ b/core/web_api.py @@ -149,8 +149,8 @@ def admin_required(f): @app.route('/') @login_required def index(): - """返回聊天页面(默认首页)""" - return app.send_static_file('index.html') + """默认首页 - 星图页面""" + return app.send_static_file('graph.html') @app.route('/graph.html') @@ -159,13 +159,6 @@ def graph_html(): """返回星图页面""" return app.send_static_file('graph.html') - -@app.route('/chat') -@login_required -def chat(): - """返回聊天页面""" - return app.send_static_file('index.html') - # 全局服务器和客户端实例 backend_server: BackendServer = None backend_client: BackendClient = None diff --git a/ui/static/graph.html b/ui/static/graph.html index b7b9ae4..198a15f 100644 --- a/ui/static/graph.html +++ b/ui/static/graph.html @@ -331,6 +331,104 @@ .chat-input-area button:hover { background: rgba(68, 136, 255, 0.5); } +.chat-input-area textarea { + flex: 1; + background: rgba(20, 20, 40, 0.9); + border: 1px solid rgba(100, 100, 255, 0.2); + color: #eee; + padding: 10px 14px; + border-radius: 6px; + font-family: 'Courier New', monospace; + font-size: 13px; + outline: none; + resize: none; + min-height: 40px; + max-height: 120px; +} +.chat-input-area textarea:focus { + border-color: rgba(68, 136, 255, 0.5); +} +.attach-btn { + background: rgba(68, 136, 255, 0.2); + border: 1px solid rgba(68, 136, 255, 0.3); + color: #aaf; + width: 40px; + height: 40px; + border-radius: 6px; + cursor: pointer; + font-size: 18px; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + flex-shrink: 0; +} +.attach-btn:hover { + background: rgba(68, 136, 255, 0.4); +} +.chat-files-container { + display: flex; + flex-wrap: wrap; + gap: 6px; + padding: 8px 16px; + border-top: 1px solid rgba(100, 100, 255, 0.1); + background: rgba(10, 10, 25, 0.5); +} +.chat-file-chip { + display: flex; + align-items: center; + gap: 6px; + background: rgba(40, 40, 80, 0.8); + border: 1px solid rgba(100, 100, 255, 0.25); + border-radius: 4px; + padding: 4px 8px; + font-size: 12px; + color: #dde; + max-width: 200px; +} +.chat-file-chip .file-icon { + color: #7af; + flex-shrink: 0; +} +.chat-file-chip .file-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1; +} +.chat-file-chip .file-size { + color: #889; + font-size: 10px; + flex-shrink: 0; +} +.chat-file-chip .file-remove { + color: #f66; + cursor: pointer; + font-size: 14px; + line-height: 1; + flex-shrink: 0; +} +.chat-file-chip .file-remove:hover { + color: #f33; +} +.chat-messages.drag-over { + background: rgba(68, 136, 255, 0.15); + border: 2px dashed rgba(68, 136, 255, 0.6); +} +.chat-messages.drag-over::after { + content: '📄 松开以上传文件'; + position: absolute; + top: 50%; left: 50%; + transform: translate(-50%, -50%); + background: rgba(10, 10, 40, 0.9); + border: 2px dashed rgba(68, 136, 255, 0.5); + color: #4488ff; + padding: 20px 40px; + border-radius: 12px; + font-size: 18px; + z-index: 10; + pointer-events: none; +} .chat-status { padding: 8px 16px; border-top: 1px solid rgba(100, 100, 255, 0.1); @@ -435,9 +533,12 @@
你好!我是 TrulyMEM,你的图记忆助手~
- + +
+ +
已连接
@@ -1775,6 +1876,73 @@ function smoothReposition() { const chatCloseBtn = document.getElementById('chatCloseBtn'); const toggleChat = document.getElementById('toggle-chat'); const chatPanel = document.getElementById('chat-panel'); + const attachBtn = document.getElementById('attachBtn'); + const fileInput = document.getElementById('fileInput'); + const chatFilesContainer = document.getElementById('chatFilesContainer'); + + let attachedFiles = []; + + function formatFileSize(bytes) { + if (bytes < 1024) return bytes + 'B'; + if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + 'KB'; + return (bytes / (1024 * 1024)).toFixed(1) + 'MB'; + } + + function getFileKey(file) { + return file.name + '_' + file.size; + } + + function addFileChip(file) { + const key = getFileKey(file); + if (attachedFiles.some(f => getFileKey(f) === key)) return; + attachedFiles.push(file); + renderFileChips(); + } + + function removeFileChip(file) { + const key = getFileKey(file); + attachedFiles = attachedFiles.filter(f => getFileKey(f) !== key); + renderFileChips(); + } + + function renderFileChips() { + chatFilesContainer.innerHTML = ''; + attachedFiles.forEach(file => { + const chip = document.createElement('div'); + chip.className = 'chat-file-chip'; + chip.innerHTML = `📄${file.name}${formatFileSize(file.size)}`; + chip.querySelector('.file-remove').onclick = () => removeFileChip(file); + chatFilesContainer.appendChild(chip); + }); + } + + // 输入框自适应高度 + chatInput.addEventListener('input', () => { + chatInput.style.height = 'auto'; + chatInput.style.height = Math.min(chatInput.scrollHeight, 120) + 'px'; + }); + + attachBtn.addEventListener('click', () => fileInput.click()); + + fileInput.addEventListener('change', () => { + Array.from(fileInput.files).forEach(addFileChip); + fileInput.value = ''; + }); + + chatMessages.addEventListener('dragover', e => { + e.preventDefault(); + chatMessages.classList.add('drag-over'); + }); + + chatMessages.addEventListener('dragleave', () => { + chatMessages.classList.remove('drag-over'); + }); + + chatMessages.addEventListener('drop', e => { + e.preventDefault(); + chatMessages.classList.remove('drag-over'); + Array.from(e.dataTransfer.files).forEach(addFileChip); + }); let chatCollapsed = false; toggleChat.addEventListener('click', () => { @@ -1836,11 +2004,44 @@ function smoothReposition() { } } + function buildFullMessage(text, files) { + if (!files || files.length === 0) return text; + let parts = []; + files.forEach(file => { + parts.push(`文件名:${file.name}`); + parts.push(`内容:`); + parts.push(file.content); + parts.push('---'); + }); + parts.push(text); + return parts.join('\n'); + } + async function sendChatMessage() { + const files = attachedFiles.slice(); const msg = chatInput.value.trim(); - if (!msg) return; + if (!msg && files.length === 0) return; chatInput.value = ''; - addChatMessage('user', msg); + // 读取文件内容 + let fullMsg = msg; + if (files.length > 0) { + const fileReads = files.map(file => new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { file.content = reader.result; resolve(); }; + reader.onerror = reject; + reader.readAsText(file); + })); + try { + await Promise.all(fileReads); + } catch(e) { + console.error('文件读取失败:', e); + } + fullMsg = buildFullMessage(msg, files); + // 清除文件芯片 + attachedFiles = []; + renderFileChips(); + } + addChatMessage('user', fullMsg); chatInput.disabled = true; chatSendBtn.disabled = true; chatStatus.textContent = '⏳ 处理中...'; @@ -1850,7 +2051,7 @@ function smoothReposition() { const res = await fetch('/api/message', { method: 'POST', headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({message: msg}) + body: JSON.stringify({message: fullMsg}) }); const data = await res.json(); if (data.success) { diff --git a/ui/static/index.html b/ui/static/index.html deleted file mode 100644 index f7db682..0000000 --- a/ui/static/index.html +++ /dev/null @@ -1,1399 +0,0 @@ - - - - - -TrulyMEM - TrueHumanMEM - - - - - - -
- -
-
-
-
[AI] 系统就绪
-
正在连接...
-
-
- -
-
- -
📄 松开以上传文件
- -
- - -
-
- - -
-
-
- - -
- - -
-
API 配置
- -
API Key
- - -
Base URL
- - -
Model
- - -
修改后自动保存
-
- -
-
操作日志
-
暂无操作记录
-
- - -
-
- - -
- - API: 未配置 - -
- - - - - -
-
- - - - - - - -