enhanced ui

This commit is contained in:
Saifeddine ALOUI 2024-02-08 23:04:27 +01:00
parent fdace6b501
commit 9d90c8c921
19 changed files with 511 additions and 336 deletions

View File

@ -1,5 +1,5 @@
# =================== Lord Of Large Language Multimodal Systems Configuration file ===========================
version: 52
version: 53
binding_name: null
model_name: null
@ -57,6 +57,9 @@ hardware_mode: nvidia-tensorcores
# Automatically open the browser
auto_show_browser: true
# copy to clipboard
copy_to_clipboard_add_all_details: false
# Voice service
enable_voice_service: false
xtts_base_url: http://127.0.0.1:8020

@ -1 +1 @@
Subproject commit 2769acff3bef7f72429cf9a997679ca8179b6272
Subproject commit e6fbc6b1f09086632bba47a411add7d7e515e3b6

View File

@ -19,7 +19,7 @@ def build_mermaid_output(code, ifram_name="unnamed"):
This function creates an HTML5 iframe with the given HTML content and iframe name.
Args:
html (str): The HTML content to be displayed in the iframe.
code (str): The mermaid code
ifram_name (str, optional): The name of the iframe. Defaults to "unnamed".
Returns:
@ -44,10 +44,23 @@ def build_mermaid_output(code, ifram_name="unnamed"):
'<div class=\'mermaid\'>',
"\n".join([c for c in code.split("\n") if c.strip()!=""]),
'</div>',
'<button onclick="saveSVG()">Save SVG</button>',
'<script src=\'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js\'></script>',
'<script>',
'// Initialize the mermaid library and render our diagram',
'mermaid.initialize({ startOnLoad: true });',
'// Function to save SVG content to a file',
'function saveSVG() {',
'var svg = document.querySelector(".mermaid > svg");',
'var serializer = new XMLSerializer();',
'var source = serializer.serializeToString(svg);',
'var blob = new Blob([source], {type: "image/svg+xml;charset=utf-8"});',
'var url = URL.createObjectURL(blob);',
'var a = document.createElement("a");',
'a.href = url;',
'a.download = "diagram.svg";',
'a.click();',
'}',
'</script>',
'<div style=\'text-align: center;\'>',
'</div>',
@ -58,6 +71,7 @@ def build_mermaid_output(code, ifram_name="unnamed"):
execution_time = time.time() - start_time
return {"output": rendered, "execution_time": execution_time}
def execute_mermaid(code, discussion_id, message_id):
return build_mermaid_output(code)

View File

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 499 B

File diff suppressed because one or more lines are too long

8
web/dist/assets/index-669b6ebd.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

