Enhanced UI

This commit is contained in:
Saifeddine ALOUI 2023-04-13 12:31:48 +02:00
parent 20a2d4617e
commit 645a67a6d3
13 changed files with 608 additions and 467 deletions

25
app.py
View File

@ -87,6 +87,10 @@ class Gpt4AllWebUI:
self.add_endpoint(
"/message_rank_down", "message_rank_down", self.message_rank_down, methods=["GET"]
)
self.add_endpoint(
"/delete_message", "delete_message", self.delete_message, methods=["GET"]
)
self.add_endpoint(
"/update_model_params", "update_model_params", self.update_model_params, methods=["POST"]
@ -103,6 +107,13 @@ class Gpt4AllWebUI:
self.add_endpoint(
"/training", "training", self.training, methods=["GET"]
)
self.add_endpoint(
"/main", "main", self.main, methods=["GET"]
)
self.add_endpoint(
"/settings", "settings", self.settings, methods=["GET"]
)
self.add_endpoint(
"/help", "help", self.help, methods=["GET"]
@ -358,6 +369,12 @@ GPT4All:Welcome! I'm here to assist you with anything you need. What can I do fo
new_rank = self.current_discussion.message_rank_down(discussion_id)
return jsonify({"new_rank": new_rank})
def delete_message(self):
discussion_id = request.args.get("id")
new_rank = self.current_discussion.delete_message(discussion_id)
return jsonify({"new_rank": new_rank})
def new_discussion(self):
title = request.args.get("title")
self.current_discussion = self.db.create_discussion(title)
@ -402,6 +419,12 @@ GPT4All:Welcome! I'm here to assist you with anything you need. What can I do fo
def get_config(self):
return jsonify(self.config)
def main(self):
return render_template("main.html")
def settings(self):
return render_template("settings.html")
def help(self):
return render_template("help.html")
@ -459,7 +482,7 @@ if __name__ == "__main__":
help="launch Flask server in debug mode",
)
parser.add_argument(
"--host", type=str, default="localhost", help="the hostname to listen on"
"--host", type=str, default=None, help="the hostname to listen on"
)
parser.add_argument("--port", type=int, default=None, help="the port to listen on")
parser.add_argument(

16
db.py
View File

@ -90,7 +90,7 @@ class DiscussionsDB:
return cursor.fetchone()
def delete(self, query):
def delete(self, query, params=None):
"""
Execute the specified SQL delete query on the database,
with optional parameters.
@ -98,7 +98,10 @@ class DiscussionsDB:
"""
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute(query)
if params is None:
cursor.execute(query)
else:
cursor.execute(query, params)
conn.commit()
def insert(self, query, params=None):
@ -276,5 +279,14 @@ class Discussion:
f"UPDATE message SET rank = ? WHERE id = ?",(new_rank,message_id)
)
return new_rank
def delete_message(self, message_id):
"""Delete the message
Args:
message_id (int): The id of the message to be deleted
"""
# Retrieve current rank value for message_id
self.discussions_db.delete("DELETE FROM message WHERE id=?", (message_id,))
# ========================================================================================================================

BIN
static/images/refresh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
static/images/thumb_up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,279 +1,236 @@
const chatWindow = document.getElementById('chat-window');
const chatForm = document.getElementById('chat-form');
const userInput = document.getElementById('user-input');
chatForm.addEventListener('submit', event => {
event.preventDefault();
// get user input and clear input field
message = userInput.value;
userInput.value = '';
// add user message to chat window
const sendbtn = document.querySelector("#submit-input")
const waitAnimation = document.querySelector("#wait-animation")
sendbtn.style.display="none";
waitAnimation.style.display="block";
fetch('/bot', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message })
}).then(function(response) {
const stream = new ReadableStream({
start(controller) {
const reader = response.body.getReader();
function push() {
reader.read().then(function(result) {
if (result.done) {
sendbtn.style.display="block";
waitAnimation.style.display="none";
controller.close();
return;
}
controller.enqueue(result.value);
push();
})
}
push();
}
});
const textDecoder = new TextDecoder();
const readableStreamDefaultReader = stream.getReader();
let entry_counter = 0
function readStream() {
readableStreamDefaultReader.read().then(function(result) {
if (result.done) {
return;
}
text = textDecoder.decode(result.value);
// The server will first send a json containing information about the message just sent
if(entry_counter==0)
{
// We parse it and
infos = JSON.parse(text)
addMessage('User', infos.message, infos.id, 0, can_edit=true);
elements = addMessage('GPT4ALL', '', infos.response_id, 0, can_edit=true);
messageTextElement=elements['messageTextElement'];
hiddenElement=elements['hiddenElement'];
entry_counter ++;
}
else{
// For the other enrtries, these are just the text of the chatbot
for (const char of text) {
txt = hiddenElement.innerHTML;
if (char != '\f') {
txt += char
hiddenElement.innerHTML = txt
messageTextElement.innerHTML = txt.replace(/\n/g, "<br>")
}
// scroll to bottom of chat window
chatWindow.scrollTop = chatWindow.scrollHeight;
}
entry_counter ++;
}
readStream();
});
}
readStream();
});
});
function addMessage(sender, message, id, rank=0, can_edit=false) {
console.log(id)
const messageElement = document.createElement('div');
messageElement.classList.add('bg-secondary', 'drop-shadow-sm', 'p-4', 'mx-6', 'my-4', 'flex', 'flex-col', 'space-x-2', 'rounded-lg', 'shadow-lg', 'bg-gray-800', 'hover:bg-gray-700', 'transition-colors', 'duration-300');
const chatWindow = document.getElementById('chat-window');
const chatForm = document.getElementById('chat-form');
const userInput = document.getElementById('user-input');
//messageElement.classList.add(sender);
messageElement.setAttribute('id', id);
const senderElement = document.createElement('div');
senderElement.classList.add('font-normal', 'underline', 'text-sm');
senderElement.innerHTML = sender;
const messageTextElement = document.createElement('div');
messageTextElement.classList.add('font-medium', 'text-md');
messageTextElement.innerText = message;
// Create a hidden div element needed to buffer responses before commiting them to the visible message
const hiddenElement = document.createElement('div');
hiddenElement.style.display = 'none';
hiddenElement.innerHTML = '';
messageElement.appendChild(senderElement);
messageElement.appendChild(messageTextElement);
if(can_edit)
{
// Create buttons container
const buttonsContainer = document.createElement('div');
// Add the 'flex' class to the div
buttonsContainer.classList.add('flex');
// Add the 'justify-end' class to the div
buttonsContainer.classList.add('justify-end');
// Set the width and height of the container to 100%
buttonsContainer.style.width = '100%';
buttonsContainer.style.height = '100%';
const editButton = document.createElement('button');
editButton.classList.add('my-1','mx-1','outline-none','px-4','bg-accent','text-white','rounded-md','hover:bg-[#7ba0ea]','active:bg-blue-100','transition-colors','ease-in-out');
editButton.style.float = 'right'; // set the float property to right
editButton.style.display='inline-block'
editButton.innerHTML = 'Edit';
editButton.addEventListener('click', () => {
const inputField = document.createElement('input');
inputField.type = 'text';
inputField.classList.add('font-medium', 'text-md', 'border', 'border-gray-300', 'p-1');
inputField.value = messageTextElement.innerHTML;
buttonsContainer.style.display="none"
console.log(id)
const messageElement = document.createElement('div');
messageElement.classList.add('bg-secondary', 'drop-shadow-sm', 'p-4', 'mx-6', 'my-4', 'flex', 'flex-col', 'space-x-2', 'rounded-lg', 'shadow-lg', 'bg-gray-800', 'hover:bg-gray-700', 'transition-colors', 'duration-300');
//messageElement.classList.add(sender);
messageElement.setAttribute('id', id);
const saveButton = document.createElement('button');
saveButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-2', 'px-4', 'rounded', 'my-2', 'ml-2');
saveButton.innerHTML = 'Save';
saveButton.addEventListener('click', () => {
const newText = inputField.value;
messageTextElement.innerHTML = newText;
// make request to update message
const url = `/update_message?id=${id}&message=${newText}`;
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
else{
console.log("Updated")
}
})
.catch(error => {
console.error('There was a problem updating the message:', error);
});
buttonsContainer.style.display='inline-block'
messageElement.replaceChild(messageTextElement, inputField);
//messageElement.removeChild(inputField);
messageElement.removeChild(saveButton);
});
const senderElement = document.createElement('div');
senderElement.classList.add('font-normal', 'underline', 'text-sm');
senderElement.innerHTML = sender;
const messageTextElement = document.createElement('div');
messageTextElement.classList.add('font-medium', 'text-md');
messageTextElement.innerText = message;
// Create a hidden div element needed to buffer responses before commiting them to the visible message
const hiddenElement = document.createElement('div');
hiddenElement.style.display = 'none';
hiddenElement.innerHTML = '';
messageElement.appendChild(senderElement);
messageElement.appendChild(messageTextElement);
if(can_edit)
{
// Create buttons container
const buttonsContainer = document.createElement('div');
// Add the 'flex' class to the div
buttonsContainer.classList.add('flex');
// Add the 'justify-end' class to the div
buttonsContainer.classList.add('justify-end');
// Set the width and height of the container to 100%
buttonsContainer.style.width = '100%';
buttonsContainer.style.height = '100%';
const editButton = document.createElement('button');
editButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded',"w-10","h-10");
editButton.style.float = 'right'; // set the float property to right
editButton.style.display='inline-block'
editButton.innerHTML = '';
const editImg = document.createElement('img');
editImg.src = "/static/images/edit_discussion.png";
editImg.classList.add('py-1', 'px-1', 'rounded', 'w-10', 'h-10');
editButton.appendChild(editImg)
editButton.addEventListener('click', () => {
const inputField = document.createElement('input');
inputField.type = 'text';
inputField.classList.add('font-medium', 'text-md', 'border', 'border-gray-300', 'p-1');
inputField.value = messageTextElement.innerHTML;
buttonsContainer.style.display="none"
const saveButton = document.createElement('button');
saveButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-2', 'px-4', 'rounded', 'my-2', 'ml-2');
saveButton.innerHTML = 'Save';
saveButton.addEventListener('click', () => {
const newText = inputField.value;
messageTextElement.innerHTML = newText;
// make request to update message
const url = `/update_message?id=${id}&message=${newText}`;
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
else{
console.log("Updated")
}
})
.catch(error => {
console.error('There was a problem updating the message:', error);
});
buttonsContainer.style.display='inline-block'
messageElement.replaceChild(messageTextElement, inputField);
//messageElement.removeChild(inputField);
messageElement.removeChild(saveButton);
});
messageElement.replaceChild(inputField, messageTextElement);
messageElement.appendChild(saveButton);
inputField.focus();
});
const deleteButton = document.createElement('button');
deleteButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded',"w-10","h-10");
deleteButton.style.float = 'right'; // set the float property to right
deleteButton.style.display='inline-block'
deleteButton.innerHTML = '';
const deleteImg = document.createElement('img');
deleteImg.src = "/static/images/delete_discussion.png";
deleteImg.classList.add('py-2', 'px-2', 'rounded', 'w-15', 'h-15');
deleteButton.appendChild(deleteImg)
deleteButton.addEventListener('click', () => {
const url = `/delete_message?id=${id}`;
fetch(url)
.then(response => response.json())
.then(data => {
console.log(data.new_rank)
messageElement.style.display="none"
})
.catch(error => {
console.error('There was a problem updating the message:', error);
});
});
const rank_up = document.createElement('button');
rank_up.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded',"w-10","h-10");
rank_up.style.float = 'right'; // set the float property to right
rank_up.style.display='inline-block'
rank_up.innerHTML = '';
const thumbUpImg = document.createElement('img');
thumbUpImg.src = "/static/images/thumb_up.png";
thumbUpImg.classList.add('py-2', 'px-2', 'rounded', 'w-15', 'h-15');
rank_up.appendChild(thumbUpImg)
const thumbUpBadge = document.createElement('span');
thumbUpBadge.innerText = "";
thumbUpBadge.classList.add('inline-flex', 'items-center', 'justify-center', 'h-4', 'w-4', 'rounded-full', 'bg-red-500', 'text-white', 'text-xs', 'top-0', 'right-0');
rank_up.appendChild(thumbUpBadge)
rank_up.addEventListener('click', () => {
const url = `/message_rank_up?id=${id}`;
fetch(url)
.then(response => response.json())
.then(data => {
console.log(data.new_rank)
if(data.new_rank>0){
thumbUpBadge.innerText=`${data.new_rank}`
thumbDownBadge.innerText=``
thumbUpBadge.display=`block`
thumbDownBadge.display='none'
}
else if(data.new_rank<0){
thumbUpBadge.innerText=``
thumbDownBadge.innerText=`${data.new_rank}`
thumbUpBadge.display=`none`
thumbDownBadge.display='block'
}
else{
thumbUpBadge.innerText=``
thumbDownBadge.innerText=``
thumbUpBadge.display=`none`
thumbDownBadge.display='none'
}
})
.catch(error => {
console.error('There was a problem updating the message:', error);
});
});
const rank_down = document.createElement('button');
rank_down.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded',"w-10","h-10");
rank_down.style.float = 'right'; // set the float property to right
rank_down.style.display='inline-block'
rank_down.innerHTML = '';
const thumbDownImg = document.createElement('img');
thumbDownImg.src = "/static/images/thumb_down.png";
thumbDownImg.classList.add('py-2', 'px-2', 'rounded', 'w-15', 'h-15');
rank_down.appendChild(thumbDownImg)
const thumbDownBadge = document.createElement('span');
thumbDownBadge.innerText = "";
thumbDownBadge.classList.add('inline-flex', 'items-center', 'justify-center', 'h-4', 'w-4', 'rounded-full', 'bg-red-500', 'text-white', 'text-xs', 'top-0', 'right-0');
rank_down.appendChild(thumbDownBadge)
rank_down.addEventListener('click', () => {
const url = `/message_rank_down?id=${id}`;
fetch(url)
.then(response => response.json())
.then(data => {
console.log(data)
if(data.new_rank>0){
thumbUpBadge.innerText=`${data.new_rank}`
thumbDownBadge.innerText=``
thumbUpBadge.display=`block`
thumbDownBadge.display='none'
}
else if(data.new_rank<0){
thumbUpBadge.innerText=``
thumbDownBadge.innerText=`${data.new_rank}`
thumbUpBadge.display=`none`
thumbDownBadge.display='block'
}
else{
thumbUpBadge.innerText=``
thumbDownBadge.innerText=``
thumbUpBadge.display=`none`
thumbDownBadge.display='none'
}
})
.catch(error => {
console.error('There was a problem updating the message:', error);
});
});
buttonsContainer.appendChild(editButton);
buttonsContainer.appendChild(deleteButton);
buttonsContainer.appendChild(rank_up);
buttonsContainer.appendChild(rank_down);
messageElement.appendChild(buttonsContainer);
if(rank>0){
thumbUpBadge.innerText=`${rank}`
thumbDownBadge.innerText=``
thumbUpBadge.display=`block`
thumbDownBadge.display='none'
}
else if(rank<0){
thumbUpBadge.innerText=``
thumbDownBadge.innerText=`${rank}`
thumbUpBadge.display=`none`
thumbDownBadge.display='block'
}
else{
thumbUpBadge.innerText=``
thumbDownBadge.innerText=``
thumbUpBadge.display=`none`
thumbDownBadge.display='none'
}
messageElement.replaceChild(inputField, messageTextElement);
messageElement.appendChild(saveButton);
inputField.focus();
});
const rank_up = document.createElement('button');
rank_up.classList.add('my-1','mx-1','outline-none','px-4','bg-accent','text-white','rounded-md','hover:bg-[#7ba0ea]','active:bg-[#3d73e1]','transition-colors','ease-in-out');
rank_up.style.float = 'right'; // set the float property to right
rank_up.style.display='inline-block'
rank_up.innerHTML = 'Up';
rank_up.addEventListener('click', () => {
const url = `/message_rank_up?id=${id}`;
fetch(url)
.then(response => response.json())
.then(data => {
console.log(data.new_rank)
if(data.new_rank>0){
rank_up.innerText=`Up(${data.new_rank})`
rank_down.innerText=`Down`
}
else if(data.new_rank<0){
rank_up.innerText=`Up`
rank_down.innerText=`Down(${data.new_rank})`
}
else{
rank_up.innerText=`Up`
rank_down.innerText=`Down`
}
})
.catch(error => {
console.error('There was a problem updating the message:', error);
});
});
const rank_down = document.createElement('button');
rank_down.classList.add('my-1','mx-1','outline-none','px-4','bg-accent','text-white','rounded-md','hover:bg-[#7ba0ea]','active:bg-[#3d73e1]','transition-colors','ease-in-out');
rank_down.style.float = 'right'; // set the float property to right
rank_down.style.display='inline-block'
rank_down.innerHTML = 'Down';
rank_down.addEventListener('click', () => {
const url = `/message_rank_down?id=${id}`;
fetch(url)
.then(response => response.json())
.then(data => {
console.log(data)
if(data.new_rank>0){
rank_up.innerText=`Up(${data.new_rank})`
rank_down.innerText=`Down`
}
else if(data.new_rank<0){
rank_up.innerText=`Up`
rank_down.innerText=`Down(${data.new_rank})`
}
})
.catch(error => {
console.error('There was a problem updating the message:', error);
});
});
buttonsContainer.appendChild(editButton);
buttonsContainer.appendChild(rank_up);
buttonsContainer.appendChild(rank_down);
messageElement.appendChild(buttonsContainer);
if(rank>0){
rank_up.innerText=`Up(${rank})`
rank_down.innerText=`Down`
}
else if(rank<0){
rank_up.innerText=`Up`
rank_down.innerText=`Down(${rank})`
chatWindow.appendChild(messageElement);
chatWindow.appendChild(hiddenElement);
// scroll to bottom of chat window
chatWindow.scrollTop = chatWindow.scrollHeight;
// Return all needed stuff
return {
'messageTextElement':messageTextElement,
'hiddenElement':hiddenElement
}
}
chatWindow.appendChild(messageElement);
chatWindow.appendChild(hiddenElement);
// scroll to bottom of chat window
chatWindow.scrollTop = chatWindow.scrollHeight;
// Return all needed stuff
return {'messageTextElement':messageTextElement, 'hiddenElement':hiddenElement}
}
const welcome_message = `
This is a very early testing Web UI of GPT4All chatbot.
Keep in mind that this is a 7B parameters model running on your own PC's CPU. It is literally 24 times smaller than GPT-3 in terms of parameter count.
While it is still new and not as powerful as GPT-3.5 or GPT-4, it can still be useful for many applications.
Many people are building models out there and you can try the models and compare them yourself.
Any feedback and contribution is welcomed.
This Web UI is a binding to the GPT4All model that allows you to test a chatbot locally on your machine. Feel free to ask questions or give instructions.
Examples:
- A color description has been provided. Find the CSS code associated with that color. A light red color with a medium light shade of pink.
- Come up with an interesting idea for a new movie plot. Your plot should be described with a title and a summary.
- Reverse a string in python.
- List 10 dogs.
- Write me a poem about the fall of Julius Ceasar into a ceasar salad in iambic pentameter.
- What is a three word topic describing the following keywords: baseball, football, soccer.
- Act as ChefAI an AI that has the ability to create recipes for any occasion. Instruction: Give me a recipe for my next anniversary.
- who is Abraham Lincoln?.
- write a letter to my collegue and tell him I can't make it to work today. Make it humorous.
- write a poem about love between two AIs.
Welcome! I'm here to assist you with anything you need. What can I do for you today?
`;
addMessage("GPT4ALL",welcome_message,0,0,false);
// Code for collapsable text
const collapsibles = document.querySelectorAll('.collapsible');
function uncollapse(id){
console.log("uncollapsing")
const content = document.querySelector(`#${id}`);
content.classList.toggle('active');
}
}

