enhanced ui

This commit is contained in:
saloui 2023-07-20 11:44:33 +02:00
parent 4c46dbf094
commit f6991ecb44
8 changed files with 195 additions and 69 deletions

10
app.py
View File

@ -174,6 +174,10 @@ class LoLLMsWebUI(LoLLMsAPPI):
self.add_endpoint( self.add_endpoint(
"/list_bindings", "list_bindings", self.list_bindings, methods=["GET"] "/list_bindings", "list_bindings", self.list_bindings, methods=["GET"]
) )
self.add_endpoint(
"/list_extensions", "list_extensions", self.list_extensions, methods=["GET"]
)
self.add_endpoint( self.add_endpoint(
"/list_models", "list_models", self.list_models, methods=["GET"] "/list_models", "list_models", self.list_models, methods=["GET"]
) )
@ -677,6 +681,10 @@ class LoLLMsWebUI(LoLLMsAPPI):
print(f"Couldn't load backend card : {f}\n\t{ex}") print(f"Couldn't load backend card : {f}\n\t{ex}")
return jsonify(bindings) return jsonify(bindings)
def list_extensions(self):
return jsonify([])
def list_models(self): def list_models(self):
if self.binding is not None: if self.binding is not None:
@ -1312,7 +1320,7 @@ class LoLLMsWebUI(LoLLMsAPPI):
def upload_avatar(self): def upload_avatar(self):
file = request.files['avatar'] file = request.files['avatar']
file.save(self.lollms_paths.personal_user_infos_path/file.filename) file.save(self.lollms_paths.personal_user_infos_path/file.filename)
return jsonify({"status": True,"file":file.filename}) return jsonify({"status": True,"fileName":file.filename})