40
web/dist/assets/process-c7666516.svg vendored Normal file
View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 480 480" xml:space="preserve">
<g>
<g>
<g>
<path d="M240,0C107.664,0,0,107.664,0,240s107.664,240,240,240s240-107.664,240-240S372.336,0,240,0z M240,460
c-121.309,0-220-98.691-220-220S118.691,20,240,20s220,98.691,220,220S361.309,460,240,460z"/>
<path d="M410,194.999h-27.058c-2.643-8.44-6-16.56-10.03-24.271l19.158-19.158c3.776-3.775,5.854-8.79,5.854-14.121
c0-5.332-2.08-10.347-5.854-14.121l-35.399-35.399c-3.775-3.775-8.79-5.854-14.122-5.854c-5.331,0-10.346,2.079-14.121,5.854
l-19.158,19.158c-7.711-4.03-15.832-7.386-24.271-10.03V70c0-11.028-8.972-20-20-20h-50c-11.028,0-20,8.972-20,20v27.058
c-8.44,2.643-16.56,6-24.271,10.03L151.57,87.93c-3.775-3.776-8.79-5.854-14.121-5.854c-5.332,0-10.347,2.08-14.121,5.854
l-35.399,35.399c-3.775,3.775-5.854,8.79-5.854,14.122c0,5.331,2.079,10.346,5.854,14.121l19.158,19.158
c-4.03,7.711-7.386,15.832-10.03,24.271H70c-11.028,0-20,8.972-20,20v50c0,11.028,8.972,20,20,20h27.057
c2.643,8.44,6,16.56,10.03,24.271L87.929,328.43c-3.776,3.775-5.854,8.79-5.854,14.121c0,5.332,2.08,10.347,5.854,14.121
l35.399,35.399c3.775,3.775,8.79,5.854,14.122,5.854c5.331,0,10.346-2.079,14.121-5.854l19.158-19.158
c7.711,4.03,15.832,7.386,24.271,10.03V410c0,11.028,8.972,20,20,20h50c11.028,0,20-8.972,20.001-20v-27.058
c8.44-2.643,16.56-6,24.271-10.03l19.158,19.158c3.775,3.776,8.79,5.854,14.121,5.854c5.332,0,10.347-2.08,14.121-5.854
l35.399-35.399c3.775-3.775,5.854-8.79,5.854-14.122c0-5.331-2.079-10.346-5.854-14.121l-19.158-19.158
c4.03-7.711,7.386-15.832,10.03-24.271H410c11.028,0,20-8.972,20-20v-50C430,203.971,421.028,194.999,410,194.999z M410,264.998
h-34.598c-4.562,0-8.544,3.086-9.684,7.503c-3.069,11.901-7.716,23.133-13.813,33.387c-2.337,3.931-1.71,8.948,1.524,12.182
l24.5,24.457l-35.357,35.4l-24.5-24.5c-3.236-3.235-8.253-3.86-12.182-1.524c-10.254,6.097-21.487,10.745-33.387,13.813
c-4.417,1.14-7.503,5.122-7.503,9.684V410h-50v-34.599c0-4.562-3.086-8.544-7.503-9.684
c-11.901-3.069-23.133-7.716-33.387-13.813c-1.587-0.944-3.353-1.404-5.107-1.404c-2.586,0-5.147,1.002-7.073,2.931l-24.457,24.5
l-35.4-35.357l24.5-24.5c3.234-3.235,3.861-8.251,1.524-12.182c-6.097-10.254-10.745-21.487-13.813-33.387
c-1.14-4.417-5.122-7.503-9.684-7.503H70v-50h34.596c4.562,0,8.544-3.086,9.684-7.503c3.069-11.901,7.716-23.133,13.813-33.387
c2.337-3.931,1.71-8.948-1.524-12.182l-24.5-24.457l35.357-35.4l24.5,24.5c3.236,3.235,8.253,3.861,12.182,1.524
c10.254-6.097,21.487-10.745,33.387-13.813c4.417-1.14,7.503-5.122,7.503-9.684V70h50v34.596c0,4.562,3.086,8.544,7.503,9.684
c11.901,3.069,23.133,7.716,33.387,13.813c3.929,2.337,8.947,1.709,12.182-1.524l24.457-24.5l35.4,35.357l-24.5,24.5
c-3.234,3.235-3.861,8.251-1.524,12.182c6.097,10.254,10.745,21.487,13.813,33.387c1.14,4.417,5.122,7.503,9.684,7.503H410
V264.998z"/>
<path d="M331.585,292.475l-40-35l-13.17,15.051L298.386,290H240c-27.57,0-50-22.43-50-50h-20c0,38.598,31.402,70,70,70h58.386
l-19.971,17.475l13.17,15.051l40-35c2.17-1.898,3.415-4.642,3.415-7.525S333.755,294.373,331.585,292.475z"/>
<path d="M201.585,207.473L181.614,190H240c27.57,0,50,22.43,50,50h20c0-38.598-31.402-70-70-70h-58.386l19.971-17.475
l-13.17-15.051l-40,35c-2.17,1.898-3.415,4.642-3.415,7.525s1.245,5.627,3.415,7.525l40,35L201.585,207.473z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

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-298bef5e.js"></script>
<link rel="stylesheet" href="/assets/index-3521e65e.css">
<script type="module" crossorigin src="/assets/index-f22b94ea.js"></script>
<link rel="stylesheet" href="/assets/index-669b6ebd.css">
</head>
<body>
<div id="app"></div>

