diff --git a/media/chatPanel.css b/media/chatPanel.css index 9f81fa9..510ce01 100644 --- a/media/chatPanel.css +++ b/media/chatPanel.css @@ -15,47 +15,110 @@ body { padding: 0; } +p { + margin-top: 0; +} + +pre { + background-color: #f1f1f1; + overflow: auto; + margin-top: 0; +} + #chat-container { display: flex; flex-direction: column; height: 100vh; } +.code-block { + background-color: #f1f1f1; + color: #000000; + padding: 10px; + border-radius: 4px; + overflow-y: auto; + font-size: 14px; + margin: 0; + display: block; + margin: 10px 0; + padding: 10px; + background-color: #f1f1f1; + border-radius: 5px; + overflow: auto; +} + +.copy-button { + background-color: #007acc; + color: white; + border: none; + border-radius: 4px; + padding: 5px; + cursor: pointer; + margin-top: 5px; +} + +.copy-button:hover { + background-color: #005b8e; +} + + #messages-container { flex-grow: 1; overflow-y: auto; padding: 10px; } -.message { +.message-item { display: flex; - align-items: center; + align-items: flex-start; + justify-content: space-between; margin: 20px 0; -} - -.sender-icon { - width: 24px; - height: 24px; - margin-right: 40px; -} - -.message-text { - flex-grow: 1; - padding: 5px 10px; /* Add some padding to the message text */ + padding: 10px; border-radius: 4px; + border-bottom: 1px solid var(--vscode-border); } -.user-message .message-text { - background-color: #007acc; /* Different background color for user messages */ +.message-item.user-message { + background-color: #007acc; color: white; } -.bot-message .message-text { - background-color: #f1f1f1; /* Different background color for bot messages */ - color: black; +.message-content { + margin-left: 30px; + margin-right: 30px; } -.action-icon { +.message-item .message-content { + flex-grow: 1; +} + +.new-message-textarea { + width: 100%; + height: 100%; + border: none; + background-color: transparent; + padding: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; + color: inherit; + overflow: hidden; + resize: none; +} + +.message-item .message-content code { + background-color: #ddd; + padding: 2px 4px; + border-radius: 4px; +} + +.message-item .sender-icon { + width: 24px; + height: 24px; + margin-right: 10px; +} + +.message-item .action-icon { width: 24px; height: 24px; margin-left: 10px; @@ -63,20 +126,32 @@ body { #input-container { display: flex; + flex-direction: column; padding: 10px; border-top: 1px solid #ccc; } +.input-resize-handle { + width: 100%; + height: 5px; + cursor: ns-resize; + bottom: 0; + left: 0; + z-index: 1; +} + + #message-input { flex-grow: 1; border: 1px solid #ccc; border-radius: 4px; padding: 5px; outline: none; + resize: none; } #send-button { - margin-left: 10px; + margin-top: 10px; background-color: var(--vscode-button-bg); color: var(--vscode-button-fg); border: 1px solid var(--vscode-border); @@ -87,4 +162,4 @@ body { #send-button:hover { background-color: var(--vscode-button-hover-bg); -} \ No newline at end of file +} diff --git a/media/chatPanel.html b/media/chatPanel.html index 0d178ce..6f544cd 100644 --- a/media/chatPanel.html +++ b/media/chatPanel.html @@ -1,21 +1,40 @@ - + + + + + Chat Panel + + + + +
+
- +
- - + + + + + + + diff --git a/media/chatPanel.js b/media/chatPanel.js deleted file mode 100644 index dc6659c..0000000 --- a/media/chatPanel.js +++ /dev/null @@ -1,74 +0,0 @@ -(function () { - const vscode = acquireVsCodeApi(); - - const messageInput = document.getElementById('message-input'); - const sendButton = document.getElementById('send-button'); - const messagesContainer = document.getElementById('messages-container'); - - function addMessageToUI(message, senderIconClass, actionIconClass, messageType) { - const messageElement = document.createElement('div'); - messageElement.classList.add('message', messageType); - - const senderIcon = document.createElement('i'); - senderIcon.className = senderIconClass; - - const messageText = document.createElement('span'); - messageText.classList.add('message-text'); - messageText.textContent = message; - - const actionIcon = document.createElement('i'); - actionIcon.className = actionIconClass; - - messageElement.appendChild(senderIcon); - messageElement.appendChild(messageText); - messageElement.appendChild(actionIcon); - messagesContainer.appendChild(messageElement); - messagesContainer.scrollTop = messagesContainer.scrollHeight; - } - - window.addEventListener('message', (event) => { - const message = event.data; - switch (message.command) { - case 'receiveMessage': - // Display the received message in the chat UI - const botIconClass = 'fas fa-robot'; - const actionIconClass = 'fas fa-check-circle'; - - addMessageToUI(message.text, botIconClass, actionIconClass, 'bot-message'); - break; - } - }); - - function processMessage(message) { - // Process the message and get the bot's response - // For an echo bot, return the same message - vscode.postMessage({ - command: 'sendMessage', - text: message - }); - - return message; - } - - sendButton.addEventListener('click', () => { - const message = messageInput.value; - if (message) { - const userIconClass = 'fas fa-user-circle'; - const botIconClass = 'fas fa-robot'; - const actionIconClass = 'fas fa-check-circle'; - - addMessageToUI(message, userIconClass, actionIconClass, 'user-message'); - messageInput.value = ''; - - const botResponse = processMessage(message); - - } - }); - - messageInput.addEventListener('keypress', (event) => { - if (event.key === 'Enter') { - sendButton.click(); - } - }); -})(); - diff --git a/media/chatUI.js b/media/chatUI.js new file mode 100644 index 0000000..b957ad6 --- /dev/null +++ b/media/chatUI.js @@ -0,0 +1,124 @@ +const vscode_api = acquireVsCodeApi(); +const md = new markdownit(); + +function addMessageToUI(role, content) { + // Create a MarkdownIt instance for rendering markdown content + const messagesContainer = document.getElementById('messages-container'); + + // Create a container for the message item + const messageItem = document.createElement('div'); + messageItem.classList.add('message-item'); + + // Create a sender icon element and add the appropriate class based on the role (user or bot) + const senderIcon = document.createElement('i'); + const iconClasses = role === 'user' ? ['fas', 'fa-user-circle'] : ['fas', 'fa-robot']; + senderIcon.classList.add(...iconClasses); + + // Create a container for the message content + const messageContent = document.createElement('div'); + messageContent.classList.add('message-content'); + + // Render the markdown content inside the message content container + const renderedContent = md.render(content); + messageContent.innerHTML = renderedContent; + + // Find any code blocks in the rendered content and add a class to style them + const codeBlocks = messageContent.querySelectorAll('pre > code'); + codeBlocks.forEach(block => { + block.classList.add('code-block'); + }); + initClipboard(codeBlocks); + + messageItem.appendChild(senderIcon); + messageItem.appendChild(messageContent); + + // Create an action icon element (checkmark) + if (role === 'user') { + const editButton = document.createElement('button'); + editButton.classList.add('edit-button'); + editButton.innerHTML = ''; + messageItem.appendChild(editButton); + + // Add a click listener to the edit button + editButton.addEventListener('click', () => { + // Hide the edit button + editButton.style.display = 'none'; + + // Create a new text area element with the same size as the message content + const textArea = document.createElement('textarea'); + textArea.classList.add('edit-textarea'); + textArea.style.width = `${messageContent.offsetWidth}px`; + textArea.style.height = `${messageContent.offsetHeight}px`; + textArea.value = messageContent.textContent.trim(); + messageContent.replaceWith(textArea); + + // Create a save button element and add it after the text area + const saveButton = document.createElement('button'); + saveButton.classList.add('save-button'); + saveButton.innerText = 'Save'; + textArea.parentNode.insertBefore(saveButton, textArea.nextSibling); + + // Create a cancel button element and add it before the text area + const cancelButton = document.createElement('button'); + cancelButton.classList.add('cancel-button'); + cancelButton.innerText = 'Cancel'; + textArea.parentNode.insertBefore(cancelButton, textArea.nextSibling); + + // Add an event listener for the cancel button + cancelButton.addEventListener('click', () => { + textArea.replaceWith(messageContent) + // Remove the text area, save button, and cancel button + textArea.remove(); + saveButton.remove(); + cancelButton.remove(); + + // Show the edit button + editButton.style.display = 'inline-block'; + }); + + // Add an event listener for the save button + saveButton.addEventListener('click', () => { + const newMessage = textArea.value.trim(); + if (newMessage !== '') { + textArea.replaceWith(messageContent) + // Remove the text area, save button, and cancel button + textArea.remove(); + saveButton.remove(); + cancelButton.remove(); + + // Show the edit button + editButton.style.display = 'inline-block'; + + // Process and send the new message to the extension + processMessageUI(newMessage); + } + }); + + // Focus on the text area + textArea.focus(); + }); + } else { + const actionIcon = document.createElement('i'); + actionIcon.className = 'fas fa-check-circle'; + messageItem.appendChild(actionIcon); + } + + messagesContainer.appendChild(messageItem); + + // Scroll the messages container to the bottom to display the latest message + messagesContainer.scrollTop = messagesContainer.scrollHeight; +} + +// Function to process the user's message and send it to the extension +function processMessage(message) { + // Send the message to the extension + vscode_api.postMessage({ + command: 'sendMessage', + text: message + }); +} + +function processMessageUI(message) { + addMessageToUI('user', message); + processMessage(message); +} \ No newline at end of file diff --git a/media/clipboard.js b/media/clipboard.js new file mode 100644 index 0000000..ed44356 --- /dev/null +++ b/media/clipboard.js @@ -0,0 +1,24 @@ +function initClipboard(codeBlocks) { + codeBlocks.forEach(block => { + const copyButton = document.createElement('button'); + copyButton.classList.add('copy-button'); + copyButton.innerText = 'Copy'; + block.appendChild(copyButton); + + copyButton.addEventListener('click', () => { + // Copy the message text to the clipboard + navigator.clipboard.writeText(block.textContent); + + // Change the button text temporarily to show that the text has been copied + copyButton.textContent = 'Copied!'; + + // Reset the button text after a short delay + setTimeout(() => { + copyButton.textContent = ''; + const copyIcon = document.createElement('i'); + copyIcon.classList.add('fas', 'fa-copy'); + copyButton.appendChild(copyIcon); + }, 1000); + }); + }); + } \ No newline at end of file diff --git a/media/main.js b/media/main.js new file mode 100644 index 0000000..1b34ab9 --- /dev/null +++ b/media/main.js @@ -0,0 +1,46 @@ +(function () { + // Get DOM elements for user interaction and message display + const messageInput = document.getElementById('message-input'); + const sendButton = document.getElementById('send-button'); + + // Initialize input resizing + initInputResizing(); + + // Event listener for receiving messages from the extension + window.addEventListener('message', (event) => { + const message = event.data; + switch (message.command) { + case 'receiveMessage': + // Add the received message to the chat UI as a bot message + addMessageToUI('bot', message.text); + break; + } + }); + + // Event listener for the send button + sendButton.addEventListener('click', () => { + const message = messageInput.value; + if (message) { + // Add the user's message to the chat UI + addMessageToUI('user', message); + + // Clear the input field + messageInput.value = ''; + + // Process and send the message to the extension + processMessage(message); + } + }); + + // Event listener for the Enter key in the message input field + messageInput.addEventListener('keypress', function (e) { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + const message = messageInput.value.trim(); + if (message !== '') { + sendButton.click(); + } + } + }); + })(); + \ No newline at end of file diff --git a/media/resizeInput.js b/media/resizeInput.js new file mode 100644 index 0000000..cdd36c9 --- /dev/null +++ b/media/resizeInput.js @@ -0,0 +1,26 @@ +function initInputResizing() { + // Create a handle for resizing the input container + const inputContainer = document.getElementById('input-container') + const inputResizeHandle = document.getElementById('input-resize-handle') + + // Add an event listener for mouse down on the resize handle + inputResizeHandle.addEventListener('mousedown', (e) => { + e.preventDefault(); + + const startY = e.clientY; + const startHeight = inputContainer.style.height ? parseInt(inputContainer.style.height) : parseInt(getComputedStyle(inputContainer).height); + + window.addEventListener('mousemove', resizeInput); + window.addEventListener('mouseup', stopResizeInput); + + function resizeInput(e) { + const delta = startY - e.clientY; + inputContainer.style.height = `${startHeight + delta}px`; + } + + function stopResizeInput() { + window.removeEventListener('mousemove', resizeInput); + window.removeEventListener('mouseup', stopResizeInput); + } + }); + } \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 3ff42e0..074a1a0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -37,8 +37,3 @@ function activate(context: { extensionUri: any; subscriptions: any[]; }) { context.subscriptions.push(disposable); } exports.activate = activate; - -function processMessage(message: any) { - // For an echo bot, return the same message - return message; - } \ No newline at end of file diff --git a/src/openaiClient.ts b/src/openaiClient.ts index af6f573..6662b1b 100644 --- a/src/openaiClient.ts +++ b/src/openaiClient.ts @@ -17,8 +17,6 @@ const openai = new OpenAIApi(configuration); const HttpsProxyAgent = require('https-proxy-agent') const HttpProxyAgent = require('http-proxy-agent'); -const httpAgent = new HttpProxyAgent("http://127.0.0.1:4780"); -const httpsAgent = new HttpsProxyAgent("http://127.0.0.1:4780"); export async function chatWithGPT(prompt: string, session_id: string, messageList: Array<{ role: string; content: string }>): Promise { const fullConversation = [ @@ -41,8 +39,6 @@ export async function chatWithGPT(prompt: string, session_id: string, messageLis stop: null, }, { - httpAgent, - httpsAgent } );