diff --git a/.gitignore b/.gitignore
index b5e5ead4..3fa045b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -150,6 +150,10 @@ configs/*
 personalities/*
 !personalities/gpt4all_chatbot.yaml
 
+# personalities other than the default one
+databases/*
+!databases/.keep
+
 # extensions
 extensions/
 !extensions/.keep
diff --git a/app.py b/app.py
index a5b89acc..eaa1e150 100644
--- a/app.py
+++ b/app.py
@@ -13,10 +13,9 @@ import argparse
 import json
 import re
 import traceback
-from datetime import datetime
 from concurrent.futures import ThreadPoolExecutor
 import sys
-from db import DiscussionsDB, Discussion
+from pyGpt4All.db import DiscussionsDB, Discussion
 from flask import (
     Flask,
     Response,
@@ -26,34 +25,20 @@ from flask import (
     stream_with_context,
     send_from_directory
 )
-from pyllamacpp.model import Model
 from queue import Queue
 from pathlib import Path
 import gc
 app = Flask("GPT4All-WebUI", static_url_path="/static", static_folder="static")
 import time
-from config import load_config, save_config
+from pyGpt4All.config import load_config, save_config
+from pyGpt4All.api import GPT4AllAPI
 import shutil
-class Gpt4AllWebUI:
-
+class Gpt4AllWebUI(GPT4AllAPI):
     def __init__(self, _app, config:dict, personality:dict, config_file_path) -> None:
-        self.config = config
-        self.config_file_path = config_file_path
-        self.personality = personality
-        self.current_discussion = None
-        self.current_message_id = 0
-        self.app = _app
-        self.db_path = config["db_path"]
-        self.db = DiscussionsDB(self.db_path)
-        # If the database is empty, populate it with tables
-        self.db.populate()
+        super().__init__(config, personality, config_file_path)
+
+        self.app = _app
 
-        # workaround for non interactive mode
-        self.full_message = ""
-        self.full_message_list = []
-        self.prompt_message = ""
-        # This is the queue used to stream text to the ui as the bot spits out its response
-        self.text_queue = Queue(0)
 
         self.add_endpoint(
             "/list_models", "list_models", self.list_models, methods=["GET"]
@@ -131,7 +116,6 @@ class Gpt4AllWebUI:
             "/help", "help", self.help, methods=["GET"]
         )
 
-        self.prepare_a_new_chatbot()
 
     def list_models(self):
         models_dir = Path('./models')  # replace with the actual path to the models folder
@@ -161,63 +145,6 @@ class Gpt4AllWebUI:
         return jsonify(discussions)
 
 
-    def prepare_a_new_chatbot(self):
-        # Create chatbot
-        self.chatbot_bindings = self.create_chatbot()
-        
-
-    def create_chatbot(self):
-        try:
-            return Model(
-                ggml_model=f"./models/{self.config['model']}", 
-                n_ctx=self.config['ctx_size'], 
-                seed=self.config['seed'],
-                )
-        except Exception as ex:
-            print(f"Exception {ex}")
-            return None
-    def condition_chatbot(self, conditionning_message):
-        if self.current_discussion is None:
-            self.current_discussion = self.db.load_last_discussion()
-        
-        message_id = self.current_discussion.add_message(
-            "conditionner", 
-            conditionning_message, 
-            DiscussionsDB.MSG_TYPE_CONDITIONNING,
-            0,
-            self.current_message_id
-        )
-        self.current_message_id = message_id
-        if self.personality["welcome_message"]!="":
-            message_id = self.current_discussion.add_message(
-                self.personality["name"], self.personality["welcome_message"], 
-                DiscussionsDB.MSG_TYPE_NORMAL,
-                0,
-                self.current_message_id
-            )
-        
-            self.current_message_id = message_id
-        return message_id
-
-    def prepare_query(self):
-        self.bot_says = ""
-        self.full_text = ""
-        self.is_bot_text_started = False
-        #self.current_message = message
-
-    def new_text_callback(self, text: str):
-        print(text, end="")
-        sys.stdout.flush()
-        self.full_text += text
-        if self.is_bot_text_started:
-            self.bot_says += text
-            self.full_message += text
-            self.text_queue.put(text)
-            
-        #if self.current_message in self.full_text:
-        if len(self.prompt_message) < len(self.full_text):
-            self.is_bot_text_started = True
-
     def add_endpoint(
         self,
         endpoint=None,
@@ -253,24 +180,6 @@ class Gpt4AllWebUI:
     def export_discussion(self):
         return jsonify(self.full_message)
     
-    def generate_message(self):
-        self.generating=True
-        self.text_queue=Queue()
-        gc.collect()
-
-        self.chatbot_bindings.generate(
-            self.prompt_message,#self.full_message,#self.current_message,
-            new_text_callback=self.new_text_callback,
-            n_predict=len(self.current_message)+self.config['n_predict'],
-            temp=self.config['temp'],
-            top_k=self.config['top_k'],
-            top_p=self.config['top_p'],
-            repeat_penalty=self.config['repeat_penalty'],
-            repeat_last_n = self.config['repeat_last_n'],
-            #seed=self.config['seed'],
-            n_threads=8
-        )
-        self.generating=False
 
     @stream_with_context
     def parse_to_prompt_stream(self, message, message_id):
@@ -281,7 +190,7 @@ class Gpt4AllWebUI:
         print(f"Received message : {message}")
         # First we need to send the new message ID to the client
         response_id = self.current_discussion.add_message(
-            self.personality["name"], ""
+            self.personality["name"], "", parent = message_id
         )  # first the content is empty, but we'll fill it at the end
         yield (
             json.dumps(
@@ -295,15 +204,9 @@ class Gpt4AllWebUI:
             )
         )
 
-        self.current_message = self.personality["message_prefix"] + message + self.personality["message_suffix"]
-        self.full_message += self.current_message
-        self.full_message_list.append(self.current_message)
-        
-        if len(self.full_message_list) > self.config["nb_messages_to_remember"]:
-            self.prompt_message = self.personality["personality_conditionning"]+ '\n'.join(self.full_message_list[-self.config["nb_messages_to_remember"]:])
-        else:
-            self.prompt_message = self.full_message
-        self.prepare_query()
+        # prepare query and reception
+        self.discussion_messages = self.prepare_query(message_id)
+        self.prepare_reception()
         self.generating = True
         app.config['executor'].submit(self.generate_message)
         while self.generating or not self.text_queue.empty():
@@ -313,12 +216,8 @@ class Gpt4AllWebUI:
             except :
                 time.sleep(1)
 
-
-
         self.current_discussion.update_message(response_id, self.bot_says)
         self.full_message_list.append(self.bot_says)
-        #yield self.bot_says# .encode('utf-8').decode('utf-8')
-        # TODO : change this to use the yield version in order to send text word by word
 
         return "\n".join(bot_says)
 
@@ -331,11 +230,13 @@ class Gpt4AllWebUI:
             else:
                 self.current_discussion = self.db.load_last_discussion()
 
+        message = request.json["message"]
         message_id = self.current_discussion.add_message(
-            "user", request.json["message"], parent=self.current_message_id
+            "user", message, parent=self.current_message_id
         )
         message = f"{request.json['message']}"
         self.current_message_id = message_id
+
         # Segmented (the user receives the output as it comes)
         # We will first send a json entry that contains the message id and so on, then the text as it goes
         return Response(
@@ -348,19 +249,12 @@ class Gpt4AllWebUI:
     def run_to(self):
         data = request.get_json()
         message_id = data["id"]
-
         self.stop = True
-        message_id = self.current_discussion.add_message(
-            "user", request.json["message"], parent=message_id
-        )
-
-        message = f"{request.json['message']}"
-
         # Segmented (the user receives the output as it comes)
         # We will first send a json entry that contains the message id and so on, then the text as it goes
         return Response(
             stream_with_context(
-                self.parse_to_prompt_stream(message, message_id)
+                self.parse_to_prompt_stream("",message_id)
             )
         )
 
@@ -370,24 +264,6 @@ class Gpt4AllWebUI:
         self.current_discussion.rename(title)
         return "renamed successfully"
 
-    def restore_discussion(self, full_message):
-        self.prompt_message = full_message
-
-        if len(self.full_message_list)>5:
-            self.prompt_message = "\n".join(self.full_message_list[-5:])
-
-        self.chatbot_bindings.generate(
-            self.prompt_message,#full_message,
-            new_text_callback=self.new_text_callback,
-            n_predict=0,#len(full_message),
-            temp=self.config['temp'],
-            top_k=self.config['top_k'],
-            top_p=self.config['top_p'],
-            repeat_penalty= self.config['repeat_penalty'],
-            repeat_last_n = self.config['repeat_last_n'],
-            n_threads=8
-        )
-
     def load_discussion(self):
         data = request.get_json()
         if "id" in data:
@@ -402,15 +278,6 @@ class Gpt4AllWebUI:
         
         messages = self.current_discussion.get_messages()
         
-        self.full_message = ""
-        self.full_message_list = []
-        for message in messages:
-            if message['sender']!="conditionner":
-                self.full_message += message['sender'] + ": " + message['content'] + "\n"
-                self.full_message_list.append(message['sender'] + ": " + message['content'])
-                self.current_message_id=message['id']
-        app.config['executor'].submit(self.restore_discussion, self.full_message)
-
         return jsonify(messages)
 
     def delete_discussion(self):
@@ -445,17 +312,8 @@ class Gpt4AllWebUI:
 
     def new_discussion(self):
         title = request.args.get("title")
-        self.current_discussion = self.db.create_discussion(title)
-        # Get the current timestamp
-        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
-
-        app.config['executor'].submit(self.prepare_a_new_chatbot)
-
-        self.full_message =""
-
-        # Chatbot conditionning
-        self.condition_chatbot(self.personality["personality_conditionning"])
-
+        timestamp = self.create_new_discussion(title)
+        app.config['executor'].submit(self.create_chatbot)
 
         # Return a success response
         return json.dumps({"id": self.current_discussion.discussion_id, "time": timestamp, "welcome_message":self.personality["welcome_message"]})
@@ -463,10 +321,15 @@ class Gpt4AllWebUI:
     def update_model_params(self):
         data = request.get_json()
         model =  str(data["model"])
+        personality =  str(data["personality"])
         if self.config['model'] != model:
             print("New model selected")
             self.config['model'] = model
-            self.prepare_a_new_chatbot()
+            self.create_chatbot()
+
+        if self.config['personality']!=data["personality"]:
+            self.config['personality'] = data["personality"]
+            self.personality = load_config(f"personalities/{self.config['personality']}.yaml")
 
         self.config['n_predict'] = int(data["nPredict"])
         self.config['seed'] = int(data["seed"])
diff --git a/configs/default.yaml b/configs/default.yaml
index 8f92bed8..c23af456 100644
--- a/configs/default.yaml
+++ b/configs/default.yaml
@@ -1,7 +1,8 @@
 config: default
 ctx_size: 512
-db_path: database.db
+db_path: databases/database.db
 debug: false
+n_threads: 8
 host: localhost
 language: en-US
 model: gpt4all-lora-quantized-ggml.bin
diff --git a/databases/.keep b/databases/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/personalities/gpt4all_chatbot.yaml b/personalities/gpt4all_chatbot.yaml
index 195461c5..527ab018 100644
--- a/personalities/gpt4all_chatbot.yaml
+++ b/personalities/gpt4all_chatbot.yaml
@@ -27,7 +27,7 @@ personality_conditionning: |
 welcome_message: "Welcome! I am GPT4All A free and open discussion AI. What can I do for you today?"
 
 # This prefix is added at the beginning of any message input by the user
-message_prefix:  "\nuser: "
+message_prefix:  "user: "
 
 # This suffix is added at the end of any message input by the user
 message_suffix: "\ngpt4all: "
diff --git a/pyGpt4All/api.py b/pyGpt4All/api.py
new file mode 100644
index 00000000..793b32a6
--- /dev/null
+++ b/pyGpt4All/api.py
@@ -0,0 +1,162 @@
+######
+# Project       : GPT4ALL-UI
+# File          : api.py
+# Author        : ParisNeo with the help of the community
+# Supported by Nomic-AI
+# Licence       : Apache 2.0
+# Description   : 
+# A simple api to communicate with gpt4all-ui and its models.
+######
+import gc
+import sys
+from queue import Queue
+from datetime import datetime
+from pyllamacpp.model import Model
+from pyGpt4All.db import DiscussionsDB
+
+class GPT4AllAPI():
+    def __init__(self, config:dict, personality:dict, config_file_path) -> None:
+        self.config = config
+        self.personality = personality
+        self.config_file_path = config_file_path
+
+        # This is the queue used to stream text to the ui as the bot spits out its response
+        self.text_queue = Queue(0)
+
+        # Keeping track of current discussion and message
+        self.current_discussion = None
+        self.current_message_id = 0
+
+        self.db_path = config["db_path"]
+
+        # Create database object
+        self.db = DiscussionsDB(self.db_path)
+
+        # If the database is empty, populate it with tables
+        self.db.populate()
+
+        # This is used to keep track of messages 
+        self.full_message_list = []
+
+        # Build chatbot
+        self.chatbot_bindings = self.create_chatbot()
+        print("Chatbot created successfully")
+
+        # tests the model
+        """
+        self.prepare_reception()
+        self.discussion_messages = "Instruction: Act as gpt4all. A kind and helpful AI bot built to help users solve problems.\nuser: how to build a water rocket?\ngpt4all:"
+        self.chatbot_bindings.generate(
+            self.discussion_messages,
+            new_text_callback=self.new_text_callback,
+            n_predict=372,
+            temp=self.config['temp'],
+            top_k=self.config['top_k'],
+            top_p=self.config['top_p'],
+            repeat_penalty=self.config['repeat_penalty'],
+            repeat_last_n = self.config['repeat_last_n'],
+            #seed=self.config['seed'],
+            n_threads=self.config['n_threads']
+        )        
+        
+        """
+
+        # generation status
+        self.generating=False
+
+    def create_chatbot(self):
+        try:
+            return Model(
+                ggml_model=f"./models/{self.config['model']}", 
+                n_ctx=self.config['ctx_size'], 
+                seed=self.config['seed'],
+                )
+        except Exception as ex:
+            print(f"Exception {ex}")
+            return None
+    
+    def condition_chatbot(self, conditionning_message):
+        if self.current_discussion is None:
+            self.current_discussion = self.db.load_last_discussion()
+        
+        message_id = self.current_discussion.add_message(
+            "conditionner", 
+            conditionning_message, 
+            DiscussionsDB.MSG_TYPE_CONDITIONNING,
+            0,
+            0
+        )
+        self.current_message_id = message_id
+        if self.personality["welcome_message"]!="":
+            message_id = self.current_discussion.add_message(
+                self.personality["name"], self.personality["welcome_message"], 
+                DiscussionsDB.MSG_TYPE_NORMAL,
+                0,
+                self.current_message_id
+            )
+        
+            self.current_message_id = message_id
+        return message_id
+
+    def prepare_reception(self):
+        self.bot_says = ""
+        self.full_text = ""
+        self.is_bot_text_started = False
+        #self.current_message = message
+
+    def create_new_discussion(self, title):
+        self.current_discussion = self.db.create_discussion(title)
+        # Get the current timestamp
+        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+
+        # Chatbot conditionning
+        self.condition_chatbot(self.personality["personality_conditionning"])
+        return timestamp
+
+    def prepare_query(self, message_id=-1):
+        messages = self.current_discussion.get_messages()
+        self.full_message_list = []
+        for message in messages:
+            if message["id"]<= message_id or message_id==-1: 
+                if message["type"]!=self.db.MSG_TYPE_CONDITIONNING:
+                    if message["sender"]==self.personality["name"]:
+                        self.full_message_list.append(message["content"])
+                    else:
+                        self.full_message_list.append(self.personality["message_prefix"] + message["content"] + self.personality["message_suffix"])
+
+        if len(self.full_message_list) > self.config["nb_messages_to_remember"]:
+            discussion_messages = self.personality["personality_conditionning"]+ '\n'.join(self.full_message_list[-self.config["nb_messages_to_remember"]:])
+        else:
+            discussion_messages = self.personality["personality_conditionning"]+ '\n'.join(self.full_message_list)
+        return discussion_messages[:-1] # Removes the last return
+    
+    def new_text_callback(self, text: str):
+        print(text, end="")
+        sys.stdout.flush()
+        self.full_text += text
+        if self.is_bot_text_started:
+            self.bot_says += text
+            self.text_queue.put(text)
+            
+        #if self.current_message in self.full_text:
+        if len(self.discussion_messages) < len(self.full_text):
+            self.is_bot_text_started = True
+        
+    def generate_message(self):
+        self.generating=True
+        self.text_queue=Queue()
+        gc.collect()
+        total_n_predict = len(self.discussion_messages)+self.config['n_predict']
+        self.chatbot_bindings.generate(
+            self.discussion_messages,
+            new_text_callback=self.new_text_callback,
+            n_predict=total_n_predict,
+            temp=self.config['temp'],
+            top_k=self.config['top_k'],
+            top_p=self.config['top_p'],
+            repeat_penalty=self.config['repeat_penalty'],
+            repeat_last_n = self.config['repeat_last_n'],
+            #seed=self.config['seed'],
+            n_threads=self.config['n_threads']
+        )
+        self.generating=False
diff --git a/config.py b/pyGpt4All/config.py
similarity index 100%
rename from config.py
rename to pyGpt4All/config.py
diff --git a/db.py b/pyGpt4All/db.py
similarity index 99%
rename from db.py
rename to pyGpt4All/db.py
index d95b7d21..63444ff0 100644
--- a/db.py
+++ b/pyGpt4All/db.py
@@ -256,7 +256,7 @@ class Discussion:
             list: List of entries in the format {"id":message id, "sender":sender name, "content":message content, "type":message type, "rank": message rank}
         """
         rows = self.discussions_db.select(
-            f"SELECT * FROM message WHERE discussion_id={self.discussion_id}"
+            "SELECT * FROM message WHERE discussion_id=?", (self.discussion_id,)
         )
 
         return [{"id": row[0], "sender": row[1], "content": row[2], "type": row[3], "rank": row[4], "parent": row[5]} for row in rows]
diff --git a/extension.py b/pyGpt4All/extension.py
similarity index 100%
rename from extension.py
rename to pyGpt4All/extension.py
diff --git a/static/js/chat.js b/static/js/chat.js
index 6f9f30e8..4dc571b2 100644
--- a/static/js/chat.js
+++ b/static/js/chat.js
@@ -60,6 +60,10 @@ function addMessage(sender, message, id, rank = 0, can_edit = false) {
             sendbtn.style.display = "none";
             waitAnimation.style.display = "block";
 
+            // local stuff
+            let messageTextElement_ = undefined
+            let hiddenElement_ = undefined
+
             fetch("/run_to", {
                 method: 'POST',
                 headers: {
@@ -105,10 +109,9 @@ function addMessage(sender, message, id, rank = 0, can_edit = false) {
                                 // We parse it and
                                 infos = JSON.parse(text)
                                 console.log(infos)
-                                addMessage('User', infos.message, infos.id, 0, can_edit = true);
                                 elements = addMessage(infos.sender, '', infos.response_id, 0, can_edit = true);
-                                messageTextElement = elements['messageTextElement'];
-                                hiddenElement = elements['hiddenElement'];
+                                messageTextElement_ = elements['messageTextElement'];
+                                hiddenElement_ = elements['hiddenElement'];
                                 entry_counter++;
                             }
                             else {
@@ -117,8 +120,8 @@ function addMessage(sender, message, id, rank = 0, can_edit = false) {
                                     txt = hiddenElement.innerHTML;
                                     if (char != '\f') {
                                         txt += char
-                                        hiddenElement.innerHTML = txt
-                                        messageTextElement.innerHTML = txt.replace(/\n/g, "<br>")
+                                        hiddenElement_.innerHTML = txt
+                                        messageTextElement_.innerHTML = txt.replace(/\n/g, "<br>")
                                     }
 
                                     // scroll to bottom of chat window
diff --git a/static/js/main.js b/static/js/main.js
index e7905bf2..79c8acf7 100644
--- a/static/js/main.js
+++ b/static/js/main.js
@@ -16,6 +16,7 @@ function update_main(){
       const waitAnimation = document.querySelector("#wait-animation")
       sendbtn.style.display="none";
       waitAnimation.style.display="block";
+      console.log("Sending message to bot")
       fetch('/bot', {
           method: 'POST',
           headers: {