View File

@ -13,7 +13,7 @@ function populate_discussions_list()
buttonWrapper.classList.add('flex', 'items-center', 'mt-2', 'px-2', 'py-1', 'text-left');
const renameButton = document.createElement('button');
renameButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-2', 'px-2', 'rounded', 'ml-2', 'mr-2',"w-20","h-20");
renameButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded',"w-10","h-10");
const renameImg = document.createElement('img');
renameImg.src = "/static/images/edit_discussion.png";
renameImg.classList.add('py-2', 'px-2', 'rounded', 'w-15', 'h-15');
@ -77,7 +77,7 @@ function populate_discussions_list()
dialog.showModal();
});
const deleteButton = document.createElement('button');
deleteButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'rounded', 'ml-2', 'mr-2', "w-20", "h-20");
deleteButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-0', 'px-0', 'rounded',"w-10","h-10");
const deleteImg = document.createElement('img');
deleteImg.src = "/static/images/delete_discussion.png";
deleteImg.classList.add('py-2', 'px-2', 'rounded', 'w-15', 'h-15');
@ -110,7 +110,7 @@ function populate_discussions_list()
});
const discussionButton = document.createElement('button');
discussionButton.classList.add('bg-blue-500', 'hover:bg-blue-700', 'text-white', 'font-bold', 'rounded', 'ml-2', 'w-full', 'h-20');
discussionButton.classList.add('bg-green-500', 'hover:bg-green-700', 'text-white', 'font-bold', 'py-2', 'px-4', 'rounded', 'ml-2', 'w-full');
discussionButton.textContent = discussion.title;
discussionButton.addEventListener('click', () => {
// send query with discussion id to reveal discussion messages

104
static/js/main.js Normal file
View File

@ -0,0 +1,104 @@
function update_main(){
const chatWindow = document.getElementById('chat-window');
const chatForm = document.getElementById('chat-form');
const userInput = document.getElementById('user-input');
chatForm.addEventListener('submit', event => {
event.preventDefault();
// get user input and clear input field
message = userInput.value;
userInput.value = '';
// add user message to chat window
const sendbtn = document.querySelector("#submit-input")
const waitAnimation = document.querySelector("#wait-animation")
sendbtn.style.display="none";
waitAnimation.style.display="block";
fetch('/bot', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message })
}).then(function(response) {
const stream = new ReadableStream({
start(controller) {
const reader = response.body.getReader();
function push() {
reader.read().then(function(result) {
if (result.done) {
sendbtn.style.display="block";
waitAnimation.style.display="none";
controller.close();
return;
}
controller.enqueue(result.value);
push();
})
}
push();
}
});
const textDecoder = new TextDecoder();
const readableStreamDefaultReader = stream.getReader();
let entry_counter = 0
function readStream() {
readableStreamDefaultReader.read().then(function(result) {
if (result.done) {
return;
}
text = textDecoder.decode(result.value);
// The server will first send a json containing information about the message just sent
if(entry_counter==0)
{
// We parse it and
infos = JSON.parse(text)
addMessage('User', infos.message, infos.id, 0, can_edit=true);
elements = addMessage('GPT4ALL', '', infos.response_id, 0, can_edit=true);
messageTextElement=elements['messageTextElement'];
hiddenElement=elements['hiddenElement'];
entry_counter ++;
}
else{
// For the other enrtries, these are just the text of the chatbot
for (const char of text) {
txt = hiddenElement.innerHTML;
if (char != '\f') {
txt += char
hiddenElement.innerHTML = txt
messageTextElement.innerHTML = txt.replace(/\n/g, "<br>")
}
// scroll to bottom of chat window
chatWindow.scrollTop = chatWindow.scrollHeight;
}
entry_counter ++;
}
readStream();
});
}
readStream();
});
});
const welcome_message = `
Welcome! I'm here to assist you with anything you need. What can I do for you today?
`;
addMessage("GPT4ALL",welcome_message,0,0,false);
}
fetch('/main')
.then(response => response.text())
.then(html => {
document.getElementById('main').innerHTML = html;
update_main();
})
.catch(error => {
console.error('Error loading main page:', error);
});

