diff --git a/index.html b/index.html
index 654a579..69eb215 100644
--- a/index.html
+++ b/index.html
@@ -9,6 +9,8 @@
+
+
+
+
+
+
+
Conversation History
+
+
@@ -280,10 +392,80 @@
const chatContainer = document.getElementById('chat-container');
const userInput = document.getElementById('user-input');
const sendButton = document.getElementById('send-button');
+ const chatTabs = document.getElementById('chat-tabs');
- let thinkingElement = null;
- let thinkingDetails = null;
- let thinkingStartTime = null;
+ let currentChatId = null;
+ let chats = {};
+
+ function createNewChat() {
+ const chatId = Date.now().toString();
+ chats[chatId] = {
+ messages: [],
+ thinkingSections: []
+ };
+ addChatTab(chatId);
+ switchToChat(chatId);
+ saveChats();
+ }
+
+ function addChatTab(chatId) {
+ const tab = document.createElement('button');
+ tab.classList.add('chat-tab');
+ tab.textContent = `Chat ${Object.keys(chats).length}`;
+ tab.onclick = () => switchToChat(chatId);
+
+ const closeButton = document.createElement('span');
+ closeButton.classList.add('close-tab');
+ closeButton.textContent = '×';
+ closeButton.onclick = (e) => {
+ e.stopPropagation();
+ closeChat(chatId);
+ };
+
+ tab.appendChild(closeButton);
+ chatTabs.insertBefore(tab, chatTabs.lastElementChild);
+ }
+
+ function switchToChat(chatId) {
+ currentChatId = chatId;
+ document.querySelectorAll('.chat-tab').forEach(tab => tab.classList.remove('active'));
+ document.querySelector(`.chat-tab:nth-child(${Object.keys(chats).indexOf(chatId) + 1})`).classList.add('active');
+ renderChat(chatId);
+ }
+
+ function closeChat(chatId) {
+ delete chats[chatId];
+ saveChats();
+ const tabToRemove = Array.from(chatTabs.children).find(tab => tab.textContent.includes(`Chat ${Object.keys(chats).indexOf(chatId) + 1}`));
+ if (tabToRemove) {
+ chatTabs.removeChild(tabToRemove);
+ }
+ if (currentChatId === chatId) {
+ const remainingChatIds = Object.keys(chats);
+ if (remainingChatIds.length > 0) {
+ switchToChat(remainingChatIds[0]);
+ } else {
+ createNewChat();
+ }
+ }
+ }
+
+ function renderChat(chatId) {
+ chatContainer.innerHTML = '';
+ const chat = chats[chatId];
+ chat.messages.forEach(message => addMessage(message.content, message.isUser));
+ chat.thinkingSections.forEach(section => {
+ const thinkingSection = createThinkingSection();
+ section.thoughts.forEach(thought => addThought(thought.type, thought.content, thought.details, thinkingSection));
+ });
+ }
+
+ function createThinkingSection() {
+ const section = document.createElement('div');
+ section.classList.add('thinking-section');
+ chatContainer.appendChild(section);
+ return section;
+ }
function addMessage(message, isUser) {
const messageElement = document.createElement('div');
@@ -292,65 +474,40 @@
messageElement.innerHTML = isUser ? message : marked.parse(message);
chatContainer.appendChild(messageElement);
chatContainer.scrollTop = chatContainer.scrollHeight;
+
+ if (currentChatId) {
+ chats[currentChatId].messages.push({ content: message, isUser: isUser });
+ saveChats();
+ }
}
- function startThinking() {
- thinkingElement = document.createElement('div');
- thinkingElement.classList.add('thought-summary', 'collapsible');
+ function addThought(type, content, details = '', thinkingSection) {
+ const stepElement = document.createElement('div');
+ stepElement.classList.add('thought-summary', 'collapsible', type);
+ stepElement.textContent = type.charAt(0).toUpperCase() + type.slice(1).replace('_', ' ') + ':';
+ stepElement.onclick = toggleStepDetails;
+
+ const stepDetails = document.createElement('div');
+ stepDetails.classList.add('thought-details');
- const led = document.createElement('div');
- led.classList.add('led', 'blinking');
-
- const textNode = document.createTextNode('Thinking...');
-
- thinkingElement.appendChild(led);
- thinkingElement.appendChild(textNode);
- thinkingElement.onclick = toggleThinkingDetails;
-
- thinkingDetails = document.createElement('div');
- thinkingDetails.classList.add('thought-details');
-
- chatContainer.appendChild(thinkingElement);
- chatContainer.appendChild(thinkingDetails);
-
- thinkingStartTime = Date.now();
+ if (type === 'error') {
+ stepElement.classList.add('error-message');
+ if (content.includes('retrying')) {
+ stepElement.classList.add('retrying');
+ }
+ stepDetails.innerHTML = marked.parse(content + '\n\nDetails:\n```\n' + details + '\n```');
+ } else {
+ stepDetails.innerHTML = marked.parse(content);
+ }
+
+ thinkingSection.appendChild(stepElement);
+ thinkingSection.appendChild(stepDetails);
chatContainer.scrollTop = chatContainer.scrollHeight;
- }
- function addThought(step, content) {
- if (thinkingDetails) {
- const stepElement = document.createElement('div');
- stepElement.classList.add('thought-summary', 'collapsible');
- stepElement.textContent = step;
- stepElement.onclick = toggleStepDetails;
-
- const stepDetails = document.createElement('div');
- stepDetails.classList.add('thought-details');
- stepDetails.innerHTML = content;
-
- thinkingDetails.appendChild(stepElement);
- thinkingDetails.appendChild(stepDetails);
- chatContainer.scrollTop = chatContainer.scrollHeight;
- }
- }
-
- function endThinking(thinkingTime) {
- if (thinkingElement) {
- const textNode = thinkingElement.childNodes[1];
- textNode.nodeValue = `Thinking... (${thinkingTime}s)`;
- const led = thinkingElement.querySelector('.led');
- led.classList.remove('blinking');
- led.style.backgroundColor = '#0f0';
- led.style.boxShadow = '0 0 10px #0f0';
- thinkingStartTime = null;
- }
- }
-
- function toggleThinkingDetails() {
- this.classList.toggle('open');
- const details = this.nextElementSibling;
- if (details) {
- details.style.display = details.style.display === 'none' ? 'block' : 'none';
+ if (currentChatId) {
+ const currentThinkingSection = chats[currentChatId].thinkingSections[chats[currentChatId].thinkingSections.length - 1];
+ currentThinkingSection.thoughts.push({ type, content, details });
+ saveChats();
}
}
@@ -362,34 +519,71 @@
}
}
- socket.on('thinking', (data) => {
- if (!thinkingElement) startThinking();
- addThought(data.step, 'Started');
- });
+ function saveChats() {
+ localStorage.setItem('chats', JSON.stringify(chats));
+ }
- socket.on('thought', (data) => {
- addThought('Result', data.content);
- });
-
- socket.on('chat_response', (data) => {
- endThinking(data.thinking_time);
- addMessage(data.response, false);
- });
-
- socket.on('error', (data) => {
- endThinking(data.thinking_time);
- addMessage(`Error: ${data.message}`, false);
- });
+ function loadChats() {
+ const storedChats = localStorage.getItem('chats');
+ if (storedChats) {
+ chats = JSON.parse(storedChats);
+ Object.keys(chats).forEach(chatId => addChatTab(chatId));
+ if (Object.keys(chats).length > 0) {
+ switchToChat(Object.keys(chats)[0]);
+ } else {
+ createNewChat();
+ }
+ } else {
+ createNewChat();
+ }
+ }
function sendMessage() {
const message = userInput.value.trim();
- if (message) {
+ if (message && currentChatId) {
addMessage(message, true);
- socket.emit('chat_request', { message: message });
+ chats[currentChatId].thinkingSections.push({ thoughts: [] });
+ socket.emit('chat_request', {
+ message: message,
+ conversation_history: chats[currentChatId].messages.filter(m => !m.isUser).map(m => ({ role: 'assistant', content: m.content }))
+ .concat(chats[currentChatId].messages.filter(m => m.isUser).map(m => ({ role: 'user', content: m.content })))
+ });
userInput.value = '';
}
}
+ socket.on('thinking', (data) => {
+ if (currentChatId) {
+ const newThinkingSection = createThinkingSection();
+ chats[currentChatId].thinkingSections.push({ thoughts: [] });
+ addThought(data.step, 'Started', '', newThinkingSection);
+ }
+ });
+
+ socket.on('thought', (data) => {
+ if (currentChatId) {
+ const currentThinkingSection = chatContainer.querySelector('.thinking-section:last-child');
+ addThought(data.type, data.content, data.details, currentThinkingSection);
+ }
+ });
+
+ socket.on('chat_response', (data) => {
+ if (currentChatId) {
+ addMessage(data.response, false);
+ }
+ });
+
+ socket.on('error', (data) => {
+ if (currentChatId) {
+ const currentThinkingSection = chatContainer.querySelector('.thinking-section:last-child');
+ if (data.type === 'retrying') {
+ addThought('error', data.content, '', currentThinkingSection);
+ } else {
+ addThought('error', data.message, '', currentThinkingSection);
+ }
+ }
+ });
+
sendButton.addEventListener('click', sendMessage);
userInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
@@ -398,6 +592,16 @@
}
});
+ // Add new chat button
+ const newChatButton = document.createElement('button');
+ newChatButton.id = 'new-chat-button';
+ newChatButton.textContent = '+ New Chat';
+ newChatButton.onclick = createNewChat;
+ chatTabs.appendChild(newChatButton);
+
+ // Load chats when the page loads
+ loadChats();
+
const chartOptions = {
type: 'line',
options: {
@@ -570,6 +774,41 @@
window.addEventListener('resize', checkWindowSize);
checkWindowSize(); // Initial check
+
+ // Add this new function to update the conversation history
+ function updateConversationHistory(history) {
+ const conversationHistoryElement = document.getElementById('conversation-history');
+ conversationHistoryElement.innerHTML = '';
+
+ history.forEach(item => {
+ const card = document.createElement('div');
+ card.classList.add('history-card');
+
+ const role = document.createElement('div');
+ role.classList.add('history-role');
+ role.textContent = item.role.charAt(0).toUpperCase() + item.role.slice(1);
+
+ const content = document.createElement('pre');
+ content.classList.add('history-content');
+ content.innerHTML = hljs.highlightAuto(item.content).value;
+
+ card.appendChild(role);
+ card.appendChild(content);
+ conversationHistoryElement.appendChild(card);
+ });
+ }
+
+ // Add this new socket listener
+ socket.on('conversation_history', (data) => {
+ updateConversationHistory(data.history);
+ });
+
+ // Add event listener for the clear history button
+ clearHistoryButton.addEventListener('click', () => {
+ if (confirm('Are you sure you want to clear the conversation history?')) {
+ clearConversationHistory();
+ }
+ });