Major upgrade in backends structure. Now you can build your own backend

This commit is contained in:
ParisNeo 2023-04-24 21:24:18 +02:00
parent ddafde66d5
commit 917600f412
11 changed files with 133 additions and 114 deletions

View File

@ -215,8 +215,8 @@ Now you're ready to work!
# Supported backends # Supported backends
Two backends are now supported: Two backends are now supported:
1 - The llama_cpp backend 1 - [The llama_cpp backend](https://github.com/nomic-ai/pygpt4all)
2 - The GPT-j backend 2 - [The GPT-j backend](https://github.com/marella/gpt4all-j)
3 - Hugging face's Transformers (under construction) 3 - Hugging face's Transformers (under construction)
# Supported models # Supported models

4
app.py
View File

@ -146,8 +146,8 @@ class Gpt4AllWebUI(GPT4AllAPI):
) )
def list_backends(self): def list_backends(self):
backends_dir = Path('./pyGpt4All/backends') # replace with the actual path to the models folder backends_dir = Path('./backends') # replace with the actual path to the models folder
backends = [f.stem for f in backends_dir.glob('*.py') if f.stem!="backend" and f.stem!="__init__"] backends = [f.stem for f in backends_dir.iterdir() if f.is_dir()]
return jsonify(backends) return jsonify(backends)

View File

@ -10,7 +10,7 @@
from pathlib import Path from pathlib import Path
from typing import Callable from typing import Callable
from gpt4allj import Model from gpt4allj import Model
from pyGpt4All.backends.backend import GPTBackend from pyGpt4All.backend import GPTBackend
__author__ = "parisneo" __author__ = "parisneo"
__github__ = "https://github.com/nomic-ai/gpt4all-ui" __github__ = "https://github.com/nomic-ai/gpt4all-ui"

View File

@ -11,7 +11,7 @@ from pathlib import Path
from typing import Callable from typing import Callable
from transformers import AutoTokenizer from transformers import AutoTokenizer
from transformers import AutoModelForCausalLM from transformers import AutoModelForCausalLM
from pyGpt4All.backends.backend import GPTBackend from pyGpt4All.backend import GPTBackend
__author__ = "parisneo" __author__ = "parisneo"
__github__ = "https://github.com/nomic-ai/gpt4all-ui" __github__ = "https://github.com/nomic-ai/gpt4all-ui"

View File

@ -10,7 +10,7 @@
from pathlib import Path from pathlib import Path
from typing import Callable from typing import Callable
from pyllamacpp.model import Model from pyllamacpp.model import Model
from pyGpt4All.backends.backend import GPTBackend from pyGpt4All.backend import GPTBackend
__author__ = "parisneo" __author__ = "parisneo"
__github__ = "https://github.com/nomic-ai/gpt4all-ui" __github__ = "https://github.com/nomic-ai/gpt4all-ui"

View File

@ -46,7 +46,7 @@ class GPT4AllAPI():
self.full_message_list = [] self.full_message_list = []
# Select backend # Select backend
self.BACKENDS_LIST = {f.stem:f for f in (Path("pyGpt4All")/"backends").glob("*.py") if f.stem not in ["__init__","backend"]} self.BACKENDS_LIST = {f.stem:f for f in Path("backends").iterdir() if f.is_dir()}
self.load_backend(self.BACKENDS_LIST[self.config["backend"]]) self.load_backend(self.BACKENDS_LIST[self.config["backend"]])
@ -86,7 +86,7 @@ class GPT4AllAPI():
module_name = backend_path.stem module_name = backend_path.stem
# use importlib to load the module from the file path # use importlib to load the module from the file path
loader = importlib.machinery.SourceFileLoader(module_name, str(absolute_path)) loader = importlib.machinery.SourceFileLoader(module_name, str(absolute_path/"__init__.py"))
backend_module = loader.load_module() backend_module = loader.load_module()
backend_class = getattr(backend_module, backend_module.backend_name) backend_class = getattr(backend_module, backend_module.backend_name)
self.backend = backend_class self.backend = backend_class

View File

