V6.7 is here

This commit is contained in:
Saifeddine ALOUI 2023-10-10 01:47:49 +02:00
parent f42382c679
commit 8376b05ceb
19 changed files with 965 additions and 797 deletions

View File

@ -20,7 +20,7 @@ from lollms.paths import LollmsPaths
from lollms.helpers import ASCIIColors, trace_exception
from lollms.app import LollmsApplication
from lollms.utilities import File64BitsManager, PromptReshaper
from safe_store import TextVectorizer, VectorizationMethod
from safe_store import TextVectorizer, VectorizationMethod, VisualizationMethod
import threading
from tqdm import tqdm
import traceback
@ -115,6 +115,10 @@ class LoLLMsAPPI(LollmsApplication):
def __init__(self, config:LOLLMSConfig, socketio, config_file_path:str, lollms_paths: LollmsPaths) -> None:
super().__init__("Lollms_webui",config, lollms_paths, callback=self.process_chunk)
self.busy = False
self.nb_received_tokens = 0
@ -123,7 +127,6 @@ class LoLLMsAPPI(LollmsApplication):
self.cancel_gen = False
self.discussion_store = None
# Keeping track of current discussion and message
self._current_user_message_id = 0
@ -144,6 +147,39 @@ class LoLLMsAPPI(LollmsApplication):
self.db.add_missing_columns()
ASCIIColors.success("ok")
# prepare vectorization
if self.config.data_vectorization_activate and self.config.use_discussions_history:
try:
ASCIIColors.yellow("Loading vectorized discussions")
folder = self.lollms_paths.personal_databases_path/"vectorized_dbs"
folder.mkdir(parents=True, exist_ok=True)
self.discussions_store = TextVectorizer(
vectorization_method=VectorizationMethod.TFIDF_VECTORIZER,#=VectorizationMethod.BM25_VECTORIZER,
database_path=folder/self.config.db_path,
data_visualization_method=VisualizationMethod.PCA,#VisualizationMethod.PCA,
save_db=True
)
ASCIIColors.yellow("1- Exporting discussions")
discussions = self.db.export_all_as_markdown_list_for_vectorization()
ASCIIColors.yellow("2- Adding discussions to vectorizer")
for (title,discussion) in discussions:
if discussion!='':
self.discussions_store.add_document(title, discussion, chunk_size=self.config.data_vectorization_chunk_size, overlap_size=self.config.data_vectorization_overlap_size, force_vectorize=False, add_as_a_bloc=False)
ASCIIColors.yellow("3- Indexing database")
self.discussions_store.index()
ASCIIColors.yellow("3- Saving database")
self.discussions_store.save_to_json()
ASCIIColors.yellow("Ready")
except Exception as ex:
trace_exception(ex)
self.discussions_store = None
else:
self.discussions_store = None
# This is used to keep track of messages
self.download_infos={}
@ -1161,21 +1197,11 @@ class LoLLMsAPPI(LollmsApplication):
str_docs = ""
if self.config.use_discussions_history:
if self.discussion_store is None:
self.discussion_store = TextVectorizer(self.config.data_vectorization_method, # supported "model_embedding" or "tfidf_vectorizer"
model=self.model, #needed in case of using model_embedding
database_path=self.lollms_paths.personal_databases_path/"discussionsdb.json",
save_db=self.config.data_vectorization_save_db,
data_visualization_method=VectorizationMethod.PCA,
database_dict=None)
corpus = self.db.export_all_as_markdown()
self.discussion_store.add_document("discussions", corpus, self.config.data_vectorization_chunk_size, self.config.data_vectorization_overlap_size )
pr = PromptReshaper("{{conditionning}}\n!@>document chunks:\n{{doc}}\n{{content}}")
emb = self.discussion_store.embed_query(message.content)
docs, sorted_similarities = self.discussion_store.recover_text(emb, top_k=self.config.data_vectorization_nb_chunks)
for doc, infos in zip(docs, sorted_similarities):
str_docs+=f"document chunk:\nchunk path: {infos[0]}\nchunk content:{doc}"
if self.discussions_store is not None:
pr = PromptReshaper("{{conditionning}}\n!@>document chunks:\n{{doc}}\n{{content}}")
docs, sorted_similarities = self.discussions_store.recover_text(message.content, top_k=self.config.data_vectorization_nb_chunks)
for doc, infos in zip(docs, sorted_similarities):
str_docs+=f"discussion chunk:\ndiscussion title: {infos[0]}\nchunk content:{doc}"
if len(self.personality.files)>0 and self.personality.vectorizer:

View File

@ -249,6 +249,25 @@ class DiscussionsDB:
)
discussions.append(discussion)
return discussions
def export_all_as_markdown_list_for_vectorization(self):
data = self.export_all_discussions_to_json()
# Initialize an empty result string
discussions = []
# Iterate through discussions in the JSON data
for discussion in data:
# Extract the title
title = discussion['title']
messages = ""
# Iterate through messages in the discussion
for message in discussion['messages']:
sender = message['sender']
content = message['content']
# Append the sender and content in a Markdown format
messages += f'{sender}: {content}\n'
discussions.append([title, messages])
return discussions
def export_all_as_markdown(self):
data = self.export_all_discussions_to_json()

76
app.py
View File

@ -14,7 +14,7 @@ __github__ = "https://github.com/ParisNeo/lollms-webui"
__copyright__ = "Copyright 2023, "
__license__ = "Apache 2.0"
__version__ ="6.7Beta1"
__version__ ="6.7"
main_repo = "https://github.com/ParisNeo/lollms-webui.git"
import os
@ -89,6 +89,7 @@ try:
import shutil
import socket
from api.db import DiscussionsDB, Discussion
from safe_store import TextVectorizer, VectorizationMethod, VisualizationMethod
except Exception as ex:
trace_exception(ex)
@ -302,9 +303,6 @@ class LoLLMsWebUI(LoLLMsAPPI):
self.add_endpoint(
"/list_bindings", "list_bindings", self.list_bindings, methods=["GET"]
)
self.add_endpoint(
"/list_extensions", "list_extensions", self.list_extensions, methods=["GET"]
)
self.add_endpoint(
"/list_models", "list_models", self.list_models, methods=["GET"]
@ -345,6 +343,7 @@ class LoLLMsWebUI(LoLLMsAPPI):
self.add_endpoint("/user_infos/<path:filename>", "serve_user_infos", self.serve_user_infos, methods=["GET"])
self.add_endpoint("/images/<path:filename>", "serve_images", self.serve_images, methods=["GET"])
self.add_endpoint("/extensions/<path:filename>", "serve_extensions", self.serve_extensions, methods=["GET"])
self.add_endpoint("/bindings/<path:filename>", "serve_bindings", self.serve_bindings, methods=["GET"])
self.add_endpoint("/personalities/<path:filename>", "serve_personalities", self.serve_personalities, methods=["GET"])
self.add_endpoint("/outputs/<path:filename>", "serve_outputs", self.serve_outputs, methods=["GET"])
@ -887,8 +886,31 @@ class LoLLMsWebUI(LoLLMsAPPI):
self.rebuild_personalities()
if self.config.auto_save:
self.config.save_config()
if self.config.data_vectorization_activate and self.config.use_discussions_history:
ASCIIColors.yellow("0- Detected discussion vectorization request")
folder = self.lollms_paths.personal_databases_path/"vectorized_dbs"
folder.mkdir(parents=True, exist_ok=True)
self.discussions_store = TextVectorizer(
vectorization_method=VectorizationMethod.TFIDF_VECTORIZER,#=VectorizationMethod.BM25_VECTORIZER,
database_path=folder/self.config.db_path,
data_visualization_method=VisualizationMethod.PCA,#VisualizationMethod.PCA,
save_db=True
)
ASCIIColors.yellow("1- Exporting discussions")
discussions = self.db.export_all_as_markdown_list_for_vectorization()
ASCIIColors.yellow("2- Adding discussions to vectorizer")
for (title,discussion) in discussions:
if discussion!='':
self.discussions_store.add_document(title, discussion, chunk_size=self.config.data_vectorization_chunk_size, overlap_size=self.config.data_vectorization_overlap_size, force_vectorize=False, add_as_a_bloc=False)
ASCIIColors.yellow("3- Indexing database")
self.discussions_store.index()
ASCIIColors.yellow("3- Saving database")
self.discussions_store.save_to_json()
ASCIIColors.yellow("Ready")
return jsonify({"status":True})
except Exception as ex:
except Exception as ex:
trace_exception(ex)
return jsonify({"status":False,"error":str(ex)})
@ -1160,6 +1182,26 @@ class LoLLMsWebUI(LoLLMsAPPI):
if self.config.auto_save:
self.config.save_config()
if self.config.data_vectorization_activate and self.config.use_discussions_history:
ASCIIColors.yellow("0- Detected discussion vectorization request")
folder = self.lollms_paths.personal_databases_path/"vectorized_dbs"
folder.mkdir(parents=True, exist_ok=True)
self.discussions_store = TextVectorizer(
vectorization_method=VectorizationMethod.TFIDF_VECTORIZER,#=VectorizationMethod.BM25_VECTORIZER,
database_path=folder/self.config.db_path,
data_visualization_method=VisualizationMethod.PCA,#VisualizationMethod.PCA,
save_db=True
)
ASCIIColors.yellow("1- Exporting discussions")
discussions = self.db.export_all_as_markdown_list_for_vectorization()
ASCIIColors.yellow("2- Adding discussions to vectorizer")
for (title,discussion) in discussions:
self.discussions_store.add_document(title, discussion, chunk_size=self.config.data_vectorization_chunk_size, overlap_size=self.config.data_vectorization_overlap_size, force_vectorize=False, add_as_a_bloc=False)
ASCIIColors.yellow("3- Indexing database")
self.discussions_store.index()
ASCIIColors.yellow("Ready")
return jsonify({"status":True})
@ -1213,6 +1255,14 @@ class LoLLMsWebUI(LoLLMsAPPI):
fn = filename.split("/")[-1]
return send_from_directory(path, fn)
def serve_extensions(self, filename):
path = str(self.lollms_paths.extensions_zoo_path/("/".join(filename.split("/")[:-1])))
fn = filename.split("/")[-1]
return send_from_directory(path, fn)
def serve_bindings(self, filename):
path = str(self.lollms_paths.bindings_zoo_path/("/".join(filename.split("/")[:-1])))
@ -1398,15 +1448,17 @@ class LoLLMsWebUI(LoLLMsAPPI):
try:
ASCIIColors.info("Unmounting binding and model")
self.binding = None
self.model = None
for per in self.mounted_personalities:
per.model = None
gc.collect()
ASCIIColors.info("Reinstalling binding")
old_bn = self.config.binding_name
self.config.binding_name = data['name']
self.binding = BindingBuilder().build_binding(self.config, self.lollms_paths, InstallOption.FORCE_INSTALL)
ASCIIColors.success("Binding reinstalled successfully")
ASCIIColors.info("Please select a model")
self.config.binding_name = old_bn
self.binding = BindingBuilder().build_binding(self.config, self.lollms_paths)
self.model = self.binding.build_model()
for per in self.mounted_personalities:
per.model = self.model
return jsonify({"status": True})
except Exception as ex:
ASCIIColors.error(f"Couldn't build binding: [{ex}]")
@ -1856,9 +1908,7 @@ class LoLLMsWebUI(LoLLMsAPPI):
else:
pth = str(config_file).replace('\\','/')
ASCIIColors.error(f"nok : Extension not found @ {pth}")
ASCIIColors.yellow(f"Available personalities: {[p.name for p in self.mounted_personalities]}")
return jsonify({"status": False, "error":f"Personality not found @ {pth}"})
return jsonify({"status": False, "error":f"Extension not found @ {pth}"})

8
web/dist/assets/index-1e952553.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

213
web/dist/assets/index-b30b467a.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -10,4 +10,4 @@ pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5p
Updated for @stackoverflow/stacks v0.64.0
Code Blocks: /blob/v0.64.0/lib/css/components/_stacks-code-blocks.less
Colors: /blob/v0.64.0/lib/css/exports/_stacks-constants-colors.less
*/.hljs{color:#fff;background:#1c1b1b}.hljs-subst{color:#fff}.hljs-comment{color:#999}.hljs-attr,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-section,.hljs-selector-tag{color:#88aece}.hljs-attribute{color:#c59bc1}.hljs-name,.hljs-number,.hljs-quote,.hljs-selector-id,.hljs-template-tag,.hljs-type{color:#f08d49}.hljs-selector-class{color:#88aece}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-string,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#b5bd68}.hljs-meta,.hljs-selector-pseudo{color:#88aece}.hljs-built_in,.hljs-literal,.hljs-title{color:#f08d49}.hljs-bullet,.hljs-code{color:#ccc}.hljs-meta .hljs-string{color:#b5bd68}.hljs-deletion{color:#de7176}.hljs-addition{color:#76c490}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
*/.hljs{color:#fff;background:#1c1b1b}.hljs-subst{color:#fff}.hljs-comment{color:#999}.hljs-keyword,.hljs-selector-tag,.hljs-meta .hljs-keyword,.hljs-doctag,.hljs-section,.hljs-attr{color:#88aece}.hljs-attribute{color:#c59bc1}.hljs-name,.hljs-type,.hljs-number,.hljs-selector-id,.hljs-quote,.hljs-template-tag{color:#f08d49}.hljs-selector-class{color:#88aece}.hljs-string,.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr{color:#b5bd68}.hljs-meta,.hljs-selector-pseudo{color:#88aece}.hljs-built_in,.hljs-title,.hljs-literal{color:#f08d49}.hljs-bullet,.hljs-code{color:#ccc}.hljs-meta .hljs-string{color:#b5bd68}.hljs-deletion{color:#de7176}.hljs-addition{color:#76c490}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

View File

@ -10,4 +10,4 @@ pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5p
Updated for @stackoverflow/stacks v0.64.0
Code Blocks: /blob/v0.64.0/lib/css/components/_stacks-code-blocks.less
Colors: /blob/v0.64.0/lib/css/exports/_stacks-constants-colors.less
*/.hljs{color:#2f3337;background:#f6f6f6}.hljs-subst{color:#2f3337}.hljs-comment{color:#656e77}.hljs-attr,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-section,.hljs-selector-tag{color:#015692}.hljs-attribute{color:#803378}.hljs-name,.hljs-number,.hljs-quote,.hljs-selector-id,.hljs-template-tag,.hljs-type{color:#b75501}.hljs-selector-class{color:#015692}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-string,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#54790d}.hljs-meta,.hljs-selector-pseudo{color:#015692}.hljs-built_in,.hljs-literal,.hljs-title{color:#b75501}.hljs-bullet,.hljs-code{color:#535a60}.hljs-meta .hljs-string{color:#54790d}.hljs-deletion{color:#c02d2e}.hljs-addition{color:#2f6f44}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
*/.hljs{color:#2f3337;background:#f6f6f6}.hljs-subst{color:#2f3337}.hljs-comment{color:#656e77}.hljs-keyword,.hljs-selector-tag,.hljs-meta .hljs-keyword,.hljs-doctag,.hljs-section,.hljs-attr{color:#015692}.hljs-attribute{color:#803378}.hljs-name,.hljs-type,.hljs-number,.hljs-selector-id,.hljs-quote,.hljs-template-tag{color:#b75501}.hljs-selector-class{color:#015692}.hljs-string,.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr{color:#54790d}.hljs-meta,.hljs-selector-pseudo{color:#015692}.hljs-built_in,.hljs-title,.hljs-literal{color:#b75501}.hljs-bullet,.hljs-code{color:#535a60}.hljs-meta .hljs-string{color:#54790d}.hljs-deletion{color:#c02d2e}.hljs-addition{color:#2f6f44}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

View File

@ -1,8 +0,0 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: Tokyo-night-Dark
origin: https://github.com/enkia/tokyo-night-vscode-theme
Description: Original highlight.js style
Author: (c) Henri Vandersleyen <hvandersleyen@gmail.com>
License: see project LICENSE
Touched: 2022
*/.hljs-comment,.hljs-meta{color:#565f89}.hljs-deletion,.hljs-doctag,.hljs-regexp,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-tag,.hljs-template-tag,.hljs-variable.language_{color:#f7768e}.hljs-link,.hljs-literal,.hljs-number,.hljs-params,.hljs-template-variable,.hljs-type,.hljs-variable{color:#ff9e64}.hljs-attribute,.hljs-built_in{color:#e0af68}.hljs-keyword,.hljs-property,.hljs-subst,.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#7dcfff}.hljs-selector-tag{color:#73daca}.hljs-addition,.hljs-bullet,.hljs-quote,.hljs-string,.hljs-symbol{color:#9ece6a}.hljs-code,.hljs-formula,.hljs-section{color:#7aa2f7}.hljs-attr,.hljs-char.escape_,.hljs-keyword,.hljs-name,.hljs-operator{color:#bb9af7}.hljs-punctuation{color:#c0caf5}.hljs{background:#1a1b26;color:#9aa5ce}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

View File

@ -0,0 +1,8 @@
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
Theme: Tokyo-night-Dark
origin: https://github.com/enkia/tokyo-night-vscode-theme
Description: Original highlight.js style
Author: (c) Henri Vandersleyen <hvandersleyen@gmail.com>
License: see project LICENSE
Touched: 2022
*/.hljs-meta,.hljs-comment{color:#565f89}.hljs-tag,.hljs-doctag,.hljs-selector-id,.hljs-selector-class,.hljs-regexp,.hljs-template-tag,.hljs-selector-pseudo,.hljs-selector-attr,.hljs-variable.language_,.hljs-deletion{color:#f7768e}.hljs-variable,.hljs-template-variable,.hljs-number,.hljs-literal,.hljs-type,.hljs-params,.hljs-link{color:#ff9e64}.hljs-built_in,.hljs-attribute{color:#e0af68}.hljs-selector-tag{color:#2ac3de}.hljs-keyword,.hljs-title.function_,.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-subst,.hljs-property{color:#7dcfff}.hljs-selector-tag{color:#73daca}.hljs-quote,.hljs-string,.hljs-symbol,.hljs-bullet,.hljs-addition{color:#9ece6a}.hljs-code,.hljs-formula,.hljs-section{color:#7aa2f7}.hljs-name,.hljs-keyword,.hljs-operator,.hljs-char.escape_,.hljs-attr{color:#bb9af7}.hljs-punctuation{color:#c0caf5}.hljs{background:#1a1b26;color:#9aa5ce}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

4
web/dist/index.html vendored
View File

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI - Welcome</title>
<script type="module" crossorigin src="/assets/index-97b789f4.js"></script>
<link rel="stylesheet" href="/assets/index-da85d9b9.css">
<script type="module" crossorigin src="/assets/index-b30b467a.js"></script>
<link rel="stylesheet" href="/assets/index-1e952553.css">
</head>
<body>
<div id="app"></div>

1038
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,7 @@
"flowbite": "^1.6.5",
"flowbite-vue": "^0.0.10",
"highlight.js": "^11.8.0",
"markdown-it": "^13.0.1",
"markdown-it": "^13.0.2",
"markdown-it-anchor": "^8.6.7",
"markdown-it-attrs": "^4.1.6",
"markdown-it-emoji": "^2.0.2",

View File

@ -56,11 +56,24 @@ h4 {
}
/* Include any additional styles you need */
p {
font-size: 16px;
word-wrap: break-word;
overflow-wrap: break-word;
white-space: normal;
}
ul {
list-style-type: disc;
margin-left: 5px;
margin-left: 0px;
}
li {
list-style-type: disc;
margin-left: 20px;
}
ol {
list-style-type: decimal;
margin-left: 20px;
}

View File

@ -76,12 +76,16 @@
title="Copy message to clipboard" @click.stop="copyContentToClipboard()">
<i data-feather="copy"></i>
</div>
<div v-if="message.sender!=this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2" title="Resend message"
@click.stop="resendMessage()" :class="{ 'disabled': editMsgMode }">
<div v-if="!editMsgMode && message.sender!=this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2"
title="Resend message"
@click.stop="resendMessage()"
:class="{ 'text-5xl': editMsgMode }">
<i data-feather="refresh-cw"></i>
</div>
<div v-if="message.sender==this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2" title="Resend message"
@click.stop="continueMessage()" :class="{ 'disabled': editMsgMode }">
<div v-if="!editMsgMode && message.sender==this.$store.state.mountedPers.name" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2"
title="Resend message"
@click.stop="continueMessage()"
>
<i data-feather="fast-forward"></i>
</div>
<!-- DELETE CONFIRMATION -->
@ -96,7 +100,7 @@
</button>
</div>
<div v-if="!deleteMsgMode" class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2"
<div v-if="!editMsgMode && !deleteMsgMode" class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2"
title="Remove message" @click="deleteMsgMode = true">
<i data-feather="trash"></i>
</div>
@ -142,11 +146,17 @@
<MarkdownRenderer ref="mdRender" v-if="!editMsgMode" :markdown-text="message.content">
</MarkdownRenderer>
<textarea v-if="editMsgMode" ref="mdTextarea" :rows="4"
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
<div >
<textarea v-if="editMsgMode" ref="mdTextarea" @keydown.tab.prevent="insertTab"
class="block p-2.5 w-full text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 overflow-y-scroll flex flex-col shadow-lg p-10 pt-0 overflow-y-scroll w-full dark:bg-bg-dark scrollbar-thin scrollbar-track-bg-light-tone scrollbar-thumb-bg-light-tone-panel hover:scrollbar-thumb-primary dark:scrollbar-track-bg-dark-tone dark:scrollbar-thumb-bg-dark-tone-panel dark:hover:scrollbar-thumb-primary active:scrollbar-thumb-secondary"
:rows="4"
:style="{ minHeight: mdRenderHeight + `px` }" placeholder="Enter message here..."
v-model="message.content"></textarea>
<div v-if="message.metadata !== null">
v-model="message.content">
</textarea>
</div>
<div v-if="message.metadata !== null">
<div v-for="(metadata, index) in message.metadata" :key="'json-' + message.id + '-' + index" class="json font-bold">
<JsonViewer :jsonFormText="metadata.title" :jsonData="metadata.content" />
</div>
@ -202,7 +212,6 @@ import RenderHTMLJS from './RenderHTMLJS.vue';
import JsonViewer from "./JsonViewer.vue";
import Step from './Step.vue';
import DynamicUIRenderer from "./DynamicUIRenderer.vue"
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Message',
@ -212,7 +221,7 @@ export default {
Step,
RenderHTMLJS,
JsonViewer,
DynamicUIRenderer
DynamicUIRenderer,
},
props: {
message: Object,
@ -254,7 +263,25 @@ export default {
})
}, methods: {
insertTab(event) {
const textarea = event.target;
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const textBefore = textarea.value.substring(0, start);
const textAfter = textarea.value.substring(end);
// Insert a tab character (or spaces if you prefer) at the cursor position
const newText = textBefore + ' ' + textAfter;
// Update the textarea content and cursor position
this.message.content = newText;
this.$nextTick(() => {
textarea.selectionStart = textarea.selectionEnd = start + 4;
});
event.preventDefault();
},
onVoicesChanged() {
// This event will be triggered when the voices are loaded
this.voices = this.speechSynthesis.getVoices();

View File

@ -736,6 +736,11 @@ export default {
}
},
async selectDiscussion(item) {
if(this.isGenerating){
this.$refs.toast.showToast("You are currently generating a text. Please wait for text generation to finish or stop it before trying to select another discussion", 4, false)
return;
}
if (item) {
// When discussion is selected it loads the discussion array
if (this.currentDiscussion===undefined) {

View File

@ -1,6 +1,6 @@
<template>
<div class="container mx-auto p-4 bg-bg-light-tone dark:bg-bg-dark-tone shadow-lg overflow-y-auto no-scrollbar p-2 pb-0 grid lg:grid-cols-3 md:grid-cols-2 gap-4">
<div class="container flex-row mx-auto p-4 bg-bg-light-tone dark:bg-bg-dark-tone shadow-lg overflow-y-auto no-scrollbar p-2 pb-0 grid lg:grid-cols-1 md:grid-cols-2 gap-4">
<Card :disableHoverAnimation="true" :disableFocus="true">
<h2 class="text-2xl font-bold mb-2">About Lord of large Language Models</h2>
<p class="mb-4"> Lollms version {{ version }}</p>

View File

@ -42,12 +42,13 @@
</div>
<div class="flex-grow m-2 p-2 border border-blue-300 rounded-md border-2 border-blue-300 m-2 p-4" :class="{ 'border-red-500': generating }">
<div v-if="tab_id === 'source'">
<textarea
@click="text_element_clicked"
@keyup="text_element_changed"
v-model="text"
ref="text_element"
class="bg-white dark:bg-black m-0 border-2 rounded-md shadow-sm w-full mt-4 h-64 p-2 rounded shadow-lg overflow-y-scroll w-full dark:bg-bg-dark scrollbar-thin scrollbar-track-bg-light-tone scrollbar-thumb-bg-light-tone-panel hover:scrollbar-thumb-primary dark:scrollbar-track-bg-dark-tone dark:scrollbar-thumb-bg-dark-tone-panel dark:hover:scrollbar-thumb-primary active:scrollbar-thumb-secondary" type="text"></textarea>
<textarea ref="mdTextarea" @keydown.tab.prevent="insertTab"
class="block min-h-500 p-2.5 w-full text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 overflow-y-scroll flex flex-col shadow-lg p-10 pt-0 overflow-y-scroll dark:bg-bg-dark scrollbar-thin scrollbar-track-bg-light-tone scrollbar-thumb-bg-light-tone-panel hover:scrollbar-thumb-primary dark:scrollbar-track-bg-dark-tone dark:scrollbar-thumb-bg-dark-tone-panel dark:hover:scrollbar-thumb-primary active:scrollbar-thumb-secondary"
:rows="4"
:style="{ minHeight: mdRenderHeight + `px` }" placeholder="Enter message here..."
v-model="text">
</textarea>
<span>Cursor position {{ cursorPosition }}</span>
</div>
<div v-if="tab_id === 'render'">
@ -427,6 +428,25 @@ export default {
},
},
methods:{
insertTab(event) {
const textarea = event.target;
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const textBefore = textarea.value.substring(0, start);
const textAfter = textarea.value.substring(end);
// Insert a tab character (or spaces if you prefer) at the cursor position
const newText = textBefore + ' ' + textAfter;
// Update the textarea content and cursor position
this.text = newText;
this.$nextTick(() => {
textarea.selectionStart = textarea.selectionEnd = start + 4;
});
event.preventDefault();
},
text_element_changed(){
console.log("text_element_changed")
this.cursorPosition = this.$refs.text_element.selectionStart;