View File

@ -413,7 +413,7 @@ export default {
console.log('dis conputer pers', this.discussionList)
return persArray
}
return null;
}
},
methods: {

View File

@ -72,6 +72,10 @@
title="Edit message" @click.stop="editMsgMode = true">
<i data-feather="edit"></i>
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer hover:border-2"
title="Add generic block" @click.stop="addBlock('')">
<img :src="code_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer hover:border-2"
title="Add python block" @click.stop="addBlock('python')">
<img :src="python_block" width="25" height="25">
@ -187,10 +191,29 @@
<div class="overflow-x-auto w-full ">
<!-- MESSAGE CONTENT -->
<div class="flex flex-col items-start w-full">
<div v-for="(step, index) in message.steps" :key="'step-' + message.id + '-' + index" class="step font-bold" :style="{ backgroundColor: step.done ? 'transparent' : 'inherit' }">
<Step :done="step.done" :message="step.message" :status="step.status" />
<details v-show="message != undefined && message.steps != undefined && message.steps.length>0" class="flex w-full rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-800 dark:bg-gray-900 mb-3.5 max-w-full svelte-1escu1z">
<summary class="grid min-w-72 select-none grid-cols-[40px,1fr] items-center gap-2.5 p-2 svelte-1escu1z">
<div class="relative grid aspect-square place-content-center overflow-hidden rounded-lg bg-gray-300 dark:bg-gray-200">
<svg class="absolute inset-0 text-gray-300 transition-opacity dark:text-gray-700 opacity-0" width="40" height="40" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="loading-path svelte-1escu1z" d="M8 2.5H30C30 2.5 35.5 2.5 35.5 8V30C35.5 30 35.5 35.5 30 35.5H8C8 35.5 2.5 35.5 2.5 30V8C2.5 8 2.5 2.5 8 2.5Z" stroke="currentColor" stroke-width="1" stroke-linecap="round" id="shape">
</path>
</svg>
<img :src="process_svg" class="absolute inset-0 text-gray-100 transition-opacity dark:text-gray-800 opacity-100">
</div>
<dl class="leading-4">
<dd class="text-sm">Processing infos</dd>
<dt class="flex items-center gap-1 truncate whitespace-nowrap text-[.82rem] text-gray-400">{{ message==undefined?"":message.status_message }}</dt>
</dl>
</summary>
<div class="content px-5 pb-5 pt-4">
<ol>
<li v-for="(step, index) in message.steps" :key="'step-' + message.id + '-' + index" class="group border-l pb-6 last:!border-transparent last:pb-0 dark:border-gray-800" :style="{ backgroundColor: step.done ? 'transparent' : 'inherit' }">
<Step :done="step.done" :message="step.message" :status="step.status" />
</li>
</ol>
</div>
</details>
<div class="flex flex-col items-start w-full">
</div>
<div class="flex flex-col items-start w-full">
<div v-for="(html_js, index) in message.html_js_s" :key="'htmljs-' + message.id + '-' + index" class="htmljs font-bold" :style="{ backgroundColor: step.done ? 'transparent' : 'inherit' }">
@ -270,6 +293,7 @@ import JsonViewer from "./JsonViewer.vue";
import Step from './Step.vue';
import axios from 'axios';
import code_block from '@/assets/code_block.svg';
import python_block from '@/assets/python_block.png';
import javascript_block from '@/assets/javascript_block.svg';
import json_block from '@/assets/json_block.png';
@ -278,6 +302,8 @@ import html5_block from '@/assets/html5_block.png';
import LaTeX_block from '@/assets/LaTeX_block.png';
import bash_block from '@/assets/bash_block.png';
import process_svg from '@/assets/process.svg';
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Message',
@ -296,7 +322,9 @@ export default {
default: "http://localhost:9600",
},
message: Object,
avatar: ''
avatar: {
default: ''
}
},
data() {
return {
@ -306,6 +334,8 @@ export default {
LaTeX_block:LaTeX_block,
json_block:json_block,
javascript_block:javascript_block,
process_svg:process_svg,
code_block:code_block,
python_block:python_block,
bash_block:bash_block,
audio_url: null,

View File

@ -41,6 +41,7 @@
:selected="configFile.personalities[configFile.active_personality_id] === pers.full_path || configFile.personalities[configFile.active_personality_id] === pers.full_path+':'+pers.language"
:on-selected="onPersonalitySelected"
:on-mount="onPersonalityMounted"
:on-edit="editPersonality"
:on-un-mount="onPersonalityUnMounted"
:on-remount="onPersonalityRemount"
:on-settings="onSettingsPersonality"
@ -208,6 +209,32 @@ export default {
return { 'status': false }
});
},
editPersonality(pers) {
pers=pers.personality;
// Make a POST request to the '/get_personality_config' endpoint using Axios
axios.post('/get_personality_config', {
category: pers.category,
name: pers.folder,
})
.then(response => {
const data = response.data;
console.log("Done")
if (data.status) {
// Update the currentPersonConfig with the received data
this.$store.state.currentPersonConfig = data.config;
this.$store.state.showPersonalityEditor = true;
this.$store.state.personality_editor.showPanel()
this.$store.state.selectedPersonality = pers
} else {
// Handle the error
console.error(data.error);
}
})
.catch(error => {
// Handle the error
console.error(error);
});
},
onPersonalityMounted(persItem) {
//persItem.ismounted = true
this.mountPersonality(persItem)

View File

@ -82,7 +82,6 @@
<button @click.prevent="hide()" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Close
</button>
</div>
</form>
</div>

View File

@ -1,4 +1,7 @@
<template>
<div class="flex items-start">
<div class="-ml-1.5 h-3 w-3 flex-none rounded-full bg-gray-200 dark:bg-gray-600 ">
</div>
<div class="step flex items-center mb-4">
<div class="flex items-center justify-center w-6 h-6 mr-2">
<div v-if="!done">
@ -31,7 +34,8 @@
fill="currentFill" />
</svg>
</div>
<div class="content flex-1 px-2" :class="{'text-green-500': done, 'text-yellow-500': !done}">{{ message }}</div>
<h3 class="text-md -mt-1.5 pl-2.5 text-gray-800 dark:text-gray-100" :class="{'text-green-500': done, 'text-yellow-500': !done}">{{ message }}</h3>
</div>
</div>
</template>

View File

@ -106,6 +106,7 @@
</div>
<UniversalForm ref="universalForm" class="z-20" />
<YesNoDialog ref="yesNoDialog" class="z-20" />
<PersonalityEditor ref="personality_editor" :config="currentPersonConfig" :personality="selectedPersonality" ></PersonalityEditor>
</header>
@ -115,11 +116,12 @@
</template>
<script setup>
import Toast from '../components/Toast.vue'
import Toast from '@/components/Toast.vue'
import MessageBox from "@/components/MessageBox.vue";
import ProgressBar from "@/components/ProgressBar.vue";
import UniversalForm from '../components/UniversalForm.vue';
import YesNoDialog from './YesNoDialog.vue';
import PersonalityEditor from "@/components/PersonalityEditor.vue"
import FastAPI from '@/assets/fastapi.png';
import discord from '@/assets/discord.svg';
@ -133,6 +135,25 @@ import feather from 'feather-icons'
export default {
name: 'TopBar',
computed:{
currentPersonConfig (){
try{
return this.$store.state.currentPersonConfig
}
catch{
console.log("Error finding current personality configuration")
return undefined
}
},
selectedPersonality (){
try{
return this.$store.state.selectedPersonality
}
catch{
console.log("Error finding current personality configuration")
return undefined
}
},
loading_infos(){
return this.$store.state.loading_infos;
},
@ -153,6 +174,7 @@ export default {
UniversalForm,
YesNoDialog,
Navigation,
PersonalityEditor
},
watch:{
isConnected(){
@ -182,6 +204,7 @@ export default {
},
data() {
return {
is_first_connection:true,
discord:discord,
FastAPI:FastAPI,
@ -203,6 +226,8 @@ export default {
this.$store.state.messageBox = this.$refs.messageBox
this.$store.state.universalForm = this.$refs.universalForm
this.$store.state.yesNoDialog = this.$refs.yesNoDialog
this.$store.state.personality_editor = this.$refs.personality_editor
this.sunIcon = document.querySelector(".sun");
this.moonIcon = document.querySelector(".moon");

View File

@ -23,6 +23,19 @@ function copyObject(obj) {
export const store = createStore({
state () {
return {
personality_editor:null,
showPersonalityEditor: false,
selectedPersonality:null,
currentPersonConfig: {
ai_name: '',
ai_author: '',
ai_category: '',
ai_language: '',
ai_description: '',
ai_conditionning: '',
ai_disclaimer: '',
ai_icon: null,
},
// count: 0,
yesNoDialog:null,
universalForm:null,

View File

@ -1003,7 +1003,8 @@ export default {
sender: msgObj.user,
created_at: msgObj.created_at,
steps: [],
html_js_s: []
html_js_s: [],
status_message: "Warming up"
}
this.discussionArr.push(usrMessage)
@ -1084,6 +1085,7 @@ export default {
open : msgObj.open
}
responseMessage.status_message = "Warming up"
console.log(responseMessage)
this.discussionArr.push(responseMessage)
// nextTick(() => {
@ -1252,6 +1254,7 @@ export default {
} else if (msgObj.message_type == this.msgTypes.MSG_TYPE_STEP){
messageItem.steps.push({"message":msgObj.content,"done":true, "status":true })
} else if (msgObj.message_type == this.msgTypes.MSG_TYPE_STEP_START){
messageItem.status_message = msgObj.content
messageItem.steps.push({"message":msgObj.content,"done":false, "status":true })
} else if (msgObj.message_type == this.msgTypes.MSG_TYPE_STEP_END) {
// Find the step with the matching message and update its 'done' property to true
@ -1262,8 +1265,10 @@ export default {
try {
console.log(msgObj.parameters)
const parameters = msgObj.parameters;
if(parameters!=undefined){
matchingStep.status=parameters.status
console.log(parameters);
}
} catch (error) {
console.error('Error parsing JSON:', error.message);
@ -1552,7 +1557,6 @@ export default {
console.log("final", msgObj)
// Last message contains halucination suppression so we need to update the message content too
const parent_id = msgObj.parent_id
this.discussion_id = msgObj.discussion_id
if (this.currentDiscussion.id == this.discussion_id) {
const index = this.discussionArr.findIndex((x) => x.id == msgObj.id)
@ -1573,10 +1577,19 @@ export default {
this.isGenerating = false
this.setDiscussionLoading(this.currentDiscussion.id, this.isGenerating)
this.chime.play()
const index = this.discussionArr.findIndex((x) => x.id == msgObj.id)
const messageItem = this.discussionArr[index]
messageItem.status_message = "Done"
},
copyToClipBoard(messageEntry) {
this.$store.state.toast.showToast("Copied to clipboard successfully", 4, true)
let content = ""
if (messageEntry.message.content) {
content = messageEntry.message.content
}
if(this.$store.state.config.copy_to_clipboard_add_all_details){
let binding = ""
if (messageEntry.message.binding) {
binding = `Binding: ${messageEntry.message.binding}`
@ -1589,10 +1602,6 @@ export default {
if (messageEntry.created_at_parsed) {
time = `\nCreated: ${messageEntry.created_at_parsed}`
}
let content = ""
if (messageEntry.message.content) {
content = messageEntry.message.content
}
let model = ""
if (messageEntry.message.model) {
model = `Model: ${messageEntry.message.model}`
@ -1609,8 +1618,15 @@ export default {
bottomRow = `${binding} ${model} ${seed} ${time_spent}`.trim()
const result = `${messageEntry.message.sender}${personality}${time}\n\n${content}\n\n${bottomRow}`
navigator.clipboard.writeText(result);
}
else{
navigator.clipboard.writeText(content);
}
this.$store.state.toast.showToast("Copied to clipboard successfully", 4, true)
nextTick(() => {
feather.replace()

View File

@ -104,8 +104,6 @@
<div>
<div v-if="vramUsage&&vramUsage.gpus && vramUsage.gpus.length == 1">
<div class="flex gap-2 items-center " v-for="item in vramUsage.gpus">
<!-- GPU IMAGE -->
<img :src="SVGGPU" width="25" height="25">
@ -267,6 +265,25 @@
>
</td>
</tr>
<tr>
<td style="min-width: 200px;">
<label for="copy_to_clipboard_add_all_details" class="text-sm font-bold" style="margin-right: 1rem;">Add details to messages copied to clipboard:</label>
</td>
<td>
<div class="flex flex-row">
<input
type="checkbox"
id="copy_to_clipboard_add_all_details"
required
v-model="configFile.copy_to_clipboard_add_all_details"
@change="settingsChanged=true"
class="m-2 h-50 w-50 py-1 border border-gray-300 rounded dark:bg-gray-600 "
>
</div>
</td>
</tr>
<tr>
<td style="min-width: 200px;">
<label for="auto_show_browser" class="text-sm font-bold" style="margin-right: 1rem;">Auto show browser:</label>
@ -2208,7 +2225,6 @@
@close-dialog="oncloseVariantChoiceDialog"
@choice-validated="onvalidateVariantChoice"
/>
<PersonalityEditor ref="personality_editor" :config="currentPersonConfig" :personality="selectedPersonality" ></PersonalityEditor>
</template>
<style scoped>
@ -2314,7 +2330,6 @@ import Card from "@/components/Card.vue"
import RadioOptions from '../components/RadioOptions.vue';
import ExtensionEntry from "@/components/ExtensionEntry.vue"
import PersonalityEditor from "@/components/PersonalityEditor.vue"
import {refreshHardwareUsage} from "../main"
@ -2334,8 +2349,7 @@ export default {
ChoiceDialog,
Card,
RadioOptions,
ExtensionEntry,
PersonalityEditor
ExtensionEntry
},
data() {
@ -2361,18 +2375,8 @@ export default {
"Hungarian": "hu",
"Hindi": "hi"
},
showPersonalityEditor: false,
selectedPersonality:null,
currentPersonConfig: {
ai_name: '',
ai_author: '',
ai_category: '',
ai_language: '',
ai_description: '',
ai_conditionning: '',
ai_disclaimer: '',
ai_icon: null,
},
binding_changed:false,
SVGGPU:SVGGPU,
models_zoo:[],
@ -4246,10 +4250,10 @@ export default {
console.log("Done")
if (data.status) {
// Update the currentPersonConfig with the received data
this.currentPersonConfig = data.config;
this.showPersonalityEditor = true;
this.$refs.personality_editor.showPanel()
this.selectedPersonality = pers
this.$store.state.currentPersonConfig = data.config;
this.$store.state.showPersonalityEditor = true;
this.$store.state.personality_editor.showPanel()
this.$store.state.selectedPersonality = pers
} else {
// Handle the error
console.error(data.error);

@ -1 +1 @@
Subproject commit 29b6e9a0a9a3ee79ad0fed9516b42f92d5cb510c
Subproject commit 46f3c456af13c2e1dfc4f054b794c2cb1fcb040f