@ -5,4 +5,8 @@ pyyaml
markdown markdown
pyllamacpp==1.0.6 pyllamacpp==1.0.6
gpt4all-j==0.2.1 gpt4all-j==0.2.1
--find-links https://download.pytorch.org/whl/cu117
torch==2.0.0
torchvision
torchaudio
transformers transformers

View File

@ -14,119 +14,134 @@ function update_main(){
}); });
}) })
userInput.addEventListener('keydown', function(event) {
if (event.shiftKey && event.key === 'Enter') {
event.preventDefault();
userInput.style.height = userInput.scrollHeight + 'px';
userInput.value += '\n';
}
});
chatForm.addEventListener('submit', event => {
event.preventDefault(); function submit_form(){
console.log("Submitting") console.log("Submitting")
// get user input and clear input field // get user input and clear input field
message = userInput.value; message = userInput.value;
userInput.value = ''; userInput.value = '';
// add user message to chat window // add user message to chat window
const sendbtn = document.querySelector("#submit-input") const sendbtn = document.querySelector("#submit-input")
const waitAnimation = document.querySelector("#wait-animation") const waitAnimation = document.querySelector("#wait-animation")
const stopGeneration = document.querySelector("#stop-generation") const stopGeneration = document.querySelector("#stop-generation")
sendbtn.style.display="none"; sendbtn.style.display="none";
waitAnimation.style.display="block"; waitAnimation.style.display="block";
stopGeneration.style.display = "block"; stopGeneration.style.display = "block";
console.log("Sending message to bot") console.log("Sending message to bot")
user_msg = addMessage('',message, 0, 0, can_edit=true); user_msg = addMessage('',message, 0, 0, can_edit=true);
bot_msg = addMessage('', '', 0, 0, can_edit=true); bot_msg = addMessage('', '', 0, 0, can_edit=true);
fetch('/generate', { fetch('/generate', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ message }) body: JSON.stringify({ message })
}).then(function(response) { }).then(function(response) {
const stream = new ReadableStream({ const stream = new ReadableStream({
start(controller) { start(controller) {
const reader = response.body.getReader(); const reader = response.body.getReader();
function push() { function push() {
reader.read().then(function(result) { reader.read().then(function(result) {
if (result.done) { if (result.done) {
sendbtn.style.display="block"; sendbtn.style.display="block";
waitAnimation.style.display="none"; waitAnimation.style.display="none";
stopGeneration.style.display = "none"; stopGeneration.style.display = "none";
console.log(result) console.log(result)
controller.close(); controller.close();
return; return;
} }
controller.enqueue(result.value); controller.enqueue(result.value);
push(); push();
}) })
} }
push(); push();
} }
}); });
const textDecoder = new TextDecoder(); const textDecoder = new TextDecoder();
const readableStreamDefaultReader = stream.getReader(); const readableStreamDefaultReader = stream.getReader();
let entry_counter = 0 let entry_counter = 0
function readStream() { function readStream() {
readableStreamDefaultReader.read().then(function(result) { readableStreamDefaultReader.read().then(function(result) {
if (result.done) { if (result.done) {
return; 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);
user_msg.setSender(infos.user); text = textDecoder.decode(result.value);
user_msg.setMessage(infos.message);
user_msg.setID(infos.id);
bot_msg.setSender(infos.bot);
bot_msg.setID(infos.response_id);
bot_msg.messageTextElement; // The server will first send a json containing information about the message just sent
bot_msg.hiddenElement; if(entry_counter==0)
entry_counter ++; {
// We parse it and
infos = JSON.parse(text);
user_msg.setSender(infos.user);
user_msg.setMessage(infos.message);
user_msg.setID(infos.id);
bot_msg.setSender(infos.bot);
bot_msg.setID(infos.response_id);
bot_msg.messageTextElement;
bot_msg.hiddenElement;
entry_counter ++;
}
else{
entry_counter ++;
prefix = "FINAL:";
if(text.startsWith(prefix)){
text = text.substring(prefix.length);
bot_msg.hiddenElement.innerHTML = text
bot_msg.messageTextElement.innerHTML = text
} }
else{ else{
entry_counter ++; // For the other enrtries, these are just the text of the chatbot
prefix = "FINAL:"; for (const char of text) {
if(text.startsWith(prefix)){ txt = bot_msg.hiddenElement.innerHTML;
text = text.substring(prefix.length); if (char != '\f') {
bot_msg.hiddenElement.innerHTML = text txt += char
bot_msg.messageTextElement.innerHTML = text bot_msg.hiddenElement.innerHTML = txt;
} bot_msg.messageTextElement.innerHTML = txt;
else{ }
// For the other enrtries, these are just the text of the chatbot
for (const char of text) {
txt = bot_msg.hiddenElement.innerHTML;
if (char != '\f') {
txt += char
bot_msg.hiddenElement.innerHTML = txt;
bot_msg.messageTextElement.innerHTML = txt;
}
// scroll to bottom of chat window // scroll to bottom of chat window
chatWindow.scrollTop = chatWindow.scrollHeight; chatWindow.scrollTop = chatWindow.scrollHeight;
}
}
} }
readStream(); }
}); }
}
readStream(); readStream();
}); });
}
readStream();
});
}
chatForm.addEventListener('submit', event => {
event.preventDefault();
submit_form();
}); });
userInput.addEventListener("keyup", function(event) {
// Check if Enter key was pressed while holding Shift
// Also check if Shift + Ctrl keys were pressed while typing
// These combinations override the submit action
const shiftPressed = event.shiftKey;
const ctrlPressed = event.ctrlKey && !event.metaKey;
if ((!shiftPressed) && event.key === "Enter") {
submit_form();
}
// Restore original functionality for the remaining cases
else if (!shiftPressed && ctrlPressed) {
setTimeout(() => {
userInput.focus();
contentEditable.value += event.data;
lastValue.innerHTML = userInput.value;
}, 0);
}
});
} }

