update chat style, and support edit history msg

This commit is contained in:
bobo.yang 2023-04-25 08:08:40 +08:00
parent 1cf84e5f71
commit f03b2574d1
9 changed files with 339 additions and 108 deletions

View File

@ -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);
}
}

View File

@ -1,21 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... meta tags, title, etc. ... -->
<!-- Meta tags for responsiveness and charset -->
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Chat Panel</title>
<!-- Font Awesome icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.0/css/all.min.css" />
<link rel="stylesheet" href="<vscode-resource:/chatPanel.css>" />
<script src="https://cdn.jsdelivr.net/npm/markdown-it/dist/markdown-it.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/themes/prism.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/prism.min.js"></script>
</head>
<body>
<div id="chat-container">
<div id="messages-container">
<!-- Chat messages will be added here dynamically -->
</div>
<div id="input-resize-handle" class="input-resize-handle"></div>
<div id="input-container">
<input id="message-input" type="text" placeholder="Type your message..." />
<textarea id="message-input" placeholder="Type your message..."></textarea>
<button id="send-button">Send</button>
</div>
</div>
<script src="<vscode-resource:/chatPanel.js>"></script>
<!-- Load the chatPanel.js file -->
<script src="<vscode-resource:/chatUI.js>"></script>
<script src="<vscode-resource:/resizeInput.js>"></script>
<script src="<vscode-resource:/clipboard.js>"></script>
<script src="<vscode-resource:/main.js>"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
Prism.highlightAll();
});
</script>
</body>
</html>

View File

@ -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();
}
});
})();

124
media/chatUI.js Normal file
View File

@ -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 = '<i class="fas fa-edit"></i>';
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);
}

24
media/clipboard.js Normal file
View File

@ -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);
});
});
}

46
media/main.js Normal file
View File

@ -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();
}
}
});
})();

26
media/resizeInput.js Normal file
View File

@ -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);
}
});
}

View File

@ -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;
}

View File

@ -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<any[]> {
const fullConversation = [
@ -41,8 +39,6 @@ export async function chatWithGPT(prompt: string, session_id: string, messageLis
stop: null,
},
{
httpAgent,
httpsAgent
}
);