mirror of
https://github.com/ParisNeo/lollms-webui.git
synced 2024-12-30 09:08:51 +00:00
commit
438e2be7cb
177
app.py
177
app.py
@ -1,12 +1,11 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import sqlite3
|
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
import sys
|
import sys
|
||||||
|
from db import Discussion, export_to_json, check_discussion_db, last_discussion_has_messages
|
||||||
from flask import (
|
from flask import (
|
||||||
Flask,
|
Flask,
|
||||||
Response,
|
Response,
|
||||||
@ -14,155 +13,11 @@ from flask import (
|
|||||||
render_template,
|
render_template,
|
||||||
request,
|
request,
|
||||||
stream_with_context,
|
stream_with_context,
|
||||||
|
send_from_directory
|
||||||
)
|
)
|
||||||
from pyllamacpp.model import Model
|
from pyllamacpp.model import Model
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
|
from pathlib import Path
|
||||||
# =================================== Database ==================================================================
|
|
||||||
class Discussion:
|
|
||||||
def __init__(self, discussion_id, db_path="database.db"):
|
|
||||||
self.discussion_id = discussion_id
|
|
||||||
self.db_path = db_path
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def create_discussion(db_path="database.db", title="untitled"):
|
|
||||||
with sqlite3.connect(db_path) as conn:
|
|
||||||
cur = conn.cursor()
|
|
||||||
cur.execute("INSERT INTO discussion (title) VALUES (?)", (title,))
|
|
||||||
discussion_id = cur.lastrowid
|
|
||||||
conn.commit()
|
|
||||||
return Discussion(discussion_id, db_path)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_discussion(db_path="database.db", discussion_id=0):
|
|
||||||
return Discussion(discussion_id, db_path)
|
|
||||||
|
|
||||||
def add_message(self, sender, content):
|
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
|
||||||
cur = conn.cursor()
|
|
||||||
cur.execute(
|
|
||||||
"INSERT INTO message (sender, content, discussion_id) VALUES (?, ?, ?)",
|
|
||||||
(sender, content, self.discussion_id),
|
|
||||||
)
|
|
||||||
message_id = cur.lastrowid
|
|
||||||
conn.commit()
|
|
||||||
return message_id
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_discussions(db_path):
|
|
||||||
with sqlite3.connect(db_path) as conn:
|
|
||||||
cursor = conn.cursor()
|
|
||||||
cursor.execute("SELECT * FROM discussion")
|
|
||||||
rows = cursor.fetchall()
|
|
||||||
return [{"id": row[0], "title": row[1]} for row in rows]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def rename(db_path, discussion_id, title):
|
|
||||||
with sqlite3.connect(db_path) as conn:
|
|
||||||
cursor = conn.cursor()
|
|
||||||
cursor.execute(
|
|
||||||
"UPDATE discussion SET title=? WHERE id=?", (title, discussion_id)
|
|
||||||
)
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
def delete_discussion(self):
|
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
|
||||||
cur = conn.cursor()
|
|
||||||
cur.execute(
|
|
||||||
"DELETE FROM message WHERE discussion_id=?", (self.discussion_id,)
|
|
||||||
)
|
|
||||||
cur.execute("DELETE FROM discussion WHERE id=?", (self.discussion_id,))
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
def get_messages(self):
|
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
|
||||||
cur = conn.cursor()
|
|
||||||
cur.execute(
|
|
||||||
"SELECT * FROM message WHERE discussion_id=?", (self.discussion_id,)
|
|
||||||
)
|
|
||||||
rows = cur.fetchall()
|
|
||||||
return [{"sender": row[1], "content": row[2], "id": row[0]} for row in rows]
|
|
||||||
|
|
||||||
def update_message(self, message_id, new_content):
|
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
|
||||||
cur = conn.cursor()
|
|
||||||
cur.execute(
|
|
||||||
"UPDATE message SET content = ? WHERE id = ?", (new_content, message_id)
|
|
||||||
)
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
def remove_discussion(self):
|
|
||||||
with sqlite3.connect(self.db_path) as conn:
|
|
||||||
conn.cursor().execute(
|
|
||||||
"DELETE FROM discussion WHERE id=?", (self.discussion_id,)
|
|
||||||
)
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def last_discussion_has_messages(db_path="database.db"):
|
|
||||||
with sqlite3.connect(db_path) as conn:
|
|
||||||
cursor = conn.cursor()
|
|
||||||
cursor.execute("SELECT * FROM message ORDER BY id DESC LIMIT 1")
|
|
||||||
last_message = cursor.fetchone()
|
|
||||||
return last_message is not None
|
|
||||||
|
|
||||||
|
|
||||||
def export_to_json(db_path="database.db"):
|
|
||||||
with sqlite3.connect(db_path) as conn:
|
|
||||||
cur = conn.cursor()
|
|
||||||
cur.execute("SELECT * FROM discussion")
|
|
||||||
discussions = []
|
|
||||||
for row in cur.fetchall():
|
|
||||||
discussion_id = row[0]
|
|
||||||
discussion = {"id": discussion_id, "messages": []}
|
|
||||||
cur.execute("SELECT * FROM message WHERE discussion_id=?", (discussion_id,))
|
|
||||||
for message_row in cur.fetchall():
|
|
||||||
discussion["messages"].append(
|
|
||||||
{"sender": message_row[1], "content": message_row[2]}
|
|
||||||
)
|
|
||||||
discussions.append(discussion)
|
|
||||||
return discussions
|
|
||||||
|
|
||||||
|
|
||||||
def remove_discussions(db_path="database.db"):
|
|
||||||
with sqlite3.connect(db_path) as conn:
|
|
||||||
cur = conn.cursor()
|
|
||||||
cur.execute("DELETE FROM message")
|
|
||||||
cur.execute("DELETE FROM discussion")
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
|
|
||||||
# create database schema
|
|
||||||
def check_discussion_db(db_path):
|
|
||||||
print("Checking discussions database...")
|
|
||||||
with sqlite3.connect(db_path) as conn:
|
|
||||||
cur = conn.cursor()
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
CREATE TABLE IF NOT EXISTS discussion (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
title TEXT
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
CREATE TABLE IF NOT EXISTS message (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
sender TEXT NOT NULL,
|
|
||||||
content TEXT NOT NULL,
|
|
||||||
discussion_id INTEGER NOT NULL,
|
|
||||||
FOREIGN KEY (discussion_id) REFERENCES discussion(id)
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
print("Ok")
|
|
||||||
|
|
||||||
|
|
||||||
# ========================================================================================================================
|
|
||||||
|
|
||||||
|
|
||||||
app = Flask("GPT4All-WebUI", static_url_path="/static", static_folder="static")
|
app = Flask("GPT4All-WebUI", static_url_path="/static", static_folder="static")
|
||||||
|
|
||||||
@ -174,8 +29,11 @@ class Gpt4AllWebUI:
|
|||||||
self.app = _app
|
self.app = _app
|
||||||
self.db_path = args.db_path
|
self.db_path = args.db_path
|
||||||
|
|
||||||
|
# This is the queue used to stream text to the ui as the bot spits out its response
|
||||||
self.text_queue = Queue(0)
|
self.text_queue = Queue(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.add_endpoint("/", "", self.index, methods=["GET"])
|
self.add_endpoint("/", "", self.index, methods=["GET"])
|
||||||
self.add_endpoint("/export", "export", self.export, methods=["GET"])
|
self.add_endpoint("/export", "export", self.export, methods=["GET"])
|
||||||
self.add_endpoint(
|
self.add_endpoint(
|
||||||
@ -203,9 +61,21 @@ class Gpt4AllWebUI:
|
|||||||
"/update_model_params", "update_model_params", self.update_model_params, methods=["POST"]
|
"/update_model_params", "update_model_params", self.update_model_params, methods=["POST"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.add_endpoint(
|
||||||
|
"/list_models", "list_models", self.list_models, methods=["GET"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
self.add_endpoint(
|
||||||
|
"/get_args", "get_args", self.get_args, methods=["GET"]
|
||||||
|
)
|
||||||
|
|
||||||
self.prepare_a_new_chatbot()
|
self.prepare_a_new_chatbot()
|
||||||
|
|
||||||
|
def list_models(self):
|
||||||
|
models_dir = Path('./models') # replace with the actual path to the models folder
|
||||||
|
models = [f.name for f in models_dir.glob('*.bin')]
|
||||||
|
return jsonify(models)
|
||||||
|
|
||||||
def prepare_a_new_chatbot(self):
|
def prepare_a_new_chatbot(self):
|
||||||
# Create chatbot
|
# Create chatbot
|
||||||
@ -463,7 +333,12 @@ GPT4All:Welcome! I'm here to assist you with anything you need. What can I do fo
|
|||||||
|
|
||||||
def update_model_params(self):
|
def update_model_params(self):
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
self.args.model = str(data["model"])
|
model = str(data["model"])
|
||||||
|
if self.args.model != model:
|
||||||
|
print("New model selected")
|
||||||
|
self.args.model = model
|
||||||
|
self.prepare_a_new_chatbot()
|
||||||
|
|
||||||
self.args.n_predict = int(data["nPredict"])
|
self.args.n_predict = int(data["nPredict"])
|
||||||
self.args.seed = int(data["seed"])
|
self.args.seed = int(data["seed"])
|
||||||
|
|
||||||
@ -484,6 +359,10 @@ GPT4All:Welcome! I'm here to assist you with anything you need. What can I do fo
|
|||||||
return jsonify({"status":"ok"})
|
return jsonify({"status":"ok"})
|
||||||
|
|
||||||
|
|
||||||
|
def get_args(self):
|
||||||
|
return jsonify(self.args)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Start the chatbot Flask app.")
|
parser = argparse.ArgumentParser(description="Start the chatbot Flask app.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
146
db.py
Normal file
146
db.py
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
|
||||||
|
import sqlite3
|
||||||
|
# =================================== Database ==================================================================
|
||||||
|
class Discussion:
|
||||||
|
def __init__(self, discussion_id, db_path="database.db"):
|
||||||
|
self.discussion_id = discussion_id
|
||||||
|
self.db_path = db_path
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_discussion(db_path="database.db", title="untitled"):
|
||||||
|
with sqlite3.connect(db_path) as conn:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("INSERT INTO discussion (title) VALUES (?)", (title,))
|
||||||
|
discussion_id = cur.lastrowid
|
||||||
|
conn.commit()
|
||||||
|
return Discussion(discussion_id, db_path)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_discussion(db_path="database.db", discussion_id=0):
|
||||||
|
return Discussion(discussion_id, db_path)
|
||||||
|
|
||||||
|
def add_message(self, sender, content):
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(
|
||||||
|
"INSERT INTO message (sender, content, discussion_id) VALUES (?, ?, ?)",
|
||||||
|
(sender, content, self.discussion_id),
|
||||||
|
)
|
||||||
|
message_id = cur.lastrowid
|
||||||
|
conn.commit()
|
||||||
|
return message_id
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_discussions(db_path):
|
||||||
|
with sqlite3.connect(db_path) as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT * FROM discussion")
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
return [{"id": row[0], "title": row[1]} for row in rows]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def rename(db_path, discussion_id, title):
|
||||||
|
with sqlite3.connect(db_path) as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"UPDATE discussion SET title=? WHERE id=?", (title, discussion_id)
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def delete_discussion(self):
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(
|
||||||
|
"DELETE FROM message WHERE discussion_id=?", (self.discussion_id,)
|
||||||
|
)
|
||||||
|
cur.execute("DELETE FROM discussion WHERE id=?", (self.discussion_id,))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def get_messages(self):
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(
|
||||||
|
"SELECT * FROM message WHERE discussion_id=?", (self.discussion_id,)
|
||||||
|
)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
return [{"sender": row[1], "content": row[2], "id": row[0]} for row in rows]
|
||||||
|
|
||||||
|
def update_message(self, message_id, new_content):
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(
|
||||||
|
"UPDATE message SET content = ? WHERE id = ?", (new_content, message_id)
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def remove_discussion(self):
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
conn.cursor().execute(
|
||||||
|
"DELETE FROM discussion WHERE id=?", (self.discussion_id,)
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def last_discussion_has_messages(db_path="database.db"):
|
||||||
|
with sqlite3.connect(db_path) as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT * FROM message ORDER BY id DESC LIMIT 1")
|
||||||
|
last_message = cursor.fetchone()
|
||||||
|
return last_message is not None
|
||||||
|
|
||||||
|
|
||||||
|
def export_to_json(db_path="database.db"):
|
||||||
|
with sqlite3.connect(db_path) as conn:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("SELECT * FROM discussion")
|
||||||
|
discussions = []
|
||||||
|
for row in cur.fetchall():
|
||||||
|
discussion_id = row[0]
|
||||||
|
discussion = {"id": discussion_id, "messages": []}
|
||||||
|
cur.execute("SELECT * FROM message WHERE discussion_id=?", (discussion_id,))
|
||||||
|
for message_row in cur.fetchall():
|
||||||
|
discussion["messages"].append(
|
||||||
|
{"sender": message_row[1], "content": message_row[2]}
|
||||||
|
)
|
||||||
|
discussions.append(discussion)
|
||||||
|
return discussions
|
||||||
|
|
||||||
|
|
||||||
|
def remove_discussions(db_path="database.db"):
|
||||||
|
with sqlite3.connect(db_path) as conn:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("DELETE FROM message")
|
||||||
|
cur.execute("DELETE FROM discussion")
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
|
||||||
|
# create database schema
|
||||||
|
def check_discussion_db(db_path):
|
||||||
|
print("Checking discussions database...")
|
||||||
|
with sqlite3.connect(db_path) as conn:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS discussion (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS message (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
sender TEXT NOT NULL,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
discussion_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (discussion_id) REFERENCES discussion(id)
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
print("Ok")
|
||||||
|
|
||||||
|
|
||||||
|
# ========================================================================================================================
|
18
install.bat
18
install.bat
@ -171,11 +171,29 @@ goto :CONTINUE
|
|||||||
:CONTINUE
|
:CONTINUE
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
|
set /p choice=Do you want to download and install the GPT4All model? [Y/N]
|
||||||
|
if /i ".choice." equ "Y" (
|
||||||
|
echo -n "Checking for git..."
|
||||||
|
if command -v git > /dev/null 2>&1; then
|
||||||
|
echo "OK"
|
||||||
|
else
|
||||||
|
read -p "Git is not installed. Would you like to install Git? [Y/N] " choice
|
||||||
|
if [ "$choice" = "Y" ] || [ "$choice" = "y" ]; then
|
||||||
|
echo "Installing Git..."
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y git
|
||||||
|
else
|
||||||
|
echo "Please install Git and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo Converting the model to the new format
|
echo Converting the model to the new format
|
||||||
if not exist tmp/llama.cpp git clone https://github.com/ggerganov/llama.cpp.git tmp\llama.cpp
|
if not exist tmp/llama.cpp git clone https://github.com/ggerganov/llama.cpp.git tmp\llama.cpp
|
||||||
move models\gpt4all-lora-quantized-ggml.bin models\gpt4all-lora-quantized-ggml.bin.original
|
move models\gpt4all-lora-quantized-ggml.bin models\gpt4all-lora-quantized-ggml.bin.original
|
||||||
python tmp\llama.cpp\migrate-ggml-2023-03-30-pr613.py models\gpt4all-lora-quantized-ggml.bin.original models\gpt4all-lora-quantized-ggml.bin
|
python tmp\llama.cpp\migrate-ggml-2023-03-30-pr613.py models\gpt4all-lora-quantized-ggml.bin.original models\gpt4all-lora-quantized-ggml.bin
|
||||||
echo The model file (gpt4all-lora-quantized-ggml.bin) has been fixed.
|
echo The model file (gpt4all-lora-quantized-ggml.bin) has been fixed.
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
echo Cleaning tmp folder
|
echo Cleaning tmp folder
|
||||||
|
@ -1,3 +1,36 @@
|
|||||||
|
function populate_models(){
|
||||||
|
// Get a reference to the <select> element
|
||||||
|
const selectElement = document.getElementById('model');
|
||||||
|
|
||||||
|
// Fetch the list of .bin files from the models subfolder
|
||||||
|
fetch('/list_models')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
// data is an array
|
||||||
|
const selectElement = document.getElementById('model');
|
||||||
|
data.forEach(filename => {
|
||||||
|
const optionElement = document.createElement('option');
|
||||||
|
optionElement.value = filename;
|
||||||
|
optionElement.textContent = filename;
|
||||||
|
selectElement.appendChild(optionElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
// fetch('/get_args')
|
||||||
|
// .then(response=> response.json())
|
||||||
|
// .then(data=>{
|
||||||
|
|
||||||
|
// })
|
||||||
|
} else {
|
||||||
|
console.error('Expected an array, but received:', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
populate_models()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const submitButton = document.getElementById('submit-model-params');
|
const submitButton = document.getElementById('submit-model-params');
|
||||||
submitButton.addEventListener('click', (event) => {
|
submitButton.addEventListener('click', (event) => {
|
||||||
|
@ -28,7 +28,8 @@
|
|||||||
<form id="model-params-form" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
|
<form id="model-params-form" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label class="block text-gray-700 font-bold mb-2" for="model">Model</label>
|
<label class="block text-gray-700 font-bold mb-2" for="model">Model</label>
|
||||||
<input class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="model" type="text" name="model" value="gpt4all-lora-quantized.bin">
|
<select class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="model" name="model" value="gpt4all-lora-quantized.bin">
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label class="block text-gray-700 font-bold mb-2" for="seed">Seed</label>
|
<label class="block text-gray-700 font-bold mb-2" for="seed">Seed</label>
|
||||||
|
Loading…
Reference in New Issue
Block a user