View File

@ -1,3 +1,121 @@
fetch('/settings')
.then(response => response.text())
.then(html => {
document.getElementById('settings').innerHTML = html;
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');
temperatureValue = document.getElementById('temperature-value');
n_predictValue = document.getElementById('n-predict-value');
topkValue = document.getElementById('top-k-value');
toppValue = document.getElementById('top-p-value');
repeatPenaltyValue = document.getElementById('repeat-penalty-value');
repeatLastNValue = document.getElementById('repeat-last-n');
tempInput.addEventListener('input',() => {
temperatureValue.textContent =`Temperature(${tempInput.value})`
})
nPredictInput.addEventListener('input',() => {
n_predictValue.textContent =`N Predict(${nPredictInput.value})`
})
topKInput.addEventListener('input',() => {
topkValue.textContent =`Top-K(${topKInput.value})`
})
topPInput.addEventListener('input',() => {
toppValue.textContent =`Top-P(${topPInput.value})`
})
repeatPenaltyInput.addEventListener('input',() => {
repeatPenaltyValue.textContent =`Repeat penalty(${repeatPenaltyInput.value})`
})
repeatLastNInput.addEventListener('input',() => {
repeatLastNValue.textContent =`Repeat last N(${repeatLastNInput.value})`
})
fetch('/get_config')
.then((response) => response.json())
.then((data) => {
console.log(data);
modelInput.value = data["model"]
seedInput.value = data["seed"]
tempInput.value = data["temp"]
nPredictInput.value = data["n_predict"]
topKInput.value = data["top_k"]
topPInput.value = data["top_p"]
repeatPenaltyInput.textContent = data["repeat_penalty"]
repeatLastNInput.textContent = data["repeat_last_n"]
temperatureValue.textContent =`Temperature(${data["temp"]})`
n_predictValue.textContent =`N Predict(${data["n_predict"]})`
topkValue.textContent =`Top-K(${data["top_k"]})`
toppValue.textContent =`Top-P(${data["top_p"]})`
repeatPenaltyValue.textContent =`Repeat penalty(${data["repeat_penalty"]})`
repeatLastNValue.textContent =`Repeat last N(${data["repeat_last_n"]})`
})
.catch((error) => {
console.error('Error:', error);
});
const submitButton = document.getElementById('submit-model-params');
submitButton.addEventListener('click', (event) => {
// Prevent default form submission
event.preventDefault();
// 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
};
console.log(formValues);
// 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);
});
});
})
.catch(error => {
console.error('Error loading settings page:', error);
});
function populate_models(){
// Get a reference to the <select> element
const selectElement = document.getElementById('model');
@ -30,107 +148,3 @@ function populate_models(){
populate_models()
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');
temperatureValue = document.getElementById('temperature-value');
n_predictValue = document.getElementById('n-predict-value');
topkValue = document.getElementById('top-k-value');
toppValue = document.getElementById('top-p-value');
repeatPenaltyValue = document.getElementById('repeat-penalty-value');
repeatLastNValue = document.getElementById('repeat-last-n');
tempInput.addEventListener('input',() => {
temperatureValue.textContent =`Temperature(${tempInput.value})`
})
nPredictInput.addEventListener('input',() => {
n_predictValue.textContent =`N Predict(${nPredictInput.value})`
})
topKInput.addEventListener('input',() => {
topkValue.textContent =`Top-K(${topKInput.value})`
})
topPInput.addEventListener('input',() => {
toppValue.textContent =`Top-P(${topPInput.value})`
})
repeatPenaltyInput.addEventListener('input',() => {
repeatPenaltyValue.textContent =`Repeat penalty(${repeatPenaltyInput.value})`
})
repeatLastNInput.addEventListener('input',() => {
repeatLastNValue.textContent =`Repeat last N(${repeatLastNInput.value})`
})
fetch('/get_config')
.then((response) => response.json())
.then((data) => {
console.log(data);
modelInput.value = data["model"]
seedInput.value = data["seed"]
tempInput.value = data["temp"]
nPredictInput.value = data["n_predict"]
topKInput.value = data["top_k"]
topPInput.value = data["top_p"]
repeatPenaltyInput.textContent = data["repeat_penalty"]
repeatLastNInput.textContent = data["repeat_last_n"]
temperatureValue.textContent =`Temperature(${data["temp"]})`
n_predictValue.textContent =`N Predict(${data["n_predict"]})`
topKValue.textContent =`Top-K(${data["top_k"]})`
topPValue.textContent =`Top-P(${data["top_p"]})`
repeatPenaltyValue.textContent =`Repeat penalty(${data["repeat_penalty"]})`
repeatLastNValue.textContent =`Repeat last N(${data["repeat_last_n"]})`
})
.catch((error) => {
console.error('Error:', error);
});
const submitButton = document.getElementById('submit-model-params');
submitButton.addEventListener('click', (event) => {
// Prevent default form submission
event.preventDefault();
// 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
};
console.log(formValues);
// 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);
});
});

