improved ergonomy, enhanced database, added ranking system

This commit is contained in:
Saifeddine ALOUI 2023-04-10 16:14:39 +02:00
parent f8ed24684a
commit 3277b81850
8 changed files with 1110 additions and 938 deletions

96
app.py
View File

@ -23,6 +23,7 @@ app = Flask("GPT4All-WebUI", static_url_path="/static", static_folder="static")
import time import time
class Gpt4AllWebUI: class Gpt4AllWebUI:
def __init__(self, _app, args) -> None: def __init__(self, _app, args) -> None:
self.args = args self.args = args
self.current_discussion = None self.current_discussion = None
@ -67,6 +68,13 @@ class Gpt4AllWebUI:
self.add_endpoint( self.add_endpoint(
"/update_message", "update_message", self.update_message, methods=["GET"] "/update_message", "update_message", self.update_message, methods=["GET"]
) )
self.add_endpoint(
"/message_rank_up", "message_rank_up", self.message_rank_up, methods=["GET"]
)
self.add_endpoint(
"/message_rank_down", "message_rank_down", self.message_rank_down, methods=["GET"]
)
self.add_endpoint( self.add_endpoint(
"/update_model_params", "update_model_params", self.update_model_params, methods=["POST"] "/update_model_params", "update_model_params", self.update_model_params, methods=["POST"]
) )
@ -83,19 +91,8 @@ class Gpt4AllWebUI:
return jsonify(models) return jsonify(models)
def list_discussions(self): def list_discussions(self):
try: discussions = self.db.get_discussions()
discussions = self.db.get_discussions() return jsonify(discussions)
return jsonify(discussions)
except Exception as ex:
print(ex)
return jsonify({
"status":"Error",
"content": "<b style='color:red;'>Exception :<b>"
+ str(ex)
+ "<br>"
+ traceback.format_exc()
+ "<br>Please report exception"
})
def prepare_a_new_chatbot(self): def prepare_a_new_chatbot(self):
@ -117,6 +114,14 @@ Instruction: Act as GPT4All. A kind and helpful AI bot built to help users solve
GPT4All:Welcome! I'm here to assist you with anything you need. What can I do for you today?""" GPT4All:Welcome! I'm here to assist you with anything you need. What can I do for you today?"""
): ):
self.full_message += conditionning_message +"\n" self.full_message += conditionning_message +"\n"
if self.current_discussion is None or not self.db.does_last_discussion_have_messages():
self.current_discussion = self.db.create_discussion()
message_id = self.current_discussion.add_message(
"conditionner", conditionning_message, DiscussionsDB.MSG_TYPE_CONDITIONNING,0
)
# self.prepare_query(conditionning_message) # self.prepare_query(conditionning_message)
# self.chatbot_bindings.generate( # self.chatbot_bindings.generate(
@ -251,38 +256,27 @@ GPT4All:Welcome! I'm here to assist you with anything you need. What can I do fo
def bot(self): def bot(self):
self.stop = True self.stop = True
try: if self.current_discussion is None or not self.db.does_last_discussion_have_messages():
if self.current_discussion is None or not self.db.does_last_discussion_have_messages(): self.current_discussion = self.db.create_discussion()
self.current_discussion = self.db.create_discussion()
message_id = self.current_discussion.add_message( message_id = self.current_discussion.add_message(
"user", request.json["message"] "user", request.json["message"]
) )
message = f"{request.json['message']}" message = f"{request.json['message']}"
# Segmented (the user receives the output as it comes) # 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 # We will first send a json entry that contains the message id and so on, then the text as it goes
return Response( return Response(
stream_with_context( stream_with_context(
self.parse_to_prompt_stream(message, message_id) self.parse_to_prompt_stream(message, message_id)
)
) )
except Exception as ex: )
print(ex)
return (
"<b style='color:red;'>Exception :<b>"
+ str(ex)
+ "<br>"
+ traceback.format_exc()
+ "<br>Please report exception"
)
def rename(self): def rename(self):
data = request.get_json() data = request.get_json()
discussion_id = data["id"] discussion_id = data["id"]
title = data["title"] title = data["title"]
self.db.rename(self.db_path, discussion_id, title) self.current_discussion.rename(discussion_id, title)
return "renamed successfully" return "renamed successfully"
def restore_discussion(self, full_message): def restore_discussion(self, full_message):
@ -320,20 +314,20 @@ GPT4All:Welcome! I'm here to assist you with anything you need. What can I do fo
return jsonify({}) return jsonify({})
def update_message(self): def update_message(self):
try: discussion_id = request.args.get("id")
discussion_id = request.args.get("id") new_message = request.args.get("message")
new_message = request.args.get("message") self.current_discussion.update_message(discussion_id, new_message)
self.current_discussion.update_message(discussion_id, new_message) return jsonify({"status": "ok"})
return jsonify({"status": "ok"})
except Exception as ex: def message_rank_up(self):
print(ex) discussion_id = request.args.get("id")
return ( new_rank = self.current_discussion.message_rank_up(discussion_id)
"<b style='color:red;'>Exception :<b>" return jsonify({"new_rank": new_rank})
+ str(ex)
+ "<br>" def message_rank_down(self):
+ traceback.format_exc() discussion_id = request.args.get("id")
+ "<br>Please report exception" new_rank = self.current_discussion.message_rank_down(discussion_id)
) return jsonify({"new_rank": new_rank})
def new_discussion(self): def new_discussion(self):
title = request.args.get("title") title = request.args.get("title")

123
db.py
View File

@ -2,6 +2,9 @@
import sqlite3 import sqlite3
# =================================== Database ================================================================== # =================================== Database ==================================================================
class DiscussionsDB: class DiscussionsDB:
MSG_TYPE_NORMAL = 0
MSG_TYPE_CONDITIONNING = 1
def __init__(self, db_path="database.db"): def __init__(self, db_path="database.db"):
self.db_path = db_path self.db_path = db_path
@ -12,33 +15,75 @@ class DiscussionsDB:
print("Checking discussions database...") print("Checking discussions database...")
with sqlite3.connect(self.db_path) as conn: with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor() cursor = conn.cursor()
# Check if the 'schema_version' table exists
cursor.execute(""" cursor.execute("""
CREATE TABLE IF NOT EXISTS discussion ( CREATE TABLE IF NOT EXISTS schema_version (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT version INTEGER NOT NULL
)
""")
cursor.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)
)
"""
) )
""")
discussion_table_exist=False
message_table_exist=False
try:
cursor.execute("""
CREATE TABLE discussion (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT
)
""")
except:
discussion_table_exist=True
try:
cursor.execute("""
CREATE TABLE IF NOT EXISTS message (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sender TEXT NOT NULL,
content TEXT NOT NULL,
type INT NOT NULL,
rank INT NOT NULL,
discussion_id INTEGER NOT NULL,
FOREIGN KEY (discussion_id) REFERENCES discussion(id)
)
"""
)
except :
message_table_exist=True
# Get the current version from the schema_version table
cursor.execute("SELECT version FROM schema_version WHERE id = 1")
row = cursor.fetchone()
if row is None:
# If the table is empty, assume version 0
version = 0
else:
# Otherwise, use the version from the table
version = row[0]
# Upgrade the schema to version 1
if version < 1:
print("Upgrading schema to version 1...")
# Add the 'created_at' column to the 'message' table
if message_table_exist:
cursor.execute("ALTER TABLE message ADD COLUMN type INT DEFAULT 0")
cursor.execute("ALTER TABLE message ADD COLUMN rank INT DEFAULT 0")
# Update the schema version
cursor.execute("INSERT INTO schema_version (id, version) VALUES (1, 1)")
version = 1
conn.commit() conn.commit()
def select(self, query, fetch_all=True): def select(self, query, params=None, fetch_all=True):
""" """
Execute the specified SQL select query on the database, Execute the specified SQL select query on the database,
with optional parameters. with optional parameters.
Returns the cursor object for further processing. Returns the cursor object for further processing.
""" """
with sqlite3.connect(self.db_path) as conn: with sqlite3.connect(self.db_path) as conn:
cursor = conn.execute(query) if params is None:
cursor = conn.execute(query)
else:
cursor = conn.execute(query, params)
if fetch_all: if fetch_all:
return cursor.fetchall() return cursor.fetchall()
else: else:
@ -97,8 +142,7 @@ class DiscussionsDB:
return Discussion(discussion_id, self) return Discussion(discussion_id, self)
def get_discussions(self): def get_discussions(self):
rows = self.select("SELECT * FROM discussion") rows = self.select("SELECT * FROM discussion")
return [{"id": row[0], "title": row[1]} for row in rows] return [{"id": row[0], "title": row[1]} for row in rows]
def does_last_discussion_have_messages(self): def does_last_discussion_have_messages(self):
@ -130,7 +174,7 @@ class Discussion:
self.discussion_id = discussion_id self.discussion_id = discussion_id
self.discussions_db = discussions_db self.discussions_db = discussions_db
def add_message(self, sender, content): def add_message(self, sender, content, message_type=0, rank=0):
"""Adds a new message to the discussion """Adds a new message to the discussion
Args: Args:
@ -141,8 +185,8 @@ class Discussion:
int: The added message id int: The added message id
""" """
message_id = self.discussions_db.insert( message_id = self.discussions_db.insert(
"INSERT INTO message (sender, content, discussion_id) VALUES (?, ?, ?)", "INSERT INTO message (sender, content, type, rank, discussion_id) VALUES (?, ?, ?, ?, ?)",
(sender, content, self.discussion_id) (sender, content, message_type, rank, self.discussion_id)
) )
return message_id return message_id
@ -170,12 +214,12 @@ class Discussion:
"""Gets a list of messages information """Gets a list of messages information
Returns: Returns:
list: List of entries in the format {"sender":sender name, "content":message content,"id":message id} 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( rows = self.discussions_db.select(
f"SELECT * FROM message WHERE discussion_id={self.discussion_id}" f"SELECT * FROM message WHERE discussion_id={self.discussion_id}"
) )
return [{"sender": row[1], "content": row[2], "id": row[0]} for row in rows] return [{"id": row[0], "sender": row[1], "content": row[2], "type": row[3], "rank": row[4]} for row in rows]
def update_message(self, message_id, new_content): def update_message(self, message_id, new_content):
"""Updates the content of a message """Updates the content of a message
@ -187,6 +231,37 @@ class Discussion:
self.discussions_db.update( self.discussions_db.update(
f"UPDATE message SET content = ? WHERE id = ?",(new_content,message_id) f"UPDATE message SET content = ? WHERE id = ?",(new_content,message_id)
) )
def message_rank_up(self, message_id):
"""Increments the rank of the message
Args:
message_id (int): The id of the message to be changed
"""
# Retrieve current rank value for message_id
current_rank = self.discussions_db.select("SELECT rank FROM message WHERE id=?", (message_id,),False)[0]
# Increment current rank value by 1
new_rank = current_rank + 1
self.discussions_db.update(
f"UPDATE message SET rank = ? WHERE id = ?",(new_rank,message_id)
)
return new_rank
def message_rank_down(self, message_id):
"""Increments the rank of the message
Args:
message_id (int): The id of the message to be changed
"""
# Retrieve current rank value for message_id
current_rank = self.discussions_db.select("SELECT rank FROM message WHERE id=?", (message_id,),False)[0]
# Increment current rank value by 1
new_rank = current_rank - 1
self.discussions_db.update(
f"UPDATE message SET rank = ? WHERE id = ?",(new_rank,message_id)
)
return new_rank
# ======================================================================================================================== # ========================================================================================================================

