diff --git a/app.py b/app.py index 362759fc..785af307 100644 --- a/app.py +++ b/app.py @@ -328,7 +328,7 @@ GPT4All:Welcome! I'm here to assist you with anything you need. What can I do fo self.chatbot_bindings.generate( self.current_message, new_text_callback=self.new_text_callback,#_with_yield, - n_predict=len(self.current_message)+args.n_predict, + n_predict=len(self.current_message)+self.args.n_predict, temp=self.args.temp, top_k=self.args.top_k, top_p=self.args.top_p, @@ -458,7 +458,18 @@ GPT4All:Welcome! I'm here to assist you with anything you need. What can I do fo def update_model_params(self): data = request.get_json() - self.args.temp = data["temp"] + self.args.temp = float(data["temp"]) + self.args.top_k = float(data["top_k"]) + self.args.top_p = float(data["top_p"]) + self.args.repeat_penalty = float(data["repeat_penalty"]) + self.args.repeat_last_n = float(data["repeat_last_n"]) + + print("Parameters changed to:") + print(f"\tTemperature:{self.args.temp}") + print(f"\top_k:{self.args.top_k}") + print(f"\top_p:{self.args.top_p}") + print(f"\repeat_penalty:{self.args.repeat_penalty}") + print(f"\repeat_last_n:{self.args.repeat_last_n}") return jsonify({"status":"ok"}) diff --git a/static/js/chat.js b/static/js/chat.js index 23c7f836..e378a6b9 100644 --- a/static/js/chat.js +++ b/static/js/chat.js @@ -162,257 +162,6 @@ function addMessage(sender, message, id, can_edit=false) { -const exportButton = document.getElementById('export-button'); - -exportButton.addEventListener('click', () => { - const messages = Array.from(chatWindow.querySelectorAll('.message')).map(messageElement => { - const senderElement = messageElement.querySelector('.sender'); - const messageTextElement= messageElement.querySelector('.message-text'); - const sender = senderElement.textContent; - const messageText = messageTextElement.textContent; - return { sender, messageText }; - }); - const exportFormat = 'json'; // replace with desired export format - - if (exportFormat === 'text') { - const exportText = messages.map(({ sender, messageText }) => `${sender}: ${messageText}`).join('\n'); - downloadTextFile(exportText); - } else if (exportFormat === 'json') { - fetch('/export') - .then(response => response.json()) - .then(data => { - db_data = JSON.stringify(data) - // Do something with the data, such as displaying it on the page - console.log(db_data); - downloadJsonFile(db_data); - }) - .catch(error => { - // Handle any errors that occur - console.error(error); - }); - } else { - console.error(`Unsupported export format: ${exportFormat}`); - } -}); - -function downloadTextFile(text) { -const blob = new Blob([text], { type: 'text/plain' }); -const url = URL.createObjectURL(blob); -downloadUrl(url); -} - -function downloadJsonFile(json) { -const blob = new Blob([json], { type: 'application/json' }); -const url = URL.createObjectURL(blob); -downloadUrl(url); -} - -function downloadUrl(url) { -const link = document.createElement('a'); -link.href = url; -link.download = 'chat.txt'; -link.click(); -} - - - -const newDiscussionBtn = document.querySelector('#new-discussion-btn'); - -newDiscussionBtn.addEventListener('click', () => { - const discussionName = prompt('Enter a name for the new discussion:'); - if (discussionName) { - const sendbtn = document.querySelector("#submit-input") - const waitAnimation = document.querySelector("#wait-animation") - sendbtn.style.display="none"; - waitAnimation.style.display="block"; - - // Add the discussion to the discussion list - const discussionItem = document.createElement('li'); - discussionItem.textContent = discussionName; - fetch(`/new_discussion?title=${discussionName}`) - .then(response => response.json()) - .then(data => { - console.log(`New chat ${data}`) - // Select the new discussion - //selectDiscussion(discussionId); - chatWindow.innerHTML="" - addMessage("GPT4ALL", welcome_message,0); - populate_discussions_list() - sendbtn.style.display="block"; - waitAnimation.style.display="none"; - }) - .catch(error => { - // Handle any errors that occur - console.error(error); - }); - - - } -}); - -function populate_discussions_list() -{ - // Populate discussions list - const discussionsList = document.querySelector('#discussions-list'); - discussionsList.innerHTML = ""; - fetch('/discussions') - .then(response => response.json()) - .then(discussions => { - discussions.forEach(discussion => { - const buttonWrapper = document.createElement('div'); - //buttonWrapper.classList.add('flex', 'space-x-2', 'mt-2'); - buttonWrapper.classList.add('flex', 'items-center', 'mt-2', 'py-4', 'text-left'); - - const renameButton = document.createElement('button'); - renameButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded', 'mr-2'); - const renameImg = document.createElement('img'); - renameImg.src = "/static/images/edit_discussion.png"; - renameImg.style.width='20px' - renameImg.style.height='20px' - renameButton.appendChild(renameImg); - - //renameButton.style.backgroundImage = "/rename_discussion.svg"; //.textContent = 'Rename'; - renameButton.addEventListener('click', () => { - const dialog = document.createElement('dialog'); - dialog.classList.add('bg-white', 'rounded', 'p-4'); - - const inputLabel = document.createElement('label'); - inputLabel.textContent = 'New name: '; - const inputField = document.createElement('input'); - inputField.classList.add('border', 'border-gray-400', 'rounded', 'py-1', 'px-2'); - inputField.setAttribute('type', 'text'); - inputField.setAttribute('name', 'title'); - inputField.setAttribute('value', discussion.title); - inputLabel.appendChild(inputField); - dialog.appendChild(inputLabel); - - const cancelButton = document.createElement('button'); - cancelButton.textContent = 'Cancel'; - cancelButton.addEventListener('click', () => { - dialog.close(); - }); - - const renameConfirmButton = document.createElement('button'); - renameConfirmButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-2', 'px-4', 'rounded', 'ml-2'); - renameConfirmButton.textContent = 'Rename'; - renameConfirmButton.addEventListener('click', () => { - const newTitle = inputField.value; - if (newTitle === '') { - alert('New name cannot be empty'); - } else { - fetch('/rename', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ id: discussion.id, title: newTitle }) - }) - .then(response => { - if (response.ok) { - discussion.title = newTitle; - discussionButton.textContent = newTitle; - dialog.close(); - } else { - alert('Failed to rename discussion'); - } - }) - .catch(error => { - console.error('Failed to rename discussion:', error); - alert('Failed to rename discussion'); - }); - } - }); - - dialog.appendChild(cancelButton); - dialog.appendChild(renameConfirmButton); - document.body.appendChild(dialog); - dialog.showModal(); - }); - const deleteButton = document.createElement('button'); - deleteButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded', 'ml-2'); - const deleteImg = document.createElement('img'); - deleteImg.src = "/static/images/delete_discussion.png"; - deleteImg.style.width='20px' - deleteImg.style.height='20px' - - deleteButton.addEventListener('click', () => { - fetch('/delete_discussion', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ id: discussion.id}) - }) - .then(response => { - if (response.ok) { - buttonWrapper.remove(); - } else { - alert('Failed to delete discussion'); - } - }) - .catch(error => { - console.error('Failed to delete discussion:', error); - alert('Failed to delete discussion'); - }); - - }); - - deleteButton.appendChild(deleteImg); - deleteButton.addEventListener('click', () => { - - }); - - const discussionButton = document.createElement('button'); - discussionButton.classList.add('flex-grow', 'w-full', 'bg-blue-500', 'hover:bg-blue-700', 'text-white', 'font-bold', 'py-2', 'px-4', 'rounded', 'text-left', 'hover:text-white'); - discussionButton.textContent = discussion.title; - discussionButton.addEventListener('click', () => { - // send query with discussion id to reveal discussion messages - fetch('/get_messages', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ id: discussion.id }) - }) - .then(response => { - if (response.ok) { - response.text().then(data => { - const messages = JSON.parse(data); - console.log(messages) - // process messages - var container = document.getElementById('chat-window'); - container.innerHTML = ''; - messages.forEach(message => { - addMessage(message.sender, message.content, message.id, true); - }); - }); - } else { - alert('Failed to query the discussion'); - } - }) - .catch(error => { - console.error('Failed to get messages:', error); - alert('Failed to get messages'); - }); - console.log(`Showing messages for discussion ${discussion.id}`); - }); - - - buttonWrapper.appendChild(renameButton); - buttonWrapper.appendChild(deleteButton); - buttonWrapper.appendChild(discussionButton); - discussionsList.appendChild(buttonWrapper); - }); - }) - .catch(error => { - console.error('Failed to get discussions:', error); - alert('Failed to get discussions'); - }); -} - -// First time we populate the discussions list -populate_discussions_list() - @@ -541,49 +290,3 @@ function uncollapse(id){ content.classList.toggle('active'); } - -// submitting the model - -// Add event listener to form submit button - -const submitButton = document.getElementById('submit-model-params'); -submitButton.addEventListener('click', (event) => { - // Prevent default form submission - event.preventDefault(); - - modelInput = document.getElementById('model'); - seedInput = document.getElementById('seed'); - tempInput = document.getElementById('temp'); - nPredictInput = document.getElementById('n-predict'); - topKInput = document.getElementById('top-k'); - topPInput = document.getElementById('top-p'); - repeatPenaltyInput = document.getElementById('repeat-penalty'); - repeatLastNInput = document.getElementById('repeat-last-n'); - // Get form values and put them in an object - const formValues = { - model: modelInput.value, - seed: seedInput.value, - temp: tempInput.value, - nPredict: nPredictInput.value, - topK: topKInput.value, - topP: topPInput.value, - repeatPenalty: repeatPenaltyInput.value, - repeatLastN: repeatLastNInput.value - }; - - // Use fetch to send form values to Flask endpoint - fetch('/update_model_params', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(formValues), - }) - .then((response) => response.json()) - .then((data) => { - console.log(data); - }) - .catch((error) => { - console.error('Error:', error); - }); -}); \ No newline at end of file diff --git a/static/js/db_export.js b/static/js/db_export.js new file mode 100644 index 00000000..d4f92fc0 --- /dev/null +++ b/static/js/db_export.js @@ -0,0 +1,52 @@ + +const exportButton = document.getElementById('export-button'); + +exportButton.addEventListener('click', () => { + const messages = Array.from(chatWindow.querySelectorAll('.message')).map(messageElement => { + const senderElement = messageElement.querySelector('.sender'); + const messageTextElement= messageElement.querySelector('.message-text'); + const sender = senderElement.textContent; + const messageText = messageTextElement.textContent; + return { sender, messageText }; + }); + const exportFormat = 'json'; // replace with desired export format + + if (exportFormat === 'text') { + const exportText = messages.map(({ sender, messageText }) => `${sender}: ${messageText}`).join('\n'); + downloadTextFile(exportText); + } else if (exportFormat === 'json') { + fetch('/export') + .then(response => response.json()) + .then(data => { + db_data = JSON.stringify(data) + // Do something with the data, such as displaying it on the page + console.log(db_data); + downloadJsonFile(db_data); + }) + .catch(error => { + // Handle any errors that occur + console.error(error); + }); + } else { + console.error(`Unsupported export format: ${exportFormat}`); + } +}); + +function downloadTextFile(text) { +const blob = new Blob([text], { type: 'text/plain' }); +const url = URL.createObjectURL(blob); +downloadUrl(url); +} + +function downloadJsonFile(json) { +const blob = new Blob([json], { type: 'application/json' }); +const url = URL.createObjectURL(blob); +downloadUrl(url); +} + +function downloadUrl(url) { +const link = document.createElement('a'); +link.href = url; +link.download = 'chat.txt'; +link.click(); +} diff --git a/static/js/discussions.js b/static/js/discussions.js new file mode 100644 index 00000000..08b6d358 --- /dev/null +++ b/static/js/discussions.js @@ -0,0 +1,199 @@ + +function populate_discussions_list() +{ + // Populate discussions list + const discussionsList = document.querySelector('#discussions-list'); + discussionsList.innerHTML = ""; + fetch('/discussions') + .then(response => response.json()) + .then(discussions => { + discussions.forEach(discussion => { + const buttonWrapper = document.createElement('div'); + //buttonWrapper.classList.add('flex', 'space-x-2', 'mt-2'); + buttonWrapper.classList.add('flex', 'items-center', 'mt-2', 'py-4', 'text-left'); + + const renameButton = document.createElement('button'); + renameButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded', 'mr-2'); + const renameImg = document.createElement('img'); + renameImg.src = "/static/images/edit_discussion.png"; + renameImg.style.width='20px' + renameImg.style.height='20px' + renameButton.appendChild(renameImg); + + //renameButton.style.backgroundImage = "/rename_discussion.svg"; //.textContent = 'Rename'; + renameButton.addEventListener('click', () => { + const dialog = document.createElement('dialog'); + dialog.classList.add('bg-white', 'rounded', 'p-4'); + + const inputLabel = document.createElement('label'); + inputLabel.textContent = 'New name: '; + const inputField = document.createElement('input'); + inputField.classList.add('border', 'border-gray-400', 'rounded', 'py-1', 'px-2'); + inputField.setAttribute('type', 'text'); + inputField.setAttribute('name', 'title'); + inputField.setAttribute('value', discussion.title); + inputLabel.appendChild(inputField); + dialog.appendChild(inputLabel); + + const cancelButton = document.createElement('button'); + cancelButton.textContent = 'Cancel'; + cancelButton.addEventListener('click', () => { + dialog.close(); + }); + + const renameConfirmButton = document.createElement('button'); + renameConfirmButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-2', 'px-4', 'rounded', 'ml-2'); + renameConfirmButton.textContent = 'Rename'; + renameConfirmButton.addEventListener('click', () => { + const newTitle = inputField.value; + if (newTitle === '') { + alert('New name cannot be empty'); + } else { + fetch('/rename', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ id: discussion.id, title: newTitle }) + }) + .then(response => { + if (response.ok) { + discussion.title = newTitle; + discussionButton.textContent = newTitle; + dialog.close(); + } else { + alert('Failed to rename discussion'); + } + }) + .catch(error => { + console.error('Failed to rename discussion:', error); + alert('Failed to rename discussion'); + }); + } + }); + + dialog.appendChild(cancelButton); + dialog.appendChild(renameConfirmButton); + document.body.appendChild(dialog); + dialog.showModal(); + }); + const deleteButton = document.createElement('button'); + deleteButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded', 'ml-2'); + const deleteImg = document.createElement('img'); + deleteImg.src = "/static/images/delete_discussion.png"; + deleteImg.style.width='20px' + deleteImg.style.height='20px' + + deleteButton.addEventListener('click', () => { + fetch('/delete_discussion', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ id: discussion.id}) + }) + .then(response => { + if (response.ok) { + buttonWrapper.remove(); + } else { + alert('Failed to delete discussion'); + } + }) + .catch(error => { + console.error('Failed to delete discussion:', error); + alert('Failed to delete discussion'); + }); + + }); + + deleteButton.appendChild(deleteImg); + deleteButton.addEventListener('click', () => { + + }); + + const discussionButton = document.createElement('button'); + discussionButton.classList.add('flex-grow', 'w-full', 'bg-blue-500', 'hover:bg-blue-700', 'text-white', 'font-bold', 'py-2', 'px-4', 'rounded', 'text-left', 'hover:text-white'); + discussionButton.textContent = discussion.title; + discussionButton.addEventListener('click', () => { + // send query with discussion id to reveal discussion messages + fetch('/get_messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ id: discussion.id }) + }) + .then(response => { + if (response.ok) { + response.text().then(data => { + const messages = JSON.parse(data); + console.log(messages) + // process messages + var container = document.getElementById('chat-window'); + container.innerHTML = ''; + messages.forEach(message => { + addMessage(message.sender, message.content, message.id, true); + }); + }); + } else { + alert('Failed to query the discussion'); + } + }) + .catch(error => { + console.error('Failed to get messages:', error); + alert('Failed to get messages'); + }); + console.log(`Showing messages for discussion ${discussion.id}`); + }); + + + buttonWrapper.appendChild(renameButton); + buttonWrapper.appendChild(deleteButton); + buttonWrapper.appendChild(discussionButton); + discussionsList.appendChild(buttonWrapper); + }); + }) + .catch(error => { + console.error('Failed to get discussions:', error); + alert('Failed to get discussions'); + }); +} + +// First time we populate the discussions list +populate_discussions_list() + + + +const newDiscussionBtn = document.querySelector('#new-discussion-btn'); + +newDiscussionBtn.addEventListener('click', () => { + const discussionName = prompt('Enter a name for the new discussion:'); + if (discussionName) { + const sendbtn = document.querySelector("#submit-input") + const waitAnimation = document.querySelector("#wait-animation") + sendbtn.style.display="none"; + waitAnimation.style.display="block"; + + // Add the discussion to the discussion list + const discussionItem = document.createElement('li'); + discussionItem.textContent = discussionName; + fetch(`/new_discussion?title=${discussionName}`) + .then(response => response.json()) + .then(data => { + console.log(`New chat ${data}`) + // Select the new discussion + //selectDiscussion(discussionId); + chatWindow.innerHTML="" + addMessage("GPT4ALL", welcome_message,0); + populate_discussions_list() + sendbtn.style.display="block"; + waitAnimation.style.display="none"; + }) + .catch(error => { + // Handle any errors that occur + console.error(error); + }); + + + } +}); diff --git a/static/js/settings.js b/static/js/settings.js new file mode 100644 index 00000000..4fd39805 --- /dev/null +++ b/static/js/settings.js @@ -0,0 +1,42 @@ + +const submitButton = document.getElementById('submit-model-params'); +submitButton.addEventListener('click', (event) => { + // Prevent default form submission + event.preventDefault(); + + modelInput = document.getElementById('model'); + seedInput = document.getElementById('seed'); + tempInput = document.getElementById('temp'); + nPredictInput = document.getElementById('n-predict'); + topKInput = document.getElementById('top-k'); + topPInput = document.getElementById('top-p'); + repeatPenaltyInput = document.getElementById('repeat-penalty'); + repeatLastNInput = document.getElementById('repeat-last-n'); + // Get form values and put them in an object + const formValues = { + model: modelInput.value, + seed: seedInput.value, + temp: tempInput.value, + nPredict: nPredictInput.value, + topK: topKInput.value, + topP: topPInput.value, + repeatPenalty: repeatPenaltyInput.value, + repeatLastN: repeatLastNInput.value + }; + + // Use fetch to send form values to Flask endpoint + fetch('/update_model_params', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(formValues), + }) + .then((response) => response.json()) + .then((data) => { + console.log(data); + }) + .catch((error) => { + console.error('Error:', error); + }); +}); \ No newline at end of file diff --git a/templates/chat.html b/templates/chat.html index 1940e787..de7aedb4 100644 --- a/templates/chat.html +++ b/templates/chat.html @@ -79,5 +79,9 @@ + + + +