View File

@ -16,99 +16,25 @@
<div class="border-b border-gray-800 content-center items-center">
<ul class="flex border-b border-gray-800 content-center items-center">
<li class="mr-1">
<a href="#main" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:text-gray-100">Main</a>
<a href="#main" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:bg-gray-200 hover:text-black" id="main-link">Main</a>
</li>
<li class="mr-1">
<a href="#settings" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:text-gray-100">Settings</a>
<a href="#settings" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:bg-gray-200 hover:text-black" id="settings-link">Settings</a>
</li>
<li class="mr-1">
<a href="#extensions" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:text-gray-100" id="extensions-link">Extensions</a>
<a href="#extensions" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:bg-gray-200 hover:text-black" id="extensions-link">Extensions</a>
</li>
<li class="mr-1">
<a href="#training" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:text-gray-100" id="training-link">Training</a>
<a href="#training" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:bg-gray-200 hover:text-black" id="training-link">Training</a>
</li>
<li class="mr-1">
<a href="#help" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:text-gray-100" id="help-link">Help</a>
<a href="#help" class="bg-gray-700 text-gray-200 py-2 px-4 rounded-t-md font-medium hover:bg-gray-200 hover:text-black" id="help-link">Help</a>
</li>
</ul>
</div>
<div id="main" class="tab-pane bg-gray-800 h-full">
<div class="grid grid-cols-5 gap-4 h-full">
<div class="col-span-1 bg-gray-900 h-full">
<div>
<h1 class="font-bold font-large">Discussions</h1>
</div>
<div id="discussions-list" class="overflow-y-auto h-96">
</div>
</div>
<div class="col-span-4 bg-gray-900 h-full">
<div class="text-white">
<h1 class="font-bold font-large">Chat box</h1>
</div>
<div id="chat-window" class="overflow-y-auto h-96">
</div>
</div>
</div>
<div id="action-buttons" class="bg-gray-800 px-4 py-4">
<button id="new-discussion-btn" class="px-4 py-4 rounded hover:bg-gray-600 ">
<img src="/static/images/new_message.png" class="w-10 h-10">
</button>
<button value="Export" id="export-button" class="px-4 py-4 rounded hover:bg-gray-600">
<img src="/static/images/export_database.png" class="w-10 h-10">
</button>
<button value="Export-discussion" id="export-discussion-button" class="px-4 py-4 rounded hover:bg-gray-600">
<img src="/static/images/export_discussion.png" class="w-10 h-10">
</button>
</div>
<form id="chat-form" class="flex w-full mt-auto">
<input type="text" id="user-input" placeholder="Type your message..." class="bg-secondary my-1 mx-1 outline-none drop-shadow-sm w-full rounded-md p-2">
<input type="submit" value="Send" id="submit-input" class="my-1 mx-1 outline-none px-4 bg-accent text-black rounded-md hover:bg-[#7ba0ea] active:bg-[#3d73e1] transition-colors ease-in-out">
<div id="wait-animation" style="display: none;" class="lds-facebook bg-secondary my-1 mx-1 outline-none drop-shadow-sm w-full rounded-md p-2"><div></div><div></div><div></div></div>
</form>
<div id="main" class="tab-pane overflow-hidden flex flex-row w-full h-full relative flex">
</div>
<div class="tab-pane" id="settings" style="display: none;">
<div class="h-full overflow-y-auto">
<form id="model-params-form" class="bg-gray-700 shadow-md rounded px-8 py-8 pt-6 pb-8 mb-4 text-white">
<div class="mb-4">
<label class="block font-bold mb-2" for="model">Model</label>
<select class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" id="model" name="model" value="gpt4all-lora-quantized.bin">
</select>
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="seed">Seed</label>
<input class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" id="seed" type="text" name="seed" value="0">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="temp" id="temperature-value">Temperature (0.1)</label>
<input class="w-full slider-value" id="temp" type="range" min="0" max="1" step="0.1" value="0.1" name="temp">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="n-predict" id="n-predict-value">N Predict (256)</label>
<input class="w-full slider-value" id="n-predict" type="range" min="0" max="2048" step="1" value="256" name="n-predict">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="top-k" id="top-k-value">Top K</label>
<input class="w-full slider-value" id="top-k" type="range" min="0" max="100" step="1" value="40" name="top-k">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="top-p" id="top-p-value">Top P</label>
<input class="w-full slider-value" id="top-p" type="range" min="0" max="100" step="1" value="40" name="top-p">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="repeat-penalty" id="repeat-penalty-value">Repeat penalty</label>
<input class="w-full slider-value" id="repeat-penalty" type="range" min="0" max="2" step="0.1" value="1.3" name="repeat-penalty">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="repeat-last-n" id="repeat-last-n-value">Repeat last N</label>
<input class="w-full slider-value" id="repeat-last-n" type="range" min="0" max="100" step="1" value="40" name="repeat-last-n">
</div>
<div class="mb-4">
<button type="submit" id="submit-model-params" class="my-1 mx-1 outline-none px-4 bg-accent rounded-md bg-gray-500 hover:bg-gray-300 transition-colors ease-in-out">Update parameters</button>
</div>
</form>
</div>
</div>
<div class="tab-pane" id="extensions" style="display: none;">
</div>
@ -119,15 +45,17 @@
</div>
<footer class="border-t border-accent flex">
</footer>
<script src="{{ url_for('static', filename='js/marked.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/chat.js') }}"></script>
<script src="{{ url_for('static', filename='js/marked.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
<script src="{{ url_for('static', filename='js/extensions.js') }}"></script>
<script src="{{ url_for('static', filename='js/training.js') }}"></script>
<script src="{{ url_for('static', filename='js/help.js') }}"></script>
<script src="{{ url_for('static', filename='js/discussions.js') }}"></script>
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
<script src="{{ url_for('static', filename='js/db_export.js') }}"></script>
<script src="{{ url_for('static', filename='js/tabs.js') }}"></script>
<script src="{{ url_for('static', filename='js/help.js') }}"></script>
<script src="{{ url_for('static', filename='js/extensions.js') }}"></script>
<script src="{{ url_for('static', filename='js/training.js') }}"></script>
</body>
</html>

