upgraded ui + file vectorization

This commit is contained in:
Saifeddine ALOUI 2023-08-25 02:12:33 +02:00
parent c81a2b4ba7
commit c93b7c12e2
19 changed files with 478 additions and 227 deletions

View File

@ -459,8 +459,7 @@ class LoLLMsAPPI(LollmsApplication):
jsons,
room=client_id
)
@socketio.on('upload_file')
def upload_file(data):
file = data['file']
@ -493,6 +492,16 @@ class LoLLMsAPPI(LollmsApplication):
ASCIIColors.error(f'Client {request.sid} canceled generation')
self.cancel_gen = False
self.busy=False
@socketio.on('get_personality_files')
def get_personality_files(data):
client_id = request.sid
self.connections[client_id]["generated_text"] = ""
self.connections[client_id]["cancel_generation"] = False
try:
self.personality.setCallback(partial(self.process_chunk,client_id = client_id))
except Exception as ex:
trace_exception(ex)
@socketio.on('send_file')
def send_file(data):
@ -509,23 +518,36 @@ class LoLLMsAPPI(LollmsApplication):
file_path = path / data["filename"]
File64BitsManager.b642file(data["fileData"],file_path)
if self.personality.processor:
self.personality.processor.add_file(file_path, partial(self.process_chunk, client_id=client_id))
result = self.personality.processor.add_file(file_path, partial(self.process_chunk, client_id=client_id))
else:
self.personality.add_file(file_path, partial(self.process_chunk, client_id=client_id))
self.socketio.emit('file_received',
{
"status":True,
}, room=client_id
)
result = self.personality.add_file(file_path, partial(self.process_chunk, client_id=client_id))
if result:
self.socketio.emit('file_received',
{
"status":True,
"filename":data["filename"],
}, room=client_id
)
else:
self.socketio.emit('file_received',
{
"status":False,
"filename":data["filename"],
"error":"Couldn't receive file: Verify that file type is compatible with the personality"
}, room=client_id
)
except Exception as ex:
ASCIIColors.error(ex)
trace_exception(ex)
self.socketio.emit('file_received',
{
"status":False,
"filename":data["filename"],
"error":"Couldn't receive file: "+str(ex)
}, room=client_id
)
)
self.close_message(client_id)
@self.socketio.on('cancel_text_generation')
@ -978,11 +1000,14 @@ class LoLLMsAPPI(LollmsApplication):
if len(self.personality.files)>0 and self.personality.vectorizer:
pr = PromptReshaper("!@>Document chunks:\n{{doc}}\n{{conditionning}}\n{{content}}")
pr = PromptReshaper("!@>document chunks:\n{{doc}}\n{{conditionning}}\n{{content}}")
emb = self.personality.vectorizer.embed_query(message.content)
docs, sorted_similarities = self.personality.vectorizer.recover_text(emb, top_k=self.config.data_vectorization_nb_chunks)
str_docs = ""
for doc, infos in zip(docs, sorted_similarities):
str_docs+=f"document chunk:\nchunk path: {infos[0]}\nchunk content:{doc}"
discussion_messages = pr.build({
"doc":"\n".join(docs),
"doc":str_docs,
"conditionning":self.personality.personality_conditioning,
"content":discussion_messages
}, self.model.tokenize, self.model.detokenize, self.config.ctx_size, place_holders_to_sacrifice=["content"])

82
app.py
View File