View File

@ -35,7 +35,7 @@
<div class="w-full flex justify-center"> <div class="w-full flex justify-center">
<div class="w-full flex bottom-0 fixed rounded-sm shadow shadow-white bg-gray-300 p-1 dark:bg-gray-500 flex-wrap"> <div class="w-full flex bottom-0 fixed rounded-sm shadow shadow-white bg-gray-300 p-1 dark:bg-gray-500 flex-wrap">
<form id="chat-form" class="w-full flex-row text-white mr-15 p-15"> <form id="chat-form" class="w-full flex-row text-white mr-15 p-15">
<input type="text" id="user-input" placeholder="Type your message..." class="dark:bg-gray-600 pl-1 pr-1 py-1 my-1 mr-2 text-black dark:text-white outline-none drop-shadow-sm w-full rounded-md flex-1"> <textarea type="text" id="user-input" placeholder="Type your message..." class="dark:bg-gray-600 pl-1 pr-1 py-1 my-1 mr-2 text-black dark:text-white outline-none drop-shadow-sm w-full rounded-md flex-1"></textarea>
<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> <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>
<button id="stop-generation" style="display: none;" class="my-1 mx-1 outline-none px-4 dark:bg-gray-900 text-black dark:text-white rounded-md hover:bg-[#7ba0ea] active:bg-[#3d73e1] transition-colors ease-in-out">Stop generating</button> <button id="stop-generation" style="display: none;" class="my-1 mx-1 outline-none px-4 dark:bg-gray-900 text-black dark:text-white rounded-md hover:bg-[#7ba0ea] active:bg-[#3d73e1] transition-colors ease-in-out">Stop generating</button>
<input type="submit" value="Send" id="submit-input" class="my-1 mx-1 outline-none px-4 dark:bg-gray-900 text-black dark:text-white rounded-md hover:bg-[#7ba0ea] active:bg-[#3d73e1] transition-colors ease-in-out"> <input type="submit" value="Send" id="submit-input" class="my-1 mx-1 outline-none px-4 dark:bg-gray-900 text-black dark:text-white rounded-md hover:bg-[#7ba0ea] active:bg-[#3d73e1] transition-colors ease-in-out">