View File

@ -29,6 +29,7 @@
<li><a href="#credits" class="block px-4 py-2 text-gray-800 hover:bg-gray-100">Credits</a></li>
<li><a href="#how-to-use" class="block px-4 py-2 text-gray-800 hover:bg-gray-100">How to use</a></li>
<li><a href="#faq" class="block px-4 py-2 text-gray-800 hover:bg-gray-100">FAQ</a></li>
<li><a href="#examples" class="block px-4 py-2 text-gray-800 hover:bg-gray-100">Examples</a></li>
</ul>
</div>
</nav>
@ -82,6 +83,33 @@
</div>
</dl>
</section>
<section id="examples">
<h2 class="text-2xl font-bold mb-4">Usage examples</h2>
<dl class="mb-8">
<div class="mb-4">
<dt class="font-bold">Casual discussion</dt>
<dd>Hello, my name is (put your name here).</dd>
<dt class="font-bold">Color picker for css</dt>
<dd>What is the hex code for the color pink.</dd>
<dt class="font-bold">Movie plot</dt>
<dd>Come up with an interesting idea for a new movie plot. Your plot should be described with a title and a summary.</dd>
<dt class="font-bold">Programming questions</dt>
<dd>Write a python function that reverses a string.</dd>
<dt class="font-bold">Ask about dogs</dt>
<dd>List 10 dogs.</dd>
<dt class="font-bold">Weird stuff</dt>
<dd>Write me a poem about the fall of Julius Ceasar into a ceasar salad in iambic pentameter.</dd>
<dt class="font-bold">Culinary help</dt>
<dd>Act as ChefAI an AI that has the ability to create recipes for any occasion. Instruction: Give me a recipe for my next anniversary.</dd>
<dt class="font-bold">General culture</dt>
<dd>Who is Abraham Lincoln?</dd>
<dt class="font-bold">Writing a letter</dt>
<dd>write a letter to my collegue and tell him I can't make it to work today. Make it humorous.</dd>
<dt class="font-bold">Love poem</dt>
<dd>write a poem about love between two AIs.</dd>
</div>
</dl>
</section>
</div>
</main>
</body>