View File

@ -1,788 +0,0 @@
/*
! tailwindcss v3.1.4 | MIT License | https://tailwindcss.com
*//*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box; /* 1 */
border-width: 0; /* 2 */
border-style: solid; /* 2 */
border-color: #e5e7eb; /* 2 */
}
::before,
::after {
--tw-content: '';
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
*/
html {
line-height: 1.5; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-moz-tab-size: 4; /* 3 */
-o-tab-size: 4;
tab-size: 4; /* 3 */
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0; /* 1 */
line-height: inherit; /* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0; /* 1 */
color: inherit; /* 2 */
border-top-width: 1px; /* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */
font-size: 1em; /* 2 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
border-collapse: collapse; /* 3 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
font-weight: inherit; /* 1 */
line-height: inherit; /* 1 */
color: inherit; /* 1 */
margin: 0; /* 2 */
padding: 0; /* 3 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button; /* 1 */
background-color: transparent; /* 2 */
background-image: none; /* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type='search'] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing and border for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/
input::-moz-placeholder, textarea::-moz-placeholder {
opacity: 1; /* 1 */
color: #9ca3af; /* 2 */
}
input:-ms-input-placeholder, textarea:-ms-input-placeholder {
opacity: 1; /* 1 */
color: #9ca3af; /* 2 */
}
input::placeholder,
textarea::placeholder {
opacity: 1; /* 1 */
color: #9ca3af; /* 2 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
*, ::before, ::after {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
::-webkit-backdrop {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
::backdrop {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
.mx-6 {
margin-left: 1.5rem;
margin-right: 1.5rem;
}
.my-4 {
margin-top: 1rem;
margin-bottom: 1rem;
}
.my-1 {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
.mx-1 {
margin-left: 0.25rem;
margin-right: 0.25rem;
}
.flex {
display: flex;
}
.h-screen {
height: 100vh;
}
.h-20 {
height: 5rem;
}
.h-12 {
height: 3rem;
}
.h-full {
height: 100%;
}
.max-h-full {
max-height: 100%;
}
.w-screen {
width: 100vw;
}
.w-full {
width: 100%;
}
.w-12 {
width: 3rem;
}
.flex-col {
flex-direction: column;
}
.items-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.space-y-0 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0px * var(--tw-space-y-reverse));
}
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse)));
}
.overflow-hidden {
overflow: hidden;
}
.overflow-y-auto {
overflow-y: auto;
}
.rounded-md {
border-radius: 0.375rem;
}
.border-b {
border-bottom-width: 1px;
}
.border-t {
border-top-width: 1px;
}
.border-accent {
border-color: var(--accent);
}
.bg-primary {
background-color: var(--primary);
}
.bg-tertiary {
background-color: var(--tertiary);
}
.bg-secondary {
background-color: var(--secondary);
}
.bg-accent {
background-color: var(--accent);
}
.p-4 {
padding: 1rem;
}
.p-2 {
padding: 0.5rem;
}
.px-6 {
padding-left: 1.5rem;
padding-right: 1.5rem;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.font-bold {
font-weight: 700;
}
.font-normal {
font-weight: 400;
}
.font-medium {
font-weight: 500;
}
.text-gray-400 {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.text-black {
--tw-text-opacity: 1;
color: rgb(0 0 0 / var(--tw-text-opacity));
}
.underline {
-webkit-text-decoration-line: underline;
text-decoration-line: underline;
}
.outline-none {
outline: 2px solid transparent;
outline-offset: 2px;
}
.drop-shadow-sm {
--tw-drop-shadow: drop-shadow(0 1px 1px rgb(0 0 0 / 0.05));
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.transition-colors {
transition-property: color, background-color, border-color, fill, stroke, -webkit-text-decoration-color;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, -webkit-text-decoration-color;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.ease-in-out {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
:root {
--primary: #1a1d21;
--secondary: #212529;
--teriary: #23282c;
--accent: #6691e7;
}
.hover\:bg-\[\#7ba0ea\]:hover {
--tw-bg-opacity: 1;
background-color: rgb(123 160 234 / var(--tw-bg-opacity));
}
.active\:bg-\[\#3d73e1\]:active {
--tw-bg-opacity: 1;
background-color: rgb(61 115 225 / var(--tw-bg-opacity));
}
@media (min-width: 640px) {
.sm\:space-x-reverse > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 1;
}
.sm\:border-b {
border-bottom-width: 1px;
}
}
@media (min-width: 768px) {
.md\:h-1\/2 {
height: 50%;
}
.md\:w-1\/3 {
width: 33.333333%;
}
.md\:flex-row {
flex-direction: row;
}
.md\:flex-col {
flex-direction: column;
}
.md\:border-r {
border-right-width: 1px;
}
.md\:border-b-0 {
border-bottom-width: 0px;
}
.md\:border-b {
border-bottom-width: 1px;
}
}
@media (min-width: 1024px) {
.lg\:w-1\/4 {
width: 25%;
}
}
@media (min-width: 1280px) {
.xl\:w-1\/5 {
width: 20%;
}
}
.collapsible-header {
cursor: pointer;
}
.collapsible-content {
display: none;
}
/* Wait animation */
.lds-facebook {
display: inline-block;
position: relative;
width: 40px;
height: 40px;
}
.lds-facebook div {
display: inline-block;
position: absolute;
left: 8px;
width: 8px;
background: #fff;
animation: lds-facebook 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite;
}
.lds-facebook div:nth-child(1) {
left: 4px;
animation-delay: -0.24s;
}
.lds-facebook div:nth-child(2) {
left: 16px;
animation-delay: -0.12s;
}
.lds-facebook div:nth-child(3) {
left: 28px;
animation-delay: 0;
}
@keyframes lds-facebook {
0% {
top: 8px;
height: 34px;
}
50%, 100% {
top: 12px;
height: 18px;
}
}

788
static/css/tailwindcss.css Normal file
View File

@ -0,0 +1,788 @@
/*
! tailwindcss v3.1.4 | MIT License | https://tailwindcss.com
*//*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box; /* 1 */
border-width: 0; /* 2 */
border-style: solid; /* 2 */
border-color: #e5e7eb; /* 2 */
}
::before,
::after {
--tw-content: '';
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
*/
html {
line-height: 1.5; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-moz-tab-size: 4; /* 3 */
-o-tab-size: 4;
tab-size: 4; /* 3 */
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0; /* 1 */
line-height: inherit; /* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0; /* 1 */
color: inherit; /* 2 */
border-top-width: 1px; /* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */
font-size: 1em; /* 2 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
border-collapse: collapse; /* 3 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
font-weight: inherit; /* 1 */
line-height: inherit; /* 1 */
color: inherit; /* 1 */
margin: 0; /* 2 */
padding: 0; /* 3 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button; /* 1 */
background-color: transparent; /* 2 */
background-image: none; /* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type='search'] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing and border for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/
input::-moz-placeholder, textarea::-moz-placeholder {
opacity: 1; /* 1 */
color: #9ca3af; /* 2 */
}
input:-ms-input-placeholder, textarea:-ms-input-placeholder {
opacity: 1; /* 1 */
color: #9ca3af; /* 2 */
}
input::placeholder,
textarea::placeholder {
opacity: 1; /* 1 */
color: #9ca3af; /* 2 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
*, ::before, ::after {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
::-webkit-backdrop {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
::backdrop {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
.mx-6 {
margin-left: 1.5rem;
margin-right: 1.5rem;
}
.my-4 {
margin-top: 1rem;
margin-bottom: 1rem;
}
.my-1 {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
.mx-1 {
margin-left: 0.25rem;
margin-right: 0.25rem;
}
.flex {
display: flex;
}
.h-screen {
height: 100vh;
}
.h-20 {
height: 5rem;
}
.h-12 {
height: 3rem;
}
.h-full {
height: 100%;
}
.max-h-full {
max-height: 100%;
}
.w-screen {
width: 100vw;
}
.w-full {
width: 100%;
}
.w-12 {
width: 3rem;
}
.flex-col {
flex-direction: column;
}
.items-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.space-y-0 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0px * var(--tw-space-y-reverse));
}
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse)));
}
.overflow-hidden {
overflow: hidden;
}
.overflow-y-auto {
overflow-y: auto;
}
.rounded-md {
border-radius: 0.375rem;
}
.border-b {
border-bottom-width: 1px;
}
.border-t {
border-top-width: 1px;
}
.border-accent {
border-color: var(--accent);
}
.bg-primary {
background-color: var(--primary);
}
.bg-tertiary {
background-color: var(--tertiary);
}
.bg-secondary {
background-color: var(--secondary);
}
.bg-accent {
background-color: var(--accent);
}
.p-4 {
padding: 1rem;
}
.p-2 {
padding: 0.5rem;
}
.px-6 {
padding-left: 1.5rem;
padding-right: 1.5rem;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.font-bold {
font-weight: 700;
}
.font-normal {
font-weight: 400;
}
.font-medium {
font-weight: 500;
}
.text-gray-400 {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.text-black {
--tw-text-opacity: 1;
color: rgb(0 0 0 / var(--tw-text-opacity));
}
.underline {
-webkit-text-decoration-line: underline;
text-decoration-line: underline;
}
.outline-none {
outline: 2px solid transparent;
outline-offset: 2px;
}
.drop-shadow-sm {
--tw-drop-shadow: drop-shadow(0 1px 1px rgb(0 0 0 / 0.05));
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.transition-colors {
transition-property: color, background-color, border-color, fill, stroke, -webkit-text-decoration-color;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, -webkit-text-decoration-color;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.ease-in-out {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
:root {
--primary: #1a1d21;
--secondary: #212529;
--teriary: #23282c;
--accent: #6691e7;
}
.hover\:bg-\[\#7ba0ea\]:hover {
--tw-bg-opacity: 1;
background-color: rgb(123 160 234 / var(--tw-bg-opacity));
}
.active\:bg-\[\#3d73e1\]:active {
--tw-bg-opacity: 1;
background-color: rgb(61 115 225 / var(--tw-bg-opacity));
}
@media (min-width: 640px) {
.sm\:space-x-reverse > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 1;
}
.sm\:border-b {
border-bottom-width: 1px;
}
}
@media (min-width: 768px) {
.md\:h-1\/2 {
height: 50%;
}
.md\:w-1\/3 {
width: 33.333333%;
}
.md\:flex-row {
flex-direction: row;
}
.md\:flex-col {
flex-direction: column;
}
.md\:border-r {
border-right-width: 1px;
}
.md\:border-b-0 {
border-bottom-width: 0px;
}
.md\:border-b {
border-bottom-width: 1px;
}
}
@media (min-width: 1024px) {
.lg\:w-1\/4 {
width: 25%;
}
}
@media (min-width: 1280px) {
.xl\:w-1\/5 {
width: 20%;
}
}
.collapsible-header {
cursor: pointer;
}
.collapsible-content {
display: none;
}
/* Wait animation */
.lds-facebook {
display: inline-block;
position: relative;
width: 40px;
height: 40px;
}
.lds-facebook div {
display: inline-block;
position: absolute;
left: 8px;
width: 8px;
background: #fff;
animation: lds-facebook 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite;
}
.lds-facebook div:nth-child(1) {
left: 4px;
animation-delay: -0.24s;
}
.lds-facebook div:nth-child(2) {
left: 16px;
animation-delay: -0.12s;
}
.lds-facebook div:nth-child(3) {
left: 28px;
animation-delay: 0;
}
@keyframes lds-facebook {
0% {
top: 8px;
height: 34px;
}
50%, 100% {
top: 12px;
height: 18px;
}
}

View File

@ -55,8 +55,8 @@ chatForm.addEventListener('submit', event => {
{ {
// We parse it and // We parse it and
infos = JSON.parse(text) infos = JSON.parse(text)
addMessage('User', infos.message, infos.id, true); addMessage('User', infos.message, infos.id, can_edit=true);
elements = addMessage('GPT4ALL', '', infos.response_id, true); elements = addMessage('GPT4ALL', '', infos.response_id, can_edit=true);
messageTextElement=elements['messageTextElement']; messageTextElement=elements['messageTextElement'];
hiddenElement=elements['hiddenElement']; hiddenElement=elements['hiddenElement'];
entry_counter ++; entry_counter ++;
@ -86,7 +86,7 @@ chatForm.addEventListener('submit', event => {
}); });
function addMessage(sender, message, id, can_edit=false) { function addMessage(sender, message, id, rank=0, can_edit=false) {
console.log(id) console.log(id)
const messageElement = document.createElement('div'); 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('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');
@ -166,8 +166,69 @@ function addMessage(sender, message, id, can_edit=false) {
inputField.focus(); inputField.focus();
}); });
const rank_up = document.createElement('button');
rank_up.classList.add('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');
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})`
}
})
.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-black','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(editButton);
buttonsContainer.appendChild(rank_up);
buttonsContainer.appendChild(rank_down);
messageElement.appendChild(buttonsContainer); 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(messageElement);
chatWindow.appendChild(hiddenElement); chatWindow.appendChild(hiddenElement);

View File

@ -132,7 +132,9 @@ function populate_discussions_list()
var container = document.getElementById('chat-window'); var container = document.getElementById('chat-window');
container.innerHTML = ''; container.innerHTML = '';
messages.forEach(message => { messages.forEach(message => {
addMessage(message.sender, message.content, message.id, true); if(message.type==0){
addMessage(message.sender, message.content, message.id, message.rank, true);
}
}); });
}); });
} else { } else {
@ -181,17 +183,22 @@ exportDiscussionButton.style.float = 'right'; // set the float property to right
exportDiscussionButton.style.display='inline-block' exportDiscussionButton.style.display='inline-block'
exportDiscussionButton.innerHTML = 'Export discussion to text'; exportDiscussionButton.innerHTML = 'Export discussion to text';
exportDiscussionButton.addEventListener('click', () => { exportDiscussionButton.addEventListener('click', () => {
fetch('/bot', { fetch(`/export_discussion`)
method: 'POST', .then(response => response.text())
headers: { .then(data => {
'Content-Type': 'application/json' const filename = window.prompt('Please enter a filename:', 'discussion.txt');
}, if (filename !== null) {
body: JSON.stringify({ message }) const blob = new Blob([data], { type: 'text/plain' });
}).then(function(response) { const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.click();
URL.revokeObjectURL(url);
}
}).catch(function(error){
}).catch(function(error){ });
});
}); });
const actionBtns = document.querySelector('#action-buttons'); const actionBtns = document.querySelector('#action-buttons');
actionBtns.appendChild(exportDiscussionButton); actionBtns.appendChild(exportDiscussionButton);

23
static/js/tabs.js Normal file
View File

@ -0,0 +1,23 @@
function showTab(tabId) {
// hide all tabs
var tabs = document.getElementsByClassName('tab-pane');
for (var i = 0; i < tabs.length; i++) {
tabs[i].style.display = 'none';
}
// show the selected tab
console.log(tabId)
var tab = document.getElementById(tabId);
tab.style.display = 'block';
}
// show the main tab by default
showTab('main');
// add event listeners to the tab links
var tabLinks = document.getElementsByTagName('a');
for (var i = 0; i < tabLinks.length; i++) {
tabLinks[i].addEventListener('click', function(event) {
event.preventDefault();
var tabId = this.getAttribute('href').substring(1);
showTab(tabId);
});
}

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>GPT4All - WEBUI</title> <title>GPT4All - WEBUI</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/tailwindcss.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/chat.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/chat.css') }}">
</head> </head>
<body class="w-screen h-screen bg-primary text-gray-400 flex flex-col overflow-hidden"> <body class="w-screen h-screen bg-primary text-gray-400 flex flex-col overflow-hidden">
@ -10,71 +11,81 @@
<div class="w-12 h-12"><img src="{{ url_for('static', filename='images/icon.png') }}"></div> <div class="w-12 h-12"><img src="{{ url_for('static', filename='images/icon.png') }}"></div>
<h1>GPT4All - WEBUI</h1> <h1>GPT4All - WEBUI</h1>
</div> </div>
<main class="h-full flex flex-col md:flex-row overflow-hidden max-h-full"> <div class="border-b border-gray-200">
<section class="w-full md:w-1/3 lg:w-1/4 xl:w-1/5 bg-secondary flex md:flex-col md:border-r border-accent sm:border-b md:border-b-0"> <ul class="flex border-b border-gray-200">
<section class="md:h-1/2 md:border-b border-accent flex flex md:flex-col"> <li class="mr-1">
<div> <a href="#main" class="bg-gray-100 text-gray-700 py-2 px-4 rounded-t-md font-medium hover:text-gray-900">Main</a>
<h1>Discussions</h1> </li>
</div> <li class="mr-1">
<div id="discussions-list" class="h-96 overflow-y-auto"> <a href="#settings" class="bg-gray-100 text-gray-700 py-2 px-4 rounded-t-md font-medium hover:text-gray-900">Settings</a>
</li>
</ul>
</div>
<div id="main" class="tab-pane h-full flex flex-row md:flex-row overflow-hidden max-h-full">
<div class="w-1/3 bg-gray-200 flex flex-row border-r border-gray-400 h-full">
<div class="w-1/3 bg-gray-200 flex flex-col border-r border-gray-400 h-full">
<section class="md:h-1/2 md:border-b border-accent flex flex md:flex-col h-full">
<div>
<h1>Discussions</h1>
</div>
<div id="discussions-list" class="h-96 overflow-y-auto h-full">
</div>
<div id="action-buttons" class="h-96 overflow-y-auto">
<input type="button" value="New Discussion" id="new-discussion-btn" 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">
<input type="button" value="Export" id="export-button" 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>
</section>
<section class="md:h-1/2 md:border-b border-accent flex flex md:flex-col">
<div>
<p>Settings</p>
</div>
<div class="h-96 overflow-y-auto">
<form id="model-params-form" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="model">Model</label>
<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">
<label class="block text-gray-700 font-bold mb-2" for="seed">Seed</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="seed" type="text" name="seed" value="0">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="temp">Temperature</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="temp" type="range" min="0" max="1" step="0.1" value="0.1" name="temp">
<p id="slider-value">0.1</p>
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="n-predict">N Predict</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="n-predict" type="range" min="0" max="2048" step="1" value="256" name="n-predict">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="top-k">Top K</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="top-k" type="range" min="0" max="100" step="1" value="40" name="top-k">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="top-p">Top P</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="top-p" type="range" min="0" max="100" step="1" value="40" name="top-p">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="repeat-penalty">Repeat penalty</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="repeat-penalty" type="range" min="0" max="100" step="1" value="40" name="repeat-penalty">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="repeat-last-n">Repeat penalty</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" 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 text-black rounded-md hover:bg-[#7ba0ea] active:bg-[#3d73e1] transition-colors ease-in-out">Update parameters</button>
</div>
</form>
</div>
</section> </section>
</section> <section id="action-buttons" class="md:border-b border-accent flex flex md:flex-col">
<section id="chat-window" class="w-full overflow-y-auto flex flex-col"> <input type="button" value="New Discussion" id="new-discussion-btn" 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">
<input type="button" value="Export" id="export-button" 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">
</section>
</div>
<div id="chat-window" class="w-2/3 overflow-y-auto flex flex-col max-h-full">
</div>
</div>
</div>
<div class="tab-pane" id="settings">
<div class="h-96 overflow-y-auto">
<form id="model-params-form" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="model">Model</label>
<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 class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="seed">Seed</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="seed" type="text" name="seed" value="0">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="temp">Temperature</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="temp" type="range" min="0" max="1" step="0.1" value="0.1" name="temp">
<p id="slider-value">0.1</p>
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="n-predict">N Predict</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="n-predict" type="range" min="0" max="2048" step="1" value="256" name="n-predict">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="top-k">Top K</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="top-k" type="range" min="0" max="100" step="1" value="40" name="top-k">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="top-p">Top P</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="top-p" type="range" min="0" max="100" step="1" value="40" name="top-p">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="repeat-penalty">Repeat penalty</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" id="repeat-penalty" type="range" min="0" max="100" step="1" value="40" name="repeat-penalty">
</div>
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2" for="repeat-last-n">Repeat penalty</label>
<input class="bg-gray-700 slider absolute top-0 w-full h-full opacity-0" 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 text-black rounded-md hover:bg-[#7ba0ea] active:bg-[#3d73e1] transition-colors ease-in-out">Update parameters</button>
</div>
</form>
</div>
</div>
</section>
</main>
<footer class="border-t border-accent flex"> <footer class="border-t border-accent flex">
<form id="chat-form" class="flex w-full"> <form id="chat-form" class="flex w-full">
<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="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">
@ -87,6 +98,7 @@
<script src="{{ url_for('static', filename='js/discussions.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/settings.js') }}"></script>
<script src="{{ url_for('static', filename='js/db_export.js') }}"></script> <script src="{{ url_for('static', filename='js/db_export.js') }}"></script>
<script src="{{ url_for('static', filename='js/tabs.js') }}"></script>
</body> </body>
</html> </html>