@ -275,6 +275,10 @@ class LoLLMsWebUI(LoLLMsAPPI):
self.add_endpoint(
"/list_models", "list_models", self.list_models, methods=["GET"]
)
self.add_endpoint(
"/get_active_model", "get_active_model", self.get_active_model, methods=["GET"]
)
self.add_endpoint(
"/list_personalities_categories", "list_personalities_categories", self.list_personalities_categories, methods=["GET"]
)
@ -408,9 +412,13 @@ class LoLLMsWebUI(LoLLMsAPPI):
)
self.add_endpoint(
"/presets.json", "presets.json", self.get_presets, methods=["GET"]
"/get_presets", "get_presets", self.get_presets, methods=["GET"]
)
self.add_endpoint(
"/add_preset", "add_preset", self.add_preset, methods=["POST"]
)
self.add_endpoint(
"/save_presets", "save_presets", self.save_presets, methods=["POST"]
)
@ -471,14 +479,55 @@ class LoLLMsWebUI(LoLLMsAPPI):
return json.dumps(output_json)
return spawn_process(code)
def copy_files(self, src, dest):
for item in os.listdir(src):
src_file = os.path.join(src, item)
dest_file = os.path.join(dest, item)
if os.path.isfile(src_file):
shutil.copy2(src_file, dest_file)
def get_presets(self):
presets_file = self.lollms_paths.personal_databases_path/"presets.json"
if not presets_file.exists():
shutil.copy("presets/presets.json",presets_file)
with open(presets_file) as f:
data = json.loads(f.read())
return jsonify(data)
presets_folder = self.lollms_paths.personal_databases_path/"lollms_playground_presets"
if not presets_folder.exists():
presets_folder.mkdir(exist_ok=True, parents=True)
self.copy_files("presets",presets_folder)
presets = []
for filename in presets_folder.glob('*.yaml'):
print(filename)
with open(filename, 'r') as file:
preset = yaml.safe_load(file)
if preset is not None:
presets.append(preset)
return jsonify(presets)
def add_preset(self):
# Get the JSON data from the POST request.
preset_data = request.get_json()
presets_folder = self.lollms_paths.personal_databases_path/"lollms_playground_presets"
if not presets_folder.exists():
presets_folder.mkdir(exist_ok=True, parents=True)
self.copy_files("presets",presets_folder)
fn = preset_data.name.lower().replace(" ","_")
filename = presets_folder/f"{fn}.yaml"
with open(filename, 'r') as file:
yaml.dump(preset_data)
return jsonify({"status": True})
def del_preset(self):
presets_folder = self.lollms_paths.personal_databases_path/"lollms_playground_presets"
if not presets_folder.exists():
presets_folder.mkdir(exist_ok=True, parents=True)
self.copy_files("presets",presets_folder)
presets = []
for filename in presets_folder.glob('*.yaml'):
print(filename)
with open(filename, 'r') as file:
preset = yaml.safe_load(file)
if preset is not None:
presets.append(preset)
return jsonify(presets)
def save_presets(self):
"""Saves a preset to a file.
@ -498,7 +547,7 @@ class LoLLMsWebUI(LoLLMsAPPI):
with open(presets_file, "w") as f:
json.dump(preset_data, f, indent=4)
return "Preset saved successfully!"
return jsonify({"status":True,"message":"Preset saved successfully!"})
def export_multiple_discussions(self):
data = request.get_json()
@ -696,17 +745,18 @@ class LoLLMsWebUI(LoLLMsAPPI):
self.config["model_name"]=data['setting_value']
if self.config["model_name"] is not None:
try:
self.model = None
if self.binding:
self.binding.destroy_model()
del self.binding
self.binding = None
self.model = None
for per in self.mounted_personalities:
per.model = None
gc.collect()
self.binding = BindingBuilder().build_binding(self.config, self.lollms_paths)
self.model = self.binding.build_model()
self.rebuild_personalities(reload_all=True)
for per in self.mounted_personalities:
per.model = self.model
except Exception as ex:
# Catch the exception and get the traceback as a list of strings
traceback_lines = traceback.format_exception(type(ex), ex, ex.__traceback__)
@ -870,6 +920,14 @@ class LoLLMsWebUI(LoLLMsAPPI):
else:
return jsonify([])
def get_active_model(self):
if self.binding is not None:
models = self.binding.list_models(self.config)
index = models.index(self.config.model_name)
ASCIIColors.yellow("Listing models")
return jsonify({"model":models[index],"index":index})
else:
return jsonify(None)
def list_personalities_categories(self):
personalities_categories_dir = self.lollms_paths.personalities_zoo_path # replace with the actual path to the models folder

View File

@ -0,0 +1,5 @@
name: Alpaca Instruct mode
content: |
### Instructions:
@<Give instructions to the AI>@
### Answer:@<generation_placeholder>@

View File

@ -0,0 +1,16 @@
name: Build a Latex Book
content: |
@<Add some context information to give the AI some context about the book or leave blank if you have no specific idea>@
```latex
\documentclass[12pt]{book}
\usepackage{url}
\begin{document}
\title{@<Title of the book>@}
\author{@<Author name>@} % Author
\date{\today} % Date
\maketitle
\tableofcontents
\chapter{Introduction}
@<generation_placeholder>@
\end{document}
```

View File

@ -0,0 +1,6 @@
name: Explain code
content: |
```@<Language:all_programming_language_options>@
@<put your code here>@
```
Here is an explanation of the previous method:@<generation_placeholder>@

11
presets/fix_a_code.yaml Normal file
View File

@ -0,0 +1,11 @@
name: Fix a code
content: |
Code fixer is a code fixing AI that fixes any code in any language.
Here is a @<Language:all_programming_language_options>@ code:
```@<Language:all_programming_language_options>@
@<Input your code>@
```
Instruction:Check this code and fix any errors if there are any.
Code fixer:
```@<Language:all_programming_language_options>@
@<generation_placeholder>@",

View File

@ -0,0 +1,5 @@
name: Instruct mode
content: |
Instructions:
@<Give instructions to the AI>@
Answer:@<generation_placeholder>@

View File

@ -7,7 +7,7 @@
"Make a function": "Here is a @<Language:all_programming_language_options>@ function that @<describe the function you want lollms to build>@:\n```@<Language:all_programming_language_options>@\n@<generation_placeholder>@",
"Fix a code": "Here is a @<Language:all_programming_language_options>@ code:\n```@<Language:all_programming_language_options>@\n@<Input your code>@\n```\nInstruction:Check this code and fix any errors if there are any.\nAI:@<generation_placeholder>@",
"Make programming project": "```@<Language:all_programming_language_options>@\n# project: @<Project name>@ \n# author: @<Author name>@\n# description: @<The description of the code>@\n\n@<generation_placeholder>@\n```\n---------\nExtra information:\nLicence: apache 2.0\nProgram type: Stand alone.\nDocumentation:\nMake README.md with the following table of contents:\n## Description\n## Installation\n## Usage\n## Licence\n## Contribute\n## Ethical guidelines\nInstructions:\nWrite a user side README.md\nStick to the provided code content and do not invent extra information.\nMake sure all sections of the table of contents are present in the file.\n----\nREADME.md:\n```markdown\n@<generation_placeholder>@\n```",
"Explain code": "```@<Language:all_programming_language_options>@\n@<put your code here>@\n```\nHere is an explanation of the previous method:",
"Translate code file strings": "Instruction: Translate the comments and values of the @<File type:yaml:json:all_programming_language_options>@ file from @<Source language:all_language_options>@ to @<Destination language:all_language_options>@.\nSession 1:\n```yaml language=english\n# This is a comment\nparameter_1: this is parameter 1\nparameter_2: this is parameter 2\nparameter_3: 25\nparameter_4: |\n This is a multi\n line parameter\n```\n```yaml language=french\n# Ceci est un commentaire\nparameter_1: ceci est le param\u00e8tre 1\nparameter_2: ceci est le param\u00e8tre 2\nparameter_3: 25\nparameter_4: |\n Ceci est une multiligne\n ligne de param\u00e8tre\n```\nSession 2:\n```yaml language=english\n@<Put your yaml data here>@\n```\n```yaml language=french",
"Explain code": "```@<Language:all_programming_language_options>@\n@<put your code here>@\n```\nHere is an explanation of the previous method:@<generation_placeholder>@",
"Translate code file strings": "Instruction: Translate the comments and values of the @<File type:yaml:json:all_programming_language_options>@ file from @<Source language:all_language_options>@ to @<Destination language:all_language_options>@.\nSession 1:\n```yaml language=english\n# This is a comment\nparameter_1: this is parameter 1\nparameter_2: this is parameter 2\nparameter_3: 25\nparameter_4: |\n This is a multi\n line parameter\n```\n```yaml language=french\n# Ceci est un commentaire\nparameter_1: ceci est le param\u00e8tre 1\nparameter_2: ceci est le param\u00e8tre 2\nparameter_3: 25\nparameter_4: |\n Ceci est une multiligne\n ligne de param\u00e8tre\n```\nSession 2:\n```yaml language=@<Source language:all_language_options>@\n@<Put your yaml data here>@\n```\n```yaml language=@<Destination language:all_language_options>@@<generation_placeholder>@",
"Translate text": "```@<Source language:all_language_options>@\n@<Text to translate>@\n```\n```@<Destination language:all_language_options>@\n@<generation_placeholder>@\n```\n"
}

View File

@ -0,0 +1,5 @@
name: Q&A with conditionning
content: |
Assistant is a highly developed AI capable of answering any question about any subject.
User:@<What's your question?>@
Assistant:@<generation_placeholder>@

View File

@ -0,0 +1,2 @@
name: Simple Book writing
content: Once apon a time

View File

@ -0,0 +1,4 @@
name: Simple Question Answer
content: |
User:@<What is your question:Why is the earth blue?>@
Assistant:@<generation_placeholder>@

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

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-0d84a618.js"></script>
<link rel="stylesheet" href="/assets/index-3540572d.css">
<script type="module" crossorigin src="/assets/index-7262b344.js"></script>
<link rel="stylesheet" href="/assets/index-d072d96d.css">
</head>
<body>
<div id="app"></div>

View File

@ -1,8 +1,8 @@
<template>
<div v-if="isActive" class="overlay" @click="toggleCard"></div>
<div
<div v-show="shrink===false"
:class="[
'bg-white dark:bg-gray-700 border-blue-300 rounded-lg shadow-lg p-6',
'bg-white dark:bg-gray-700 border-blue-300 rounded-lg shadow-lg p-2',
cardWidthClass,
'm-2',
{ hovered: !disableHoverAnimation && isHovered, active: isActive }
@ -13,7 +13,7 @@
:style="{ cursor:!this.disableFocus ? 'pointer' : ''}"
>
<!-- Title -->
<div v-if="title" class="font-bold mb-2">{{ title }}</div>
<div v-if="title" @click="shrink=true" class="font-bold mb-2 cursor-pointer">{{ title }}</div>
<div v-if="isHorizontal" class="flex flex-wrap">
<!-- Card Content -->
@ -25,11 +25,18 @@
<slot></slot>
</div>
</div>
<div v-show="shrink===true" @click="shrink=false" class="bg-white dark:bg-gray-700 border-blue-300 rounded-lg shadow-lg p-2 h-10 cursor-pointer">
+
</div>
</template>
<script>
export default {
props: {
is_shrunk: {
type:Boolean,
default:false
},
title: {
type: String,
default: "",
@ -44,7 +51,7 @@ export default {
},
disableHoverAnimation: {
type: Boolean,
default: false,
default: true,
},
disableFocus: {
type: Boolean,
@ -53,6 +60,7 @@ export default {
},
data() {
return {
shrink: this.is_shrunk,
isHovered: false,
isActive: false,
};

View File

@ -25,13 +25,6 @@
<i data-feather="list"></i>
</button>
<button v-if="fileList.length > 0"
class="mx-1 w-full text-2xl hover:text-secondary duration-75 flex justify-center hover:bg-bg-light-tone hover:dark:bg-bg-dark-tone rounded-lg "
:title="showFileList ? 'Send files' : 'Show file list'" type="button"
@click.stop="send_files">
<i data-feather="send"></i>
</button>
</div>
<!-- FILES -->
<div v-if="fileList.length > 0 && showFileList ==true">
@ -45,6 +38,18 @@
<div
class="flex flex-row items-center gap-1 text-left p-2 text-sm font-medium bg-bg-dark-tone-panel dark:bg-bg-dark-tone rounded-lg hover:bg-primary dark:hover:bg-primary">
<div v-if="!isFileSentList[index]" fileList role="status">
<svg aria-hidden="true" class="w-6 h-6 animate-spin fill-secondary"
viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor" />
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill" />
</svg>
<span class="sr-only">Loading...</span>
</div>
<div>
<i data-feather="file" class="w-5 h-5"></i>
@ -96,15 +101,15 @@
({{ fileList.length }})
</div>
<div class="grow">
</div>
<button type="button" title="Clear all"
class="flex items-center p-0.5 text-sm rounded-sm hover:text-red-600 active:scale-75"
@click="fileList = []">
@click="clear_files">
<i data-feather="trash" class="w-5 h-5 "></i>
</button>
</div>
<div v-if="showPersonalities" class="mx-1">
@ -250,6 +255,7 @@ export default {
message: "",
isLesteningToVoice:false,
fileList: [],
isFileSentList: [],
totalSize: 0,
showFileList: true,
showPersonalities: false,
@ -281,11 +287,14 @@ export default {
}
},
methods: {
clear_files(){
fileList = []
isFileSentList = []
},
send_file(file){
const formData = new FormData();
formData.append('file', file);
console.log("Uploading file")
//this.loading=true;
// Read the file as a data URL and emit it to the server
const reader = new FileReader();
reader.onload = () => {
@ -294,29 +303,28 @@ export default {
fileData: reader.result,
};
socket.on('file_received',(resp)=>{
if(resp.status){
this.onShowToastMessage("File uploaded successfully",4,true)
}
else{
this.onShowToastMessage("Couldn't upload file\n"+resp.error,4,false)
}
//this.loading = false;
socket.off('file_received')
if(resp.status){
console.log(resp.filename)
let index = this.fileList.findIndex((file) => file.name === resp.filename);
if(index>=0){
this.isFileSentList[index]=true;
console.log(this.isFileSentList)
}
else{
console.log("Not found")
}
this.onShowToastMessage("File uploaded successfully",4,true);
}
else{
this.onShowToastMessage("Couldn't upload file\n"+resp.error,4,false);
}
socket.off('file_received')
})
socket.emit('send_file', data);
};
reader.readAsDataURL(file);
},
// vue.js method. The list of files are in this.fileList
// This function will call this.send_file on each file from this.fileList
send_files(event){
event.preventDefault(); // Add this line to prevent form validation
for(let i = 0; i < this.fileList.length; i++){
let file = this.fileList[i];
this.send_file(file);
}
this.fileList = [];
},
startSpeechRecognition() {
if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
this.recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
@ -420,8 +428,9 @@ export default {
this.$emit('stopGenerating')
},
addFiles(event) {
this.fileList = this.fileList.concat([...event.target.files])
this.isFileSentList = this.isFileSentList.concat([false] * this.fileList.length)
this.send_file(this.fileList[this.fileList.length-1])
}
},
watch: {

View File

@ -3,22 +3,9 @@
<div class="container flex flex-row m-2">
<div class="flex-grow m-2">
<div class="flex-grow m-2 p-2 border border-blue-300 rounded-md border-2 border-blue-300 m-2 p-4">
<label class="mt-2">Presets</label>
<select v-model="selectedPreset" class="m-2 border-2 rounded-md shadow-sm w-full">
<option v-for="preset in Object.keys(presets)" :key="preset" :value="preset">
{{ preset }}
</option>
</select>
<button class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer" @click="setPreset" title="Use preset"><i data-feather="check"></i></button>
<button class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer" @click="addPreset" title="Add this text as a preset"><i data-feather="plus"></i></button>
<button class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer" @click="removePreset" title="Remove preset"><i data-feather="x"></i></button>
<button class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer" @click="savePreset" title="Save presets list"><i data-feather="save"></i></button>
<button class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer" @click="reloadPresets" title="Reload presets list"><i data-feather="refresh-ccw"></i></button>
</div>
<div class="flex-grow m-2 p-2 border border-blue-300 rounded-md border-2 border-blue-300 m-2 p-4">
<div class="m-0">
<button v-show="!generating" id="generate-button" @click="generate" class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer"><i data-feather="pen-tool"></i></button>
<button v-show="!generating" id="generate-next-button" @click="generate_in_placeholder" class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer"><i data-feather="archive"></i></button>
<span class="w-80"></span>
<button v-show="generating" id="stop-button" @click="stopGeneration" class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer"><i data-feather="x"></i></button>
<button
type="button"
@ -39,61 +26,109 @@
<button v-show="!generating" id="import-button" @click="importText" class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer"><i data-feather="download"></i></button>
<input type="file" id="import-input" class="hidden">
</div>
<textarea v-model="text" id="text_element" class="mt-4 h-64 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>
<span>Cursor position {{ cursorPosition }}</span>
</div>
<div class="flex-grow m-2 p-2 border border-blue-300 rounded-md border-2 border-blue-300 m-2 p-4">
<MarkdownRenderer ref="mdRender" :markdown-text="text" class="dark:bg-bg-dark">
</MarkdownRenderer>
</div>
</div>
<div id="settings" class="border border-blue-300 bg-blue-200 mt-4 w-25 mr-2 h-full mb-10 min-w-500" style="align-items: center; height: fit-content; margin: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); border-radius: 4px;">
<div id="title" class="border border-blue-600 bg-blue-300 m-0 flex justify-center items-center box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) border-radius: 4px;">
<h3 class="text-gray-600 mb-4 text-center m-0">Settings</h3>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Temperature</h3>
<input type="range" v-model="temperature" min="0" max="5" step="0.1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ temperature }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Top K</h3>
<input type="range" v-model="top_k" min="1" max="100" step="1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ top_k }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Top P</h3>
<input type="range" v-model="top_p" min="0" max="1" step="0.1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ top_p }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Repeat Penalty</h3>
<input type="range" v-model="repeat_penalty" min="0" max="5" step="0.1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ repeat_penalty }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Repeat Last N</h3>
<input type="range" v-model="repeat_last_n" min="0" max="100" step="1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ repeat_last_n }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Number of tokens to crop the text to</h3>
<input type="number" v-model="n_crop" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ n_crop }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Number of tokens to generate</h3>
<input type="number" v-model="n_predicts" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ n_predicts }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Seed</h3>
<input type="number" v-model="seed" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ seed }}</span>
<div class="flex-grow m-2 p-2 border border-blue-300 rounded-md border-2 border-blue-300 m-2 p-4">
<div class="flex flex-row m-2 p-0">
<div class="border-2 text-blue-600 border-blue-300 p-2 rounded shadow-lg hover:border-gray-600 dark:link-item-dark cursor-pointer" @click="tab_id='source'" :class="{'bg-blue-200':tab_id=='source'}">
Source
</div>
<div class="border-2 text-blue-600 border-blue-300 p-2 rounded shadow-lg hover:border-gray-600 dark:link-item-dark cursor-pointer" @click="tab_id='render'" :class="{'bg-blue-200':tab_id=='render'}">
Render
</div>
</div>
<div v-if="tab_id === 'source'">
<textarea v-model="text" id="text_element" class="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>
<span>Cursor position {{ cursorPosition }}</span>
</div>
<div v-else>
<MarkdownRenderer ref="mdRender" :markdown-text="text" class="mt-4 p-2 rounded shadow-lg dark:bg-bg-dark">
</MarkdownRenderer>
</div>
</div>
</div>
<Card title="settings" class="slider-container ml-0 mr-0" :isHorizontal="false" :disableHoverAnimation="true" :disableFocus="true">
<Card title="Model" class="slider-container ml-0 mr-0" :isHorizontal="false" :disableHoverAnimation="true" :disableFocus="true">
<select v-model="selectedModel" @change="setModel" class="m-0 border-2 rounded-md shadow-sm w-full">
<option v-for="model in models" :key="model" :value="model">
{{ model }}
</option>
</select>
<div v-if="selecting_model" title="Selecting model" class="flex flex-row flex-grow justify-end">
<!-- SPINNER -->
<div role="status">
<svg aria-hidden="true" class="w-6 h-6 animate-spin fill-secondary" viewBox="0 0 100 101"
fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor" />
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill" />
</svg>
<span class="sr-only">Selecting model...</span>
</div>
</div>
</Card>
<Card title="Presets" class="slider-container ml-0 mr-0" :isHorizontal="false" :disableHoverAnimation="true" :disableFocus="true">
<select v-model="selectedPreset" class="m-0 border-2 rounded-md shadow-sm w-full">
<option v-for="preset in presets" :key="preset" :value="preset">
{{ preset.name }}
</option>
</select>
<br>
<button class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer" @click="setPreset" title="Use preset"><i data-feather="check"></i></button>
<button class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer" @click="addPreset" title="Add this text as a preset"><i data-feather="plus"></i></button>
<button class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer" @click="removePreset" title="Remove preset"><i data-feather="x"></i></button>
<button class="w-6 ml-2 hover:text-secondary duration-75 active:scale-90 cursor-pointer" @click="reloadPresets" title="Reload presets list"><i data-feather="refresh-ccw"></i></button>
</Card>
<Card title="Generation params" class="slider-container ml-0 mr-0" :isHorizontal="false" :disableHoverAnimation="true" :disableFocus="true">
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Temperature</h3>
<input type="range" v-model="temperature" min="0" max="5" step="0.1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ temperature }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Top K</h3>
<input type="range" v-model="top_k" min="1" max="100" step="1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ top_k }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Top P</h3>
<input type="range" v-model="top_p" min="0" max="1" step="0.1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ top_p }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Repeat Penalty</h3>
<input type="range" v-model="repeat_penalty" min="0" max="5" step="0.1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ repeat_penalty }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Repeat Last N</h3>
<input type="range" v-model="repeat_last_n" min="0" max="100" step="1" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ repeat_last_n }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Number of tokens to crop the text to</h3>
<input type="number" v-model="n_crop" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ n_crop }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Number of tokens to generate</h3>
<input type="number" v-model="n_predicts" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ n_predicts }}</span>
</div>
<div class="slider-container ml-2 mr-2">
<h3 class="text-gray-600">Seed</h3>
<input type="number" v-model="seed" class="w-full">
<span class="slider-value text-gray-500">Current value: {{ seed }}</span>
</div>
</Card>
</Card>
</div>
</div>
<Toast ref="toast"/>
@ -105,7 +140,8 @@ import axios from "axios";
import socket from '@/services/websocket.js'
import Toast from '../components/Toast.vue'
import MarkdownRenderer from '../components/MarkdownRenderer.vue';
import ClipBoardTextInput from "@/components/ClipBoardTextInput.vue";
import Card from "@/components/Card.vue"
async function showInputPanel(name, default_value="", options=[]) {
@ -250,22 +286,21 @@ function replaceInText(text, callback) {
});
}
// Get input value function
function getInputValue() {
const inputField = document.getElementById('input-field');
return inputField ? inputField.value : '';
}
export default {
name: 'PlayGroundView',
data() {
return {
selecting_model:false,
tab_id:"source",
generating:false,
isSpeaking:false,
voices: [],
isLesteningToVoice:false,
presets:{},
selectedPreset: '',
presets:[],
selectedPreset: '',
models:{},
selectedModel: '',
cursorPosition:0,
text:"",
pre_text:"",
@ -282,7 +317,9 @@ export default {
},
components:{
Toast,
MarkdownRenderer
MarkdownRenderer,
ClipBoardTextInput,
Card
},
mounted() {
const text_element = document.getElementById('text_element');
@ -301,18 +338,37 @@ export default {
catch{
}
});
axios.get('./presets.json').then(response => {
});
axios.get('list_models').then(response => {
console.log("List models "+response.data)
this.models=response.data
axios.get('get_active_model').then(response => {
console.log("Active model " + JSON.stringify(response.data))
if(response.data!=undefined){
this.selectedModel = response.data["model"]
}
}).catch(ex=>{
this.$refs.toast.showToast(`Error: ${ex}`,4,false)
});
}).catch(ex=>{
this.$refs.toast.showToast(`Error: ${ex}`,4,false)
});
axios.get('./get_presets').then(response => {
console.log(response.data)
this.presets=response.data
this.selectedPreset = this.presets[0]
}).catch(ex=>{
this.$refs.toast.showToast(`Error: ${ex}`,4,false)
});
// Event handler for receiving generated text chunks
socket.on('text_chunk', data => {
this.appendToOutput(data.chunk);
const text_element = document.getElementById('text_element');
text_element.scrollTo(0, text_element.scrollHeight);
// const text_element = document.getElementById('text_element');
// text_element.scrollTo(0, text_element.scrollHeight);
});
// Event handler for receiving generated text chunks
@ -388,6 +444,19 @@ export default {
},
},
methods:{
setModel(){
this.selecting_model=true
axios.post("/update_setting", {
setting_name: "model_name",
setting_value: this.selectedModel
}).then((response) => {
console.log(response);
this.$refs.toast.showToast(`Model changed to this.selectedModel`,4,true)
}).catch(err=>{
this.$refs.toast.showToast(`Error ${err}`,4,true)
});
},
onVoicesChanged() {
// This event will be triggered when the voices are loaded
this.voices = this.speechSynthesis.getVoices();
@ -467,6 +536,33 @@ export default {
this.pre_text += chunk
this.text = this.pre_text + this.post_text
},
generate_in_placeholder(){
console.log("Finding cursor position")
// Find next placeholder @<generation_placeholder>@
let index = this.text.indexOf("@<generation_placeholder>@")
if(index<0){
this.$refs.toast.showToast(`No generation placeholder found`,4,false)
return
}
this.text = this.text.substring(0,index) + this.text.substring(index+"@<generation_placeholder>@".length,this.text.length)
this.pre_text = this.text.substring(0,index)
this.post_text = this.text.substring(index, this.text.length)
var prompt = this.text.substring(0, index)
console.log(prompt)
// Trigger the 'generate_text' event with the prompt
socket.emit('generate_text', { prompt: prompt, personality: -1, n_predicts: this.n_predicts , n_crop: this.n_crop,
parameters: {
temperature: this.temperature,
top_k: this.top_k,
top_p: this.top_p,
repeat_penalty: this.repeat_penalty, // Update with desired repeat penalty value
repeat_last_n: this.repeat_last_n, // Update with desired repeat_last_n value
seed: parseInt(this.seed)
}});
// Toggle button visibility
this.generating=true
},
generate(){
console.log("Finding cursor position")
this.pre_text = this.text.substring(0,this.getCursorPosition())
@ -518,7 +614,9 @@ export default {
inputFile.click();
},
setPreset() {
this.text = replaceInText(this.presets[this.selectedPreset], (text)=>{
console.log("Setting preset")
console.log(this.selectedPreset)
this.text = replaceInText(this.selectedPreset.content, (text)=>{
console.log("Done")
console.log(text);
this.text= text
@ -527,23 +625,26 @@ export default {
addPreset() {
let title = prompt('Enter the title of the preset:');
this.presets[title] = this.text
this.presets[title] = {
name:title,
content:this.text
}
axios.post("./add_preset",this.presets[title]).then(response => {
console.log(response.data)
}).catch(ex=>{
this.$refs.toast.showToast(`Error: ${ex}`,4,false)
});
},
removePreset() {
if (this.selectedPreset) {
delete this.presets[this.selectedPreset];
delete this.presets[this.selectedPreset.name];
}
},
savePreset() {
axios.post("/save_presets", this.presets).then((response) => {
console.log(response);
this.$refs.toast.showToast(`Presets saved`,4,true)
});
},
reloadPresets() {
axios.get('./presets.json').then(response => {
axios.get('./get_presets').then(response => {
console.log(response.data)
this.presets=response.data
this.selectedPreset = this.presets[0]
}).catch(ex=>{
this.$refs.toast.showToast(`Error: ${ex}`,4,false)
});

View File

@ -80,7 +80,7 @@
<div class="flex gap-2 items-center ">
<div>
<div v-if="vramUsage.gpus && vramUsage.gpus.length == 1">
<div v-if="vramUsage&&vramUsage.gpus && vramUsage.gpus.length == 1">
<div class="flex gap-2 items-center " v-for="item in vramUsage.gpus">
@ -221,7 +221,7 @@
</h3>
</div>
</div>
<div v-if="vramUsage.gpus && vramUsage.gpus.length >1">
<div v-if="vramUsage&& vramUsage.gpus && vramUsage.gpus.length >1">
<div class="flex gap-2 items-center ">
<!-- GPU IMAGE -->
@ -530,8 +530,8 @@
</button>
</div>
<div :class="{ 'hidden': minconf_collapsed }" class="flex flex-col mb-2 px-3 pb-0">
<div class="flex flex-col mb-2 px-3 pb-2">
<div class="pb-2">
<div class="flex flex-row mb-2 px-3 pb-2">
<div class="pb-2 m-2 expand-to-fit">
<table class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 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">
<th>Generic</th>
<tr>
@ -602,7 +602,7 @@
</tr>
</table>
</div>
<div class="pb-2">
<div class="pb-2 m-2">
<table class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 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">
<th>User</th>
<tr>
@ -672,7 +672,7 @@
</tr>
</table>
</div>
<div class="pb-2">
<div class="pb-2 m-2">
<table class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 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">
<th>Audio</th>
<tr>
@ -782,26 +782,22 @@
<!-- Row 0 -->
<div class="w-full">
<div class="flex flex-row">
<button
class="hover:text-secondary dark:bg-gray-600 w-full bg-red-100 m-2 p-2 duration-75 flex justify-center w-full hover:bg-bg-light-tone hover:dark:bg-bg-dark-tone rounded-lg"
class="text-2xl hover:text-secondary duration-75 active:scale-90"
@click="api_get_req('clear_uploads').then((res)=>{if(res.status){this.$refs.toast.showToast('Success!', 4, true)}else{this.$refs.toast.showToast(['failed!'], 4, false)}})"
>
Clear uploads
<i data-feather="trash-2">Clear uploads</i>
</button>
</div>
<div class="w-full">
<button
class="hover:text-secondary dark:bg-gray-600 w-full bg-red-100 m-2 p-2 duration-75 flex justify-center w-full hover:bg-bg-light-tone hover:dark:bg-bg-dark-tone rounded-lg"
title="Restart program"
class="text-2xl hover:text-secondary duration-75 active:scale-90"
@click="api_get_req('restart_program').then((res)=>{if(res.status){this.$refs.toast.showToast('Success!', 4, true)}else{this.$refs.toast.showToast(['failed!'], 4, false)}})"
>
Restart program
<i data-feather="arrow-down-circle">Res tart program</i>
</button>
</div>
<!-- Row 0 -->
<div class="w-full">
<button
class="hover:text-secondary dark:bg-gray-600 w-full bg-red-100 m-2 p-2 duration-75 flex justify-center w-full hover:bg-bg-light-tone hover:dark:bg-bg-dark-tone rounded-lg"
class="text-2xl hover:text-secondary duration-75 active:scale-90"
@click="api_get_req('update_software').then((res)=>{if(res.status){this.$refs.toast.showToast('Success!', 4, true)}else{this.$refs.toast.showToast('Success!', 4, true)}})"
>
Upgrade program
@ -853,7 +849,7 @@
</div>
<div :class="{ 'hidden': bzc_collapsed }" class="flex flex-col mb-2 px-3 pb-0">
<div v-if="bindingsArr.length > 0" class="mb-2">
<div v-if="bindingsArr&&bindingsArr.length > 0" class="mb-2">
<label for="binding" class="block ml-2 mb-2 text-sm font-medium text-gray-900 dark:text-white">
Bindings: ({{ bindingsArr.length }})
</label>