File diff suppressed because one or more lines are too long

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"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI - Welcome</title> <title>LoLLMS WebUI - Welcome</title>
<script type="module" crossorigin src="/assets/index-45195456.js"></script> <script type="module" crossorigin src="/assets/index-4c5ae20c.js"></script>
<link rel="stylesheet" href="/assets/index-2014a4be.css"> <link rel="stylesheet" href="/assets/index-562b86e9.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@ -27,8 +27,7 @@ export const store = createStore({
diskUsage:null, diskUsage:null,
ramUsage:null, ramUsage:null,
vramUsage:null, vramUsage:null,
extensionsZoo:null,
} }
}, },
mutations: { mutations: {
@ -63,6 +62,9 @@ export const store = createStore({
state.vramUsage = vramUsage; state.vramUsage = vramUsage;
}, },
setExtensionsZoo(state, extensionsZoo) {
state.extensionsZoo = extensionsZoo;
},
setModelsZoo(state, modelsZoo) { setModelsZoo(state, modelsZoo) {
state.models_zoo = modelsZoo; state.models_zoo = modelsZoo;
}, },
@ -104,6 +106,9 @@ export const store = createStore({
getModelsZoo(state) { getModelsZoo(state) {
return state.models_zoo; return state.models_zoo;
}, },
getExtensionsZoo(state) {
return state.extensionsZoo;
},
}, },
actions: { actions: {
@ -192,6 +197,10 @@ export const store = createStore({
let modelsArr = await api_get_req("list_models") let modelsArr = await api_get_req("list_models")
commit('setModelsArr',modelsArr) commit('setModelsArr',modelsArr)
}, },
async refreshExtensionsZoo({ commit }) {
let extensionsZoo = await api_get_req("list_extensions")
commit('setExtensionsZoo',extensionsZoo)
},
async refreshDiskUsage({ commit }) { async refreshDiskUsage({ commit }) {
this.state.diskUsage = await api_get_req("disk_usage") this.state.diskUsage = await api_get_req("disk_usage")
@ -350,6 +359,8 @@ app.mixin({
this.$store.dispatch('refreshRamUsage'); this.$store.dispatch('refreshRamUsage');
this.$store.dispatch('refreshVramUsage'); this.$store.dispatch('refreshVramUsage');
this.$store.dispatch('refreshModelsZoo'); this.$store.dispatch('refreshModelsZoo');
this.$store.dispatch('refreshExtensionsZoo');
this.$store.state.ready = true this.$store.state.ready = true
console.log("done loading data") console.log("done loading data")

View File

@ -50,9 +50,10 @@
<div class=" sticky z-10 top-0 bg-bg-light-tone dark:bg-bg-dark-tone shadow-md"> <div class=" sticky z-10 top-0 bg-bg-light-tone dark:bg-bg-dark-tone shadow-md">
<!-- CONTROL PANEL --> <!-- CONTROL PANEL -->
<div class="flex-row p-4 flex items-center gap-3 flex-0"> <div class="flex-row p-4 flex items-center gap-3 flex-0">
<!-- MAIN BUTTONS --> <!-- MAIN BUTTONS -->
<button class="text-2xl hover:text-secondary duration-75 active:scale-90" title="Create new discussion" <button class="text-2xl hover:text-secondary duration-75 active:scale-90" title="Create new discussion"
type="button" @click="createNewDiscussion()"> type="button" @click="createNewDiscussion()">
@ -84,6 +85,21 @@
type="button" @click="isSearch = !isSearch" :class="isSearch ? 'text-secondary' : ''"> type="button" @click="isSearch = !isSearch" :class="isSearch ? 'text-secondary' : ''">
<i data-feather="search"></i> <i data-feather="search"></i>
</button> </button>
<button v-if="!showConfirmation" title="Save configuration" class="text-2xl hover:text-secondary duration-75 active:scale-90"
@click="showConfirmation = true">
<i data-feather="save"></i>
</button>
<!-- SAVE CONFIG -->
<div v-if="showConfirmation" class="flex gap-3 flex-1 items-center duration-75">
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 " title="Cancel" type="button"
@click.stop="showConfirmation = false">
<i data-feather="x"></i>
</button>
<button class="text-2xl hover:text-secondary duration-75 active:scale-90" title="Confirm save changes"
type="button" @click.stop="save_configuration()">
<i data-feather="check"></i>
</button>
</div>
<div v-if="loading" title="Loading.." class="flex flex-row flex-grow justify-end"> <div v-if="loading" title="Loading.." class="flex flex-row flex-grow justify-end">
<!-- SPINNER --> <!-- SPINNER -->
<div role="status"> <div role="status">
@ -252,6 +268,7 @@
<Toast ref="toast"> <Toast ref="toast">
</Toast> </Toast>
<MessageBox ref="messageBox" />
</template> </template>
@ -382,6 +399,26 @@ export default {
} }
}, },
methods: { methods: {
save_configuration() {
this.showConfirmation = false
axios.post('/save_settings', {})
.then((res) => {
if (res) {
if (res.status) {
// this.$refs.messageBox.showMessage("Settings saved!")
}
else
this.$refs.messageBox.showMessage("Error: Couldn't save settings!")
return res.data;
}
})
.catch(error => {
console.log(error.message, 'save_configuration')
this.$refs.messageBox.showMessage("Couldn't save settings!")
return { 'status': false }
});
},
showToastMessage(text){ showToastMessage(text){
console.log("sending",text) console.log("sending",text)
this.$refs.toast.showToast(text, 4, true) this.$refs.toast.showToast(text, 4, true)
@ -809,7 +846,7 @@ export default {
let responseMessage = { let responseMessage = {
//content:msgObj.data, //content:msgObj.data,
content: "✍ please stand by ...",//msgObj.message, content: msgObj.message,// " please stand by ...",//msgObj.message,
created_at:msgObj.created_at, created_at:msgObj.created_at,
binding:msgObj.binding, binding:msgObj.binding,
model:msgObj.model, model:msgObj.model,
@ -820,7 +857,6 @@ export default {
sender: msgObj.bot, sender: msgObj.bot,
type:msgObj.type, type:msgObj.type,
steps: [] steps: []
//type: msgObj.type
} }
this.discussionArr.push(responseMessage) this.discussionArr.push(responseMessage)
@ -1398,9 +1434,13 @@ export default {
}) })
}, },
getAvatar(sender) { getAvatar(sender) {
if (sender.toLowerCase().trim() == this.$store.state.config.user_name.toLowerCase().trim()){
return "user_infos/"+this.$store.state.config.user_avatar
}
const index = this.personalityAvatars.findIndex((x) => x.name === sender) const index = this.personalityAvatars.findIndex((x) => x.name === sender)
const pers = this.personalityAvatars[index] const pers = this.personalityAvatars[index]
if (pers) { if (pers) {
console.log("Avatar",pers.avatar)
return pers.avatar return pers.avatar
} }
@ -1584,6 +1624,7 @@ import Message from '../components/Message.vue'
import ChatBox from '../components/ChatBox.vue' import ChatBox from '../components/ChatBox.vue'
import WelcomeComponent from '../components/WelcomeComponent.vue' import WelcomeComponent from '../components/WelcomeComponent.vue'
import Toast from '../components/Toast.vue' import Toast from '../components/Toast.vue'
import MessageBox from "@/components/MessageBox.vue";
import DragDrop from '../components/DragDrop.vue' import DragDrop from '../components/DragDrop.vue'
import feather from 'feather-icons' import feather from 'feather-icons'

View File

@ -1,16 +1,41 @@
<template> <template>
<div> <div>
Extensions <div v-for="extension in activeExtensions" :key="extension.name" @click="showExtensionPage(extension)">
<div :class="{ 'active-tab': extension === activeExtension }">{{ extension.name }}</div>
</div>
<div v-if="activeExtension">
<!-- Render the selected extension's page here -->
<iframe :src="activeExtension.page" width="100%" height="500px" frameborder="0"></iframe>
</div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
setup () { data() {
return {
activeExtension: null,
return {} };
} },
} computed: {
activeExtensions() {
// Filter the extensions to get only active ones
return this.$store.state.extensionsZoo.filter((extension) => extension.is_active);
},
},
methods: {
showExtensionPage(extension) {
// Set the selected extension as active to render its page
this.activeExtension = extension;
},
},
};
</script> </script>
<style>
.active-tab {
/* Style the active tab as you like */
font-weight: bold;
}
</style>

View File

@ -533,7 +533,28 @@
<table style="width: 100%;"> <table style="width: 100%;">
<!-- Row 1 --> <tr>
<td style="min-width: 200px;">
<label for="enable_gpu" class="text-sm font-bold" style="margin-right: 1rem;">Enable GPU:</label>
</td>
<td>
<input
type="checkbox"
id="enable_gpu"
required
v-model="enable_gpu"
class="mt-1 px-2 py-1 border border-gray-300 rounded"
>
</td>
<td>
<button
class="hover:text-secondary bg-blue-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"
@click="update_setting('enable_gpu', enable_gpu)"
>
<i data-feather="check"></i>
</button>
</td>
</tr>
<tr> <tr>
<td style="min-width: 200px;"> <td style="min-width: 200px;">
<label for="auto_update" class="text-sm font-bold" style="margin-right: 1rem;">Auto update:</label> <label for="auto_update" class="text-sm font-bold" style="margin-right: 1rem;">Auto update:</label>
@ -547,12 +568,12 @@
class="mt-1 px-2 py-1 border border-gray-300 rounded" class="mt-1 px-2 py-1 border border-gray-300 rounded"
> >
</td> </td>
<td style="min-width: 300px;"> <td>
<button <button
class="hover:text-secondary bg-blue-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="hover:text-secondary bg-blue-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"
@click="update_setting('auto_update', auto_update)" @click="update_setting('auto_update', auto_update)"
> >
Validate <i data-feather="check"></i>
</button> </button>
</td> </td>
</tr> </tr>
@ -571,12 +592,12 @@
class="w-full mt-1 px-2 py-1 border border-gray-300 rounded" class="w-full mt-1 px-2 py-1 border border-gray-300 rounded"
> >
</td> </td>
<td style="min-width: 300px;"> <td>
<button <button
class="hover:text-secondary bg-blue-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="hover:text-secondary bg-blue-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"
@click="update_setting('db_path', db_path)" @click="update_setting('db_path', db_path)"
> >
Select Database <i data-feather="check"></i>
</button> </button>
</td> </td>
</tr> </tr>
@ -595,12 +616,12 @@
class="w-full mt-1 px-2 py-1 border border-gray-300 rounded" class="w-full mt-1 px-2 py-1 border border-gray-300 rounded"
> >
</td> </td>
<td style="min-width: 300px;"> <td>
<button <button
class="hover:text-secondary bg-blue-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="hover:text-secondary bg-blue-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"
@click="update_setting('user_name', userName)" @click="update_setting('user_name', userName)"
> >
Validate <i data-feather="check"></i>
</button> </button>
</td> </td>
</tr> </tr>
@ -615,12 +636,12 @@
</label> </label>
<input type="file" id="avatar-upload" style="display: none" @change="uploadAvatar"> <input type="file" id="avatar-upload" style="display: none" @change="uploadAvatar">
</td> </td>
<td style="min-width: 300px;"> <td>
<button <button
class="hover:text-secondary bg-blue-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="hover:text-secondary bg-blue-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"
@click="update_setting('user_name', userName)" @click="update_setting('user_name', userName)"
> >
Validate <i data-feather="check"></i>
</button> </button>
</td> </td>
</tr> </tr>
@ -638,12 +659,12 @@
class=" mt-1 px-2 py-1 border border-gray-300 rounded" class=" mt-1 px-2 py-1 border border-gray-300 rounded"
> >
</td> </td>
<td style="min-width: 300px;"> <td>
<button <button
class="hover:text-secondary bg-blue-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="hover:text-secondary bg-blue-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"
@click="update_setting('use_user_name_in_discussions', use_user_name_in_discussions)" @click="update_setting('use_user_name_in_discussions', use_user_name_in_discussions)"
> >
Validate <i data-feather="check"></i>
</button> </button>
</td> </td>
</tr> </tr>
@ -1644,8 +1665,10 @@ export default {
axios.post('/upload_avatar', formData) axios.post('/upload_avatar', formData)
.then(response => { .then(response => {
console.log("Avatar uploaded successfully") console.log("Avatar uploaded successfully")
this.$refs.toast.showToast("Avatar uploaded successfully!", 4, true)
// Assuming the server responds with the file name after successful upload // Assuming the server responds with the file name after successful upload
const fileName = response.fileName; const fileName = response.data.fileName;
console.log("response",response);
this.user_avatar = fileName; // Update the user_avatar value with the file name this.user_avatar = fileName; // Update the user_avatar value with the file name
this.update_setting("user_avatar", fileName, ()=>{}).then(()=>{}) this.update_setting("user_avatar", fileName, ()=>{}).then(()=>{})
}) })
@ -2355,8 +2378,13 @@ export default {
if (res) { if (res) {
this.isLoading = false this.isLoading = false
console.log('update_setting', res) console.log('update_setting', res)
if(res['status']){
this.$refs.toast.showToast("Setting updated successfully.\nDon't forget to save to keep the setting permanently.", 4, true)
}
else{
this.$refs.toast.showToast("Setting update failed.\nPlease view the console for more details.", 4, false)
}
if (next !== undefined) { if (next !== undefined) {
next(res) next(res)
} }
return res.data; return res.data;
@ -2869,6 +2897,17 @@ export default {
this.$store.state.config.user_avatar = value this.$store.state.config.user_avatar = value
}, },
}, },
enable_gpu:{
get() {
return this.$store.state.config.enable_gpu;
},
set(value) {
// You should not set the value directly here; use the updateSetting method instead
this.$store.state.config.enable_gpu = value
},
},
auto_update:{ auto_update:{
get() { get() {
return this.$store.state.config.auto_update; return this.$store.state.config.auto_update;