35
templates/main.html Normal file
View File

@ -0,0 +1,35 @@
<div class="dark bg-gray-900 md:flex-row flex felx-row">
<div class="dark hidden bg-gray-900 md:flex md:w-[260px] flex flex-col">
<nav id="action-buttons" class="flex flex-row">
<button id="new-discussion-btn" class="px-4 py-4 rounded hover:bg-gray-600">
<img src="/static/images/new_message.png" class="w-10 h-10">
</button>
<button value="Export" id="export-button" class="px-4 py-4 rounded hover:bg-gray-600">
<img src="/static/images/export_database.png" class="w-10 h-10">
</button>
<button value="Export-discussion" id="export-discussion-button" class="px-4 py-4 rounded hover:bg-gray-600">
<img src="/static/images/export_discussion.png" class="w-10 h-10">
</button>
</nav>
<div>
<h1 class="font-bold font-large">Discussions</h1>
</div>
<nav id="discussions-list" class="flex h-full flex-1 flex-col space-y-1 p-2 overflow-y-auto">
</nav>
</div>
<div class="flex max-w-full flex-1 flex-col">
<div class="text-white">
<h1 class="font-bold font-large">Chat box</h1>
</div>
<div id="chat-window" class="overflow-y-auto max-h-full">
</div>
<form id="chat-form" class="flex w-full mt-auto">
<input type="text" id="user-input" placeholder="Type your message..." class="bg-secondary my-1 mx-1 outline-none drop-shadow-sm w-full rounded-md p-2">
<div id="wait-animation" style="display: none;" class="lds-facebook bg-secondary my-1 mx-1 outline-none drop-shadow-sm w-full rounded-md p-2"><div></div><div></div><div></div></div>
<input type="submit" value="Send" id="submit-input" class="my-1 mx-1 outline-none px-4 bg-accent text-black rounded-md hover:bg-[#7ba0ea] active:bg-[#3d73e1] transition-colors ease-in-out">
</form>
</div>
</div>

