diff --git a/Html/apps/extension_ase/ase_client/manager.py b/Html/apps/extension_ase/ase_client/manager.py index 583b642..1af1639 100644 --- a/Html/apps/extension_ase/ase_client/manager.py +++ b/Html/apps/extension_ase/ase_client/manager.py @@ -129,10 +129,11 @@ class ChatManager: self.chapter_chain_now = chapter_index self.chapter_chain[chapter_index].Focus() - def load_now_chapter(self): + def load_now_chapter(self, load_code = True): print(f"now load now chapter markdown {self.chapter_chain_now}") self.ase_client.loadmarkdown(self.chapter_chain[self.chapter_chain_now].chapter, self.chapter_chain[self.chapter_chain_now].chapter_prompt, self.chapter_chain[self.chapter_chain_now].score_prompt) - self.load_code_in_markdown() + if load_code: + self.load_code_in_markdown() def upload_bb(self): diff --git a/Html/apps/services/asectrl_service.py b/Html/apps/services/asectrl_service.py index f7ca0a9..5505f7f 100644 --- a/Html/apps/services/asectrl_service.py +++ b/Html/apps/services/asectrl_service.py @@ -34,8 +34,8 @@ def on_connect_to_ase(client, entry, init_data, **kwargs): clear_user_session(namespace_entry, init_data['room']) restart = init_data.get("restart", False) + ase_client.chatmanager.load_now_chapter(load_code=restart) if restart: - ase_client.chatmanager.load_now_chapter() ase_client.send_text("chapter-start", "") namespace_entry.emit('message', "教案加载完毕", room=init_data['room'], namespace='/agent') diff --git a/Html/apps/sockets/namespaces.py b/Html/apps/sockets/namespaces.py index c385e59..c1fa2f7 100644 --- a/Html/apps/sockets/namespaces.py +++ b/Html/apps/sockets/namespaces.py @@ -136,10 +136,15 @@ class AgentNamespace(Namespace): chatmanager.init(user_uuid, user_uuid2ase_client[user_uuid], fmd, fmdp, fsp, course_id, chapter_name, lesson_name, max_iter=5, app=current_app, socketio=self) backboard_manager.add_backboard(user_uuid, user_id, course_id, lesson_name, root_path=f'/home/{user_id}/{course_id}/{chapter_name}/{lesson_name}') chatmanager.bb = backboard_manager.get_backboard(user_uuid) - # 如果有保存的进度,需要跳过已经完成的章节 + # 如果有保存的进度,需要跳过已经完成的章节、无需清空代码、对话历史恢复 if continue_learn: for _ in range(need_skip_chapters): chatmanager.next_chapter() + + # 恢复对话历史到前端 - 使用批量发送消息列表 + if chatmanager.chat_historys: + emit('messages', chatmanager.chat_historys, room=user_uuid, namespace='/agent') + self.chatmanager = chatmanager self.ase_client = user_uuid2ase_client[user_uuid] user_uuid2ase_client[user_uuid].register_on_connect_entry( diff --git a/Html/apps/static/js/chatbox.js b/Html/apps/static/js/chatbox.js index 7ba5155..346c07b 100644 --- a/Html/apps/static/js/chatbox.js +++ b/Html/apps/static/js/chatbox.js @@ -2,6 +2,57 @@ var socket; let system_message_idx = 0 const activeApprovals = {}; +let chatManager; // 全局聊天管理器实例 + +// 聊天消息管理器 - 更现代的数据结构 +class ChatMessageManager { + constructor() { + this.chatbox = document.getElementById('chatbox'); + this.messageTemplate = { + user: `
你: {{content}}
`, + assistant: `
华实君:
{{content}}
` + }; + } + + // 渲染单个消息 + renderMessage(message) { + let html; + let content; + + // 处理不同的数据格式 + if (typeof message === 'string') { + // 旧格式:直接字符串 + content = marked.parse(message); + html = this.messageTemplate.assistant.replace('{{content}}', content); + } else if (typeof message === 'object' && message !== null) { + // 新格式:{role, content} 对象 + content = marked.parse(message.content); + if (message.role === 'user') { + html = this.messageTemplate.user.replace('{{content}}', content); + } else { + html = this.messageTemplate.assistant.replace('{{content}}', content); + } + } + + if (html) { + const messageDiv = document.createElement('div'); + messageDiv.innerHTML = html; + this.chatbox.appendChild(messageDiv); + this.scrollToBottom(); + } + } + + // 渲染多条消息(用于恢复历史) + renderMessages(messages) { + messages.forEach(message => this.renderMessage(message)); + } + + // 滚动到底部 + scrollToBottom() { + this.chatbox.scrollTop = this.chatbox.scrollHeight; + } +} + // 清理过期的批准记录 function cleanupExpiredApprovals() { const now = Date.now(); @@ -24,6 +75,10 @@ document.addEventListener('DOMContentLoaded', function () { folder: data.folder } }); + + // 初始化聊天消息管理器 + const chatManager = new ChatMessageManager(); + socket.on('connect', function () { console.log('Connected to server'); socket.emit('login',JSON.stringify(data)); @@ -38,12 +93,13 @@ document.addEventListener('DOMContentLoaded', function () { input.value += data; }); socket.on('message', function (data) { - // 显示服务器的回复消息 - const serverMessage = document.createElement('div'); - serverMessage.innerHTML = `
华实君:
${marked.parse(data)}
`; - document.getElementById('chatbox').appendChild(serverMessage); - // 滚动到最新消息 - document.getElementById('chatbox').scrollTop = document.getElementById('chatbox').scrollHeight; + // 显示服务器的回复消息 - 单个消息 + chatManager.renderMessage(data); + }); + + socket.on('messages', function (data) { + // 显示服务器发送的消息列表 - 用于恢复对话历史 + chatManager.renderMessages(data); }); socket.on('message-hint', function(data){ console.log('get message-hint'); @@ -210,22 +266,14 @@ function sendMessage() { const input = document.getElementById('messageInput').value; if (input.trim() === '') return; - // 使用 marked.js 解析 markdown - const markdownHtml = marked.parse(input); - - // 显示用户发送的消息 - const userMessage = document.createElement('div'); - userMessage.innerHTML = `
你: ${markdownHtml}
`; - document.getElementById('chatbox').appendChild(userMessage); - // 发送消息到服务器 socket.emit('message', JSON.stringify({ data: input, type: 'text' })); + // 使用聊天管理器显示用户消息 + chatManager.renderMessage({ role: 'user', content: input }); + // 清空输入框 document.getElementById('messageInput').value = ''; - - // 滚动到最新消息 - document.getElementById('chatbox').scrollTop = document.getElementById('chatbox').scrollHeight; }