40
templates/settings.html Normal file
View File

@ -0,0 +1,40 @@
<div class="h-full overflow-y-auto">
<form id="model-params-form" class="bg-gray-700 shadow-md rounded px-8 py-8 pt-6 pb-8 mb-4 text-white">
<div class="mb-4">
<label class="block font-bold mb-2" for="model">Model</label>
<select class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" id="model" name="model" value="gpt4all-lora-quantized.bin">
</select>
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="seed">Seed</label>
<input class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" id="seed" type="text" name="seed" value="0">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="temp" id="temperature-value">Temperature (0.1)</label>
<input class="w-full slider-value" id="temp" type="range" min="0" max="1" step="0.1" value="0.1" name="temp">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="n-predict" id="n-predict-value">N Predict (256)</label>
<input class="w-full slider-value" id="n-predict" type="range" min="0" max="2048" step="1" value="256" name="n-predict">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="top-k" id="top-k-value">Top K</label>
<input class="w-full slider-value" id="top-k" type="range" min="0" max="100" step="1" value="40" name="top-k">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="top-p" id="top-p-value">Top P</label>
<input class="w-full slider-value" id="top-p" type="range" min="0" max="100" step="1" value="40" name="top-p">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="repeat-penalty" id="repeat-penalty-value">Repeat penalty</label>
<input class="w-full slider-value" id="repeat-penalty" type="range" min="0" max="2" step="0.1" value="1.3" name="repeat-penalty">
</div>
<div class="mb-4">
<label class="block font-bold mb-2" for="repeat-last-n" id="repeat-last-n-value">Repeat last N</label>
<input class="w-full slider-value" id="repeat-last-n" type="range" min="0" max="100" step="1" value="40" name="repeat-last-n">
</div>
<div class="mb-4">
<button type="submit" id="submit-model-params" class="my-1 mx-1 outline-none px-4 bg-accent rounded-md bg-gray-500 hover:bg-gray-300 transition-colors ease-in-out">Update parameters</button>
</div>
</form>
</div>