upgraded ui to v 6.5

This commit is contained in:
Saifeddine ALOUI 2023-09-13 01:23:06 +02:00
parent b5d94f104f
commit e547bee9ad
11 changed files with 300 additions and 364 deletions

View File

@ -215,10 +215,15 @@ class LoLLMsAPPI(LollmsApplication):
def install_model_():
print("Install model triggered")
model_path = data["path"]
model_type:str=data["type"]
progress = 0
installation_dir = self.lollms_paths.personal_models_path/self.config["binding_name"]
filename = Path(model_path).name
installation_path = installation_dir / filename
if model_type=="gptq":
filename = model_path.split("/")[4]
installation_path = installation_dir / filename
else:
filename = Path(model_path).name
installation_path = installation_dir / filename
print("Model install requested")
print(f"Model path : {model_path}")
@ -378,15 +383,20 @@ class LoLLMsAPPI(LollmsApplication):
@socketio.on('uninstall_model')
def uninstall_model(data):
model_path = data['path']
model_type:str=data["type"]
installation_dir = self.lollms_paths.personal_models_path/self.config["binding_name"]
filename = Path(model_path).name
installation_path:Path = installation_dir / filename
model_name = filename
binding_folder = self.config["binding_name"]
if model_type=="gptq":
filename = model_path.split("/")[4]
installation_path = installation_dir / filename
else:
filename = Path(model_path).name
installation_path = installation_dir / filename
model_name = filename
if not installation_path.exists():
socketio.emit('install_progress',{
socketio.emit('uninstall_progress',{
'status': False,
'error': 'The model does not exist',
'model_name' : model_name,
@ -397,7 +407,7 @@ class LoLLMsAPPI(LollmsApplication):
shutil.rmtree(installation_path)
else:
installation_path.unlink()
socketio.emit('install_progress',{
socketio.emit('uninstall_progress',{
'status': True,
'error': '',
'model_name' : model_name,
@ -406,7 +416,7 @@ class LoLLMsAPPI(LollmsApplication):
except Exception as ex:
trace_exception(ex)
ASCIIColors.error(f"Couldn't delete {installation_path}, please delete it manually and restart the app")
socketio.emit('install_progress',{
socketio.emit('uninstall_progress',{
'status': False,
'error': f"Couldn't delete {installation_path}, please delete it manually and restart the app",
'model_name' : model_name,

54
app.py
View File

@ -14,7 +14,7 @@ __github__ = "https://github.com/ParisNeo/lollms-webui"
__copyright__ = "Copyright 2023, "
__license__ = "Apache 2.0"
__version__ ="6.3"
__version__ ="6.5"
main_repo = "https://github.com/ParisNeo/lollms-webui.git"
import os
@ -765,7 +765,7 @@ class LoLLMsWebUI(LoLLMsAPPI):
elif setting_name== "override_personality_model_parameters":
self.config["override_personality_model_parameters"]=bool(data['setting_value'])
elif setting_name== "model_name":
elif setting_name == "model_name":
self.config["model_name"]=data['setting_value']
if self.config["model_name"] is not None:
try:
@ -1812,55 +1812,7 @@ class LoLLMsWebUI(LoLLMsAPPI):
if self.binding is None:
return jsonify([])
model_list = self.binding.get_available_models()
models = []
ASCIIColors.yellow("Recovering available models")
for model in model_list:
try:
filename = model.get('filename',"")
server = model.get('server',"")
variants = model.get('variants',[])
image_url = model.get("icon", '/images/default_model.png')
license = model.get("license", 'unknown')
owner = model.get("owner", 'unknown')
patreon = model.get("patreon", '')
model_type = self.config.binding_name
owner_link = model.get("owner_link", 'https://github.com/ParisNeo')
filesize = int(model.get('filesize',0))
description = model.get('description',"")
model_type = model.get("model_type","")
if server.endswith("/"):
path = f'{server}{filename}'
else:
path = f'{server}/{filename}'
blocs = filename.split("/")
# Special case, if hugging face model format
if len(blocs)==2:
filename = blocs[1]
local_path = lollms_paths.personal_models_path/f'{self.config["binding_name"]}/{filename}'
is_installed = local_path.exists() or model_type.lower()=="api"
models.append({
'title': filename,
'variants': variants,
'icon': image_url, # Replace with the path to the model icon
'license': license,
'owner': owner,
'patreon': patreon,
'type': model_type,
'owner_link': owner_link,
'description': description,
'isInstalled': is_installed,
'path': path,
'filesize': filesize,
'model_type': model_type
})
except Exception as ex:
print("#################################")
print(ex)
print("#################################")
print(f"Problem with model : {model}")
return jsonify(models)
return jsonify(model_list)
def train(self):

File diff suppressed because one or more lines are too long

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

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-236be334.js"></script>
<link rel="stylesheet" href="/assets/index-b0332756.css">
<script type="module" crossorigin src="/assets/index-7158f20c.js"></script>
<link rel="stylesheet" href="/assets/index-7dad82f8.css">
</head>
<body>
<div id="app"></div>

View File

@ -124,7 +124,7 @@
<div class="flex flex-row flex-grow items-center gap-2 overflow-visible">
<InteractiveMenu
:title="selectedModel"
:sendCommand="setModel"
:execute_cmd="setModel"
:icon="models_menu_icon"
:commands="commandify(models)"
:selected_entry="selectedModel"></InteractiveMenu>
@ -343,20 +343,20 @@ export default {
},
setModel(selectedModel){
console.log("Setting model to "+selectedModel);
this.selecting_model=true
this.selectedModel = selectedModel
axios.post("/update_setting", {
setting_name: "model_name",
setting_value: selectedModel
}).then((response) => {
console.log(response);
this.$refs.toast.showToast(`Model changed to ${selectedModel}`,4,true)
this.selecting_model=false
}).catch(err=>{
this.$refs.toast.showToast(`Error ${err}`,4,true)
this.selecting_model=false
});
console.log("Setting model to "+selectedModel);
this.selecting_model=true
this.selectedModel = selectedModel
axios.post("/update_setting", {
setting_name: "model_name",
setting_value: selectedModel.value
}).then((response) => {
console.log(response);
this.$refs.toast.showToast(`Model changed to ${selectedModel.value}`,4,true)
this.selecting_model=false
}).catch(err=>{
this.$refs.toast.showToast(`Error ${err}`,4,true)
this.selecting_model=false
});
},
clear_files(){

View File

@ -1,16 +1,18 @@
<template>
<div
class="relative items-start p-4 hover:bg-primary-light hover:border-primary-light rounded-lg mb-2 shadow-lg border-2 cursor-pointer select-none"
class="relative items-start p-4 hover:bg-primary-light rounded-lg mb-2 shadow-lg border-2 cursor-pointer select-none"
:class="computed_classes"
:title="title">
:title="model.name">
<!-- CUSTOM MODEL VIEW -->
<div class="flex flex-row" v-if="model.isCustomModel">
<div class="max-w-[300px] overflow-x-auto">
<div class="flex gap-3 items-center grow">
<img :src="getImgUrl()" @error="defaultImg($event)" class="w-10 h-10 rounded-lg object-fill">
<a :href="model.model_creator_link" target="_blank">
<img :src="getImgUrl()" @error="defaultImg($event)" class="w-10 h-10 rounded-lg object-fill">
</a>
<div class="flex-1 overflow-hidden">
<h3 class="font-bold font-large text-lg truncate">
{{ title }}
{{ model.name }}
</h3>
</div>
</div>
@ -32,7 +34,7 @@
<button v-if="model.isInstalled" type="button" title="Select"
@click="toggleSelected"
class="hover:text-secondary duration-75 active:scale-90 font-medium rounded-lg text-sm p-2 text-center inline-flex items-center " @click.stop="">
<i data-feather="check" class="w-5"></i>
<i data-feather="check" :class="selected?'border-2 border-blue-300 w-5':'w-5'"></i>
<span class="sr-only">Select</span>
</button>
@ -110,7 +112,7 @@
<img ref="imgElement" :src="getImgUrl()" @error="defaultImg($event)" class="w-10 h-10 rounded-lg object-fill"
:class="linkNotValid ? 'grayscale' : ''">
<h3 class="font-bold font-large text-lg truncate">
{{ title }}
{{ model.name }}
</h3>
<div class="grow">
<!-- EMPTY SPACE FILLER -->
@ -118,7 +120,7 @@
<button v-if="model.isInstalled" type="button" title="Select"
@click="toggleSelected"
class="hover:text-secondary duration-75 active:scale-90 font-medium rounded-lg text-sm p-2 text-center inline-flex items-center " @click.stop="">
<i data-feather="check" class="w-5"></i>
<i data-feather="check" :class="selected?'border-2 border-blue-300 rounded bg-green-300 w-5':'border-2 border-blue-300 rounded bg-gray-100 w-5'"></i>
<span class="sr-only">Select</span>
</button>
@ -140,7 +142,7 @@
</div>
<div class="" :title="!model.isInstalled ? 'Not installed' : title">
<div class="" :title="!model.isInstalled ? 'Not installed' : model.name">
<div class="">
<!-- <div class="flex flex-row items-center ">
@ -152,16 +154,13 @@
<div class="flex flex-row items-center ">
<i data-feather="download" class="w-5 m-1 flex-shrink-0"></i>
<b>Manual download:&nbsp;</b>
<b>Card:&nbsp;</b>
<a :href="path" @click.stop
<a :href="'https://huggingface.co/'+model.quantizer+'/'+model.name" target="_blank" @click.stop
class="m-1 flex items-center hover:text-secondary duration-75 active:scale-90 truncate"
:title="linkNotValid ? 'Link is not valid' : 'Download this manually (faster) and put it in the models/<current binding> folder then refresh'">
Click here to download
View full model card
</a>
<div class="grow"></div>
@ -186,72 +185,51 @@
<div class="flex items-center">
<i data-feather="key" class="w-5 m-1"></i>
<b>License:&nbsp;</b>
{{ license }}
{{ model.license }}
</div>
<div class="flex items-center">
<i data-feather="user" class="w-5 m-1"></i>
<b>Owner:&nbsp;</b>
<a :href="owner_link" target="_blank" rel="noopener noreferrer" @click.stop
class="flex hover:text-secondary duration-75 active:scale-90" title="Owner's profile">
<b>quantizer:&nbsp;</b>
<a :href="'https://huggingface.co/'+model.quantizer" target="_blank" rel="noopener noreferrer" @click.stop
class="flex hover:text-secondary duration-75 active:scale-90" title="quantizer's profile">
{{ owner }}
{{ model.quantizer }}
</a>
</div>
<div class="flex items-center">
<i data-feather="user" class="w-5 m-1"></i>
<b>Model creator:&nbsp;</b>
<a :href="model.model_creator_link" target="_blank" rel="noopener noreferrer" @click.stop
class="flex hover:text-secondary duration-75 active:scale-90" title="quantizer's profile">
{{ model.model_creator }}
</a>
</div>
<div class="flex items-center">
<i data-feather="clock" class="w-5 m-1"></i>
<b>Release date:&nbsp;</b>
{{ model.last_commit_time }}
</div>
<div class="flex items-center">
<i data-feather="grid" class="w-5 m-1"></i>
<b>Category:&nbsp;</b>
<a :href="'https://huggingface.co/'+model.model_creator" target="_blank" rel="noopener noreferrer" @click.stop
class="flex hover:text-secondary duration-75 active:scale-90" title="quantizer's profile">
{{ model.category }}
</a>
</div>
<div class="flex items-center">
<i data-feather="user" class="w-5 m-1"></i>
<b>Hugging face rank:&nbsp;</b>
<a href="https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard" target="_blank" rel="noopener noreferrer" @click.stop
class="flex hover:text-secondary duration-75 active:scale-90" title="quantizer's profile">
{{ model.rank }}
</a>
</div>
</div>
<div v-if="patreon!=''" class="flex items-center">
<i class="w-5 m-1 pr-2">
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="15"
height="15"
id="svg3168"
version="1.1"
inkscape:version="0.48.4 r9939"
viewBox="0 0 541.4375 541.43744"
sodipodi:docname="Patreon">
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-78.58618,-210.44369)">
<path
inkscape:connector-curvature="0"
id="path3204"
d="m 349.30488,210.44369 c -149.51545,0 -270.7187,121.20325 -270.7187,270.71875 l 0,270.4687 259.375,0 c 3.7608,0.155 7.5448,0.25 11.3437,0.25 149.5155,0 270.7188,-121.2032 270.7188,-270.7187 0,-149.5155 -121.2033,-270.71875 -270.7188,-270.71875 z"
style="fill:#ff5900;fill-opacity:1;stroke:none" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 349.30493,273.28744 c -114.80003,0 -207.875,93.07494 -207.875,207.875 l 0,123.90625 0,83.75 0,62.8125 83.1875,0 0,-270.25 c 0,-68.64109 55.64016,-124.3125 124.28125,-124.3125 68.64109,0 124.28125,55.67141 124.28125,124.3125 0,68.64109 -55.64016,124.28125 -124.28125,124.28125 -25.09566,0 -48.463,-7.45836 -68,-20.25 l 0,89.34375 c 13.09042,8.05513 42.97659,13.74429 78.03125,14.03125 110.32856,-5.03362 198.25,-96.05383 198.25,-207.625 0,-114.80006 -93.07493,-207.875 -207.875,-207.875 z m -8.71875,415.53125 c 2.8876,0.1191 5.80191,0.21875 8.71875,0.21875 3.07049,0 6.11821,-0.087 9.15625,-0.21875 l -17.875,0 z"
id="path3192"
inkscape:connector-curvature="0" />
</g>
</svg>
</i>
<b>Patreon:&nbsp;</b>
<!-- <p class="mx-1 opacity-80 line-clamp-3" :title="description">{{ description }}</p> -->
<a :href="patreon" class="mx-1 opacity-80 line-clamp-3 overflow-y_auto" :title="description">{{ patreon }}</a>
<!-- <p class="mx-1 opacity-80 line-clamp-3" :title="description"><span v-html="description"></span></p> -->
</div>
<div class="flex items-center">
<i data-feather="info" class="w-5 m-1"></i>
<b>Description:&nbsp;</b><br>
</div>
<!-- <p class="mx-1 opacity-80 line-clamp-3" :title="description">{{ description }}</p> -->
<p class="mx-1 opacity-80 line-clamp-3 overflow-y_auto" :title="description">{{ description.replace(/<\/?[^>]+>/ig, " ") }}</p>
<!-- <p class="mx-1 opacity-80 line-clamp-3" :title="description"><span v-html="description"></span></p> -->
</div>
</div>
@ -274,14 +252,6 @@ const bUrl = import.meta.env.VITE_LOLLMS_API_BASEURL
export default {
components:{InteractiveMenu},
props: {
title: String,
icon: String,
path: String,
owner: String,
owner_link: String,
license: String,
patreon: String,
description: String,
isInstalled: Boolean,
onInstall: Function,
onCancelInstall: Function,
@ -308,8 +278,6 @@ export default {
};
},
async mounted() {
//this.fileSize = await this.getFileSize(this.model.path)
//console.log('model path', this.model.path)
nextTick(() => {
feather.replace()
@ -330,65 +298,17 @@ export default {
},
computedFileSize(size) {
return filesize(size)
},
async getFileSize(url) {
if (this.model_type != "api") {
try {
const res = await axios.head(url)
if (res) {
if (res.headers["content-length"]) {
return this.computedFileSize(res.headers["content-length"])
}
if (this.model.filesize) {
return this.computedFileSize(this.model.filesize)
}
return 'Could not be determined'
}
if (this.model.filesize) {
return this.computedFileSize(this.model.filesize)
}
return 'Could not be determined'
// Example response
// {
// date: 'Tue, 03 Apr 2018 14:29:32 GMT',
// 'content-type': 'application/javascript; charset=utf-8',
// 'content-length': '9068',
// connection: 'close',
// 'last-modified': 'Wed, 28 Feb 2018 04:16:30 GMT',
// etag: '"5a962d1e-236c"',
// expires: 'Sun, 24 Mar 2019 14:29:32 GMT',
// 'cache-control': 'public, max-age=30672000',
// 'access-control-allow-origin': '*',
// 'cf-cache-status': 'HIT',
// 'accept-ranges': 'bytes',
// 'strict-transport-security': 'max-age=15780000; includeSubDomains',
// 'expect-ct': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"',
// server: 'cloudflare',
// 'cf-ray': '405c3a5cba7a68ba-CDG'
// }
} catch (error) {
console.log(error.message, 'getFileSize')
//this.linkNotValid = true
return 'Could not be determined'
}
}
},
getImgUrl() {
if (this.icon === '/images/default_model.png') {
if(this.model.icon==undefined){
return defaultImgPlaceholder
}
if (this.model.icon === '/images/default_model.png') {
return defaultImgPlaceholder
}
return this.icon
return this.model.icon
},
defaultImg(event) {
event.target.src = defaultImgPlaceholder
@ -435,7 +355,6 @@ export default {
return 'border-transparent'
}
if(this.selected){
console.log("Selected")
return 'border-4 border-gray-200 bg-primary'
}
return 'border-0 border-primary bg-primary'

View File

@ -16,6 +16,7 @@ export const store = createStore({
// count: 0,
ready:false,
version : "unknown",
sort_type : 0, // 0: by date, 1: by rank, 2: by name, 3: by maker, 4: by quantizer
refreshingModelsList:false,
settingsChanged:false,
isConnected: false, // Add the isConnected property
@ -190,13 +191,9 @@ export const store = createStore({
mountedPersArr.push(this.state.personalities[this.state.personalities.findIndex(item => item.full_path == "generic/lollms")])
}
}
console.log("Personalities list",this.state.personalities)
commit('setMountedPersArr', mountedPersArr);
console.log("active_personality_id",this.state.config.active_personality_id)
console.log("selected pers",this.state.config.personalities[this.state.config.active_personality_id])
this.state.mountedPers = this.state.personalities[this.state.personalities.findIndex(item => item.full_path == this.state.config.personalities[this.state.config.active_personality_id])]
console.log("selected pers",this.state.mountedPers)
},
async refreshBindings({ commit }) {
@ -206,7 +203,6 @@ export const store = createStore({
async refreshModels({ commit }) {
let modelsArr = await api_get_req("list_models");
let selectedModel = await api_get_req('get_active_model');
console.log("Active model " + JSON.stringify(selectedModel))
if(selectedModel!=undefined){
commit('setselectedModel',selectedModel["model"])
}
@ -225,7 +221,6 @@ export const store = createStore({
this.state.ramUsage = await api_get_req("ram_usage")
},
async refreshVramUsage({ commit }) {
console.log("getting gpu data")
const resp = await api_get_req("vram_usage")
// {
// "gpu_0_total_vram": 11811160064,
@ -283,29 +278,68 @@ export const store = createStore({
},
async refreshModelsZoo({ commit }) {
console.log("Refreshing models zoo")
console.log(`REFRESHING models using sorting ${this.state.sort_type}`)
this.state.refreshingModelsList=true;
axios.get('/get_available_models')
.then(response => {
console.log("found models")
let models_zoo = response.data
models_zoo.sort((a, b) => a.title.localeCompare(b.title))
models_zoo = models_zoo.filter(model => model.variants && model.variants.length>0);
if(this.state.sort_type==0){ // Sort by date
models_zoo.sort((a, b) => {
const dateA = new Date(a.last_commit_time);
const dateB = new Date(b.last_commit_time);
// Compare the date objects to sort by last_commit_time
return dateB - dateA;
});
} else if(this.state.sort_type==1){ // Sort by rank
models_zoo.sort((a, b) => {
// Compare the date objects to sort by last_commit_time
return b.rank - a.rank;
});
} else if(this.state.sort_type==2){ // Sort by name
models_zoo.sort((a, b) => a.name.localeCompare(b.name))
} else if(this.state.sort_type==3){ // Sort by name
models_zoo.sort((a, b) => a.name.localeCompare(b.name))
}
// models_zoo.sort((a, b) => a.name.localeCompare(b.name))
// Returns array of model filenames which are = to title of models zoo entry
// Returns array of model filenames which are = to name of models zoo entry
for (let i = 0; i < this.state.modelsArr.length; i++) {
const customModel = this.state.modelsArr[i]
const index = models_zoo.findIndex(x => x.title == customModel)
let index = models_zoo.findIndex(x => x.name == customModel)
if(index==-1){
// The customModel is not directly in the model zoo, so check its variants
for (let j = 0; j < models_zoo.length; j++) {
let v = models_zoo[j]["variants"]
if(v!=undefined){
index = v.findIndex(x => x.name == customModel);
if(index!=-1){
console.log("Found")
break;
}
}
else{
}
}
}
if (index == -1) {
let newModelEntry = {}
newModelEntry.title = customModel
newModelEntry.path = customModel
newModelEntry.name = customModel
newModelEntry.icon = ""
newModelEntry.isCustomModel = true
newModelEntry.isInstalled = true
models_zoo.push(newModelEntry)
}
else{
models_zoo[index].isInstalled=true;
}
}
console.log("models_zoo")
models_zoo.sort((a, b) => {
if (a.isInstalled && !b.isInstalled) {
return -1; // a is installed, b is not installed, so a comes first
@ -317,7 +351,7 @@ export const store = createStore({
});
models_zoo.forEach(model => {
if (model.title == this.state.config["model_name"]) {
if (model.name == this.state.config["model_name"]) {
model.selected = true;
}
else{
@ -325,7 +359,6 @@ export const store = createStore({
}
});
commit('setModelsZoo', models_zoo)
console.log("Models zoo loaded successfully")
this.state.refreshingModelsList=false;
})
.catch(error => {

View File

@ -694,7 +694,6 @@ export default {
},
async selectDiscussion(item) {
if (item) {
console.log("this.currentDiscussion",this.currentDiscussion)
// When discussion is selected it loads the discussion array
if (this.currentDiscussion===undefined) {
this.currentDiscussion = item
@ -1177,7 +1176,6 @@ export default {
this.isSelectAll = !this.isSelectAll
},
createDiscussionList(disList) {
console.log("Creating discussions list", disList)
// This creates a discussion list for UI with additional properties
if (disList) {
const newDisList = disList.map((item) => {
@ -1197,7 +1195,6 @@ export default {
this.list = newDisList
this.tempList = newDisList
console.log("List created")
}
},
setDiscussionLoading(id, loading) {
@ -1267,10 +1264,7 @@ export default {
this.setDiscussionLoading(this.currentDiscussion.id, this.isGenerating);
axios.get('/get_generation_status', {}).then((res) => {
if (res) {
console.log("--------------------")
console.log(msgId);
if (!res.data.status) {
console.log('generate_msg_from');
socket.emit('generate_msg_from', { prompt: msg, id: msgId });
}
else {
@ -1291,7 +1285,6 @@ export default {
this.setDiscussionLoading(this.currentDiscussion.id, this.isGenerating);
axios.get('/get_generation_status', {}).then((res) => {
if (res) {
console.log(res);
if (!res.data.status) {
socket.emit('continue_generate_msg_from', { prompt: msg, id: msgId });
@ -1577,13 +1570,9 @@ export default {
await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for 100ms
}
// Constructor
console.log("Setting title")
this.setPageTitle()
console.log("listing discussions")
await this.list_discussions()
console.log("loading last discussion")
this.loadLastUsedDiscussion()
console.log("Discussions view is ready")
// socket responses
@ -1592,7 +1581,6 @@ export default {
socket.on('update_message', this.streamMessageContent)
socket.on('close_message', this.finalMsgEvent)
console.log("Setting events")
socket.onopen = () => {
console.log('WebSocket connection established.');
if (this.currentDiscussion!=null){

View File

@ -1196,6 +1196,10 @@
<input v-model="show_only_installed_models" class="m-2 p-2" type="checkbox" ref="only_installed">
<label for="only_installed">Show only installed models</label>
</div>
<div>
<!-- Pass the radio options as a prop -->
<RadioOptions :radioOptions="sortOptions" @radio-selected="handleRadioSelected" />
</div>
<div v-if="searchModel">
<div v-if="modelsFiltered.length > 0" class="mb-2">
<label for="model" class="block ml-2 mb-2 text-sm font-medium text-gray-900 dark:text-white">
@ -1206,13 +1210,11 @@
:class="mzl_collapsed ? '' : 'max-h-96'">
<TransitionGroup name="list">
<model-entry ref="modelZoo" v-for="(model, index) in show_only_installed_models?filter_installed(modelsFiltered):modelsFiltered"
:key="'index-' + index + '-' + model.title" :title="model.title" :icon="model.icon"
:path="model.path" :owner="model.owner" :owner_link="model.owner_link"
:license="model.license" :description="model.description"
:patreon="model.patreon?model.patreon:''"
:key="'index-' + index + '-' + model.name"
:model="model"
:is-installed="model.isInstalled" :on-install="onInstall"
:on-uninstall="onUninstall" :on-selected="onSelected"
:selected="model.title === configFile.model_name" :model="model"
:selected="model.name === configFile.model_name"
:model_type="model.model_type" :on-copy="onCopy" :on-copy-link="onCopyLink"
:on-cancel-install="onCancelInstall" />
</TransitionGroup>
@ -1231,13 +1233,11 @@
:class="mzl_collapsed ? '' : 'max-h-96'">
<TransitionGroup name="list">
<model-entry ref="modelZoo" v-for="(model, index) in show_only_installed_models?filter_installed(models):models"
:key="'index-' + index + '-' + model.title" :title="model.title" :icon="model.icon"
:path="model.path" :owner="model.owner" :owner_link="model.owner_link"
:license="model.license" :description="model.description"
:patreon="model.patreon?model.patreon:''"
:key="'index-' + index + '-' + model.name"
:model="model"
:is-installed="model.isInstalled" :on-install="onInstall"
:on-uninstall="onUninstall" :on-selected="onSelected"
:selected="model.title === configFile.model_name" :model="model"
:selected="model.name === configFile.model_name"
:model_type="model.model_type" :on-copy="onCopy" :on-copy-link="onCopyLink"
:on-cancel-install="onCancelInstall" />
</TransitionGroup>
@ -1837,6 +1837,7 @@ import UniversalForm from '../components/UniversalForm.vue';
import ChoiceDialog from "@/components/ChoiceDialog.vue";
import Card from "@/components/Card.vue"
import RadioOptions from '../components/RadioOptions.vue';
const bUrl = import.meta.env.VITE_LOLLMS_API_BASEURL
axios.defaults.baseURL = import.meta.env.VITE_LOLLMS_API_BASEURL
@ -1853,11 +1854,20 @@ export default {
BindingEntry,
UniversalForm,
ChoiceDialog,
Card
Card,
RadioOptions
},
data() {
return {
// Sort options
sortOptions: [
{ label: 'Sort by Date', value: 0 },
{ label: 'Sort by Rank', value: 1 },
{ label: 'Sort by Name', value: 2 },
{ label: 'Sort by Maker', value: 3 },
{ label: 'Sort by Quantizer', value: 4 },
],
show_only_installed_models:false,
// Local model reference path
reference_path:"",
@ -1924,6 +1934,19 @@ export default {
},
methods: {
async selectSortOption(index){
this.$store.state.sort_type=index
this.$store.dispatch('refreshModelsZoo');
this.modelsFiltered = this.models
console.log(`Selected sorting:${index}`)
},
handleRadioSelected(index){
this.isLoading = true;
this.selectSortOption(index).then(()=>{
this.isLoading = false;
})
},
filter_installed(models){
console.log("filtering")
return models.filter(element => element.isInstalled === true);
@ -1961,10 +1984,14 @@ export default {
this.$refs.toast.showToast("Link is not valid, file does not exist", 4, false)
return
}
let path = model_object.path;
let path = 'https://huggingface.co/'+model_object.model.quantizer+'/'+model_object.model.name+'/resolve/main/'+this.selected_variant.name;
this.showProgress = true;
this.progress = 0;
this.addModel = { model_name: this.selected_variant.name, binding_folder: this.configFile.binding_name, model_url: model_object.path }
this.addModel = {
model_name: this.selected_variant.name,
binding_folder: this.configFile.binding_name,
model_url: path
}
console.log("installing...", this.addModel);
// Use an arrow function for progressListener
@ -1980,7 +2007,7 @@ export default {
model_object.start_time = response.start_time
model_object.installing = true
if (model_object.progress == 100) {
const index = this.models.findIndex((model) => model.path === path);
const index = this.models.findIndex((model) => model.name === model_object.model.name);
this.models[index].isInstalled = true;
this.showProgress = false;
model_object.installing = false
@ -1990,7 +2017,7 @@ export default {
console.log("Installed successfully")
// Update the isInstalled property of the corresponding model
this.$refs.toast.showToast("Model:\n" + model_object.title + "\ninstalled!", 4, true)
this.$refs.toast.showToast("Model:\n" + model_object.model.name + "\ninstalled!", 4, true)
this.$store.dispatch('refreshDiskUsage');
}
} else {
@ -2001,15 +2028,16 @@ export default {
this.showProgress = false;
console.error('Installation failed:', response.error);
this.$refs.toast.showToast("Model:\n" + model_object.title + "\nfailed to install!", 4, false)
this.$refs.toast.showToast("Model:\n" + model_object.model.name + "\nfailed to install!", 4, false)
this.$store.dispatch('refreshDiskUsage');
}
console.log("Here")
};
socket.on('install_progress', progressListener);
socket.emit('install_model', { path: path });
socket.emit('install_model', { path: path, type:model_object.model.type });
console.log("Started installation, please wait");
},
@ -2114,7 +2142,7 @@ export default {
// FInd model
if (this.$refs.modelZoo) {
const index = this.$refs.modelZoo.findIndex(item => item.model.path == response.model_url && item.model.title == response.model_name && this.configFile.binding_name == response.binding_folder)
const index = this.$refs.modelZoo.findIndex(item => item.model.name == response.model_name && this.configFile.binding_name == response.binding_folder)
const modelEntry = this.models[index]
if (modelEntry) {
@ -2135,7 +2163,7 @@ export default {
console.log("Installed successfully")
if (this.$refs.modelZoo) {
const index = this.$refs.modelZoo.findIndex(item => item.model.path == response.model_url && item.model.title == response.model_name && this.configFile.binding_name == response.binding_folder)
const index = this.$refs.modelZoo.findIndex(item => item.model.name == response.model_name && this.configFile.binding_name == response.binding_folder)
const modelEntry = this.models[index]
if (modelEntry) {
@ -2148,14 +2176,14 @@ export default {
}
this.$refs.toast.showToast("Model:\n" + model_object.title + "\ninstalled!", 4, true)
this.$refs.toast.showToast("Model:\n" + model_object.name + "\ninstalled!", 4, true)
this.$store.dispatch('refreshDiskUsage');
} else if (response.status === 'failed') {
console.log("Install failed")
// Installation failed or encountered an error
if (this.$refs.modelZoo) {
const index = this.$refs.modelZoo.findIndex(item => item.model.path == response.model_url && item.model.title == response.model_name && this.configFile.binding_name == response.binding_folder)
const index = this.$refs.modelZoo.findIndex(item => item.model.name == response.model_name && this.configFile.binding_name == response.binding_folder)
const modelEntry = this.models[index]
if (modelEntry) {
@ -2166,7 +2194,7 @@ export default {
}
console.error('Installation failed:', response.error);
this.$refs.toast.showToast("Model:\n" + model_object.title + "\nfailed to install!", 4, false)
this.$refs.toast.showToast("Model:\n" + model_object.name + "\nfailed to install!", 4, false)
this.$store.dispatch('refreshDiskUsage');
}
}
@ -2292,19 +2320,18 @@ export default {
}
if (model_object) {
if (model_object.isInstalled) {
if (this.configFile.model_name != model_object.title || force) {
this.update_model(model_object.title).then((res)=>{
if (this.configFile.model_name != model_object.model.name || force) {
this.update_model(model_object.model.name).then((res)=>{
console.log("update_model",res)
this.configFile.model_name = model_object.title
this.$refs.toast.showToast("Selected model:\n" + model_object.title, 4, true)
this.configFile.model_name = model_object.model.name
this.$refs.toast.showToast("Selected model:\n" + model_object.name, 4, true)
this.settingsChanged = true
this.isModelSelected = true
});
}
} else {
this.$refs.toast.showToast("Model:\n" + model_object.title + "\nis not installed", 4, false)
this.$refs.toast.showToast("Model:\n" + model_object.model.name + "\nis not installed", 4, false)
}
nextTick(() => {
@ -2317,9 +2344,9 @@ export default {
onCopy(modelEntry) {
let content
if (!modelEntry.model.isCustomModel) {
content = `Model name: ${modelEntry.title}\nFile size: ${modelEntry.fileSize}\nDownload: ${modelEntry.path}\nLicense: ${modelEntry.license}\nOwner: ${modelEntry.owner}\nWebsite: ${modelEntry.owner_link}\nDescription: ${modelEntry.description}`
content = `Model name: ${modelEntry.name}\nFile size: ${modelEntry.fileSize}\nDownload: ${'https://huggingface.co/'+modelEntry.quantizer+'/'+modelEntry.name}\nLicense: ${modelEntry.license}\nOwner: ${modelEntry.quantizer}\nWebsite: ${'https://huggingface.co/'+modelEntry.quantizer}\nDescription: ${modelEntry.description}`
} else {
content = `Model name: ${modelEntry.title}\nFile size: ${modelEntry.fileSize}\nManually downloaded model `
content = `Model name: ${modelEntry.name}\nFile size: ${modelEntry.fileSize}\nManually downloaded model `
}
this.$refs.toast.showToast("Copied model info to clipboard!", 4, true)
@ -2328,7 +2355,7 @@ export default {
onCopyLink(modelEntry) {
this.$refs.toast.showToast("Copied link to clipboard!", 4, true)
navigator.clipboard.writeText(modelEntry.path);
navigator.clipboard.writeText('https://huggingface.co/'+modelEntry.model.quantizer+'/'+modelEntry.model.name);
},
onCancelInstall() {
@ -2349,7 +2376,9 @@ export default {
onInstall(model_object) {
this.variant_choices = model_object.model.variants;
this.currenModelToInstall = model_object;
console.log("variant_choices")
console.log(this.variant_choices)
console.log(model_object)
this.variantSelectionDialogVisible=true;
},
onCreateReference() {
@ -2385,12 +2414,6 @@ export default {
console.log(`Progress`, response);
this.addModel = response
this.addModel.url = path
// this.addModel.progress = response.progress
// this.addModel.speed = response.speed
// this.addModel.total_size = response.total_size
// this.addModel.downloaded_size = response.downloaded_size
// this.addModel.start_time = response.start_time
this.modelDownlaodInProgress = true
if (this.addModel.progress == 100) {
this.modelDownlaodInProgress = false
@ -2408,8 +2431,6 @@ export default {
console.log("Install failed")
// Installation failed or encountered an error
this.modelDownlaodInProgress = false;
console.error('Installation failed:', response.error);
this.$refs.toast.showToast("Model:\n" + this.addModel.model_name + "\nfailed to install!", 4, false)
this.$store.dispatch('refreshDiskUsage');
@ -2418,7 +2439,6 @@ export default {
socket.on('install_progress', progressListener);
socket.emit('install_model', { path: path });
console.log("Started installation, please wait");
},
@ -2448,7 +2468,6 @@ export default {
// this.addModel.total_size = response.total_size
// this.addModel.downloaded_size = response.downloaded_size
// this.addModel.start_time = response.start_time
this.modelDownlaodInProgress = true
if (this.addModel.progress == 100) {
this.modelDownlaodInProgress = false
@ -2489,7 +2508,7 @@ export default {
},
onUninstall(model_object) {
this.$refs.yesNoDialog.askQuestion("Are you sure you want to delete this model?\n [" + model_object.title + "]", 'Yes', 'Cancel').then(yesRes => {
this.$refs.yesNoDialog.askQuestion("Are you sure you want to delete this model?\n [" + model_object.name + "]", 'Yes', 'Cancel').then(yesRes => {
if (yesRes) {
console.log("uninstalling model...")
const progressListener = (response) => {
@ -2501,34 +2520,38 @@ export default {
model_object.uninstalling = false;
socket.off('install_progress', progressListener);
this.showProgress = false;
const index = this.models.findIndex((model) => model.path === model_object.path);
const index = this.models.findIndex((model) => model.name === model_object.name);
this.models[index].isInstalled = false;
if (model_object.model.isCustomModel) {
try{
this.models = this.models.filter((model) => model.title !== model_object.title)
this.models = this.models.filter((model) => model.name !== model_object.name)
}
catch{
this.models = model
this.models = this.models
}
}
this.$refs.toast.showToast("Model:\n" + model_object.title + "\nwas uninstalled!", 4, true)
this.$refs.toast.showToast("Model:\n" + model_object.name + "\nwas uninstalled!", 4, true)
this.$store.dispatch('refreshDiskUsage');
} else {
console.log("uninstalling failed", response)
// Installation failed or encountered an error
model_object.uninstalling = false;
this.showProgress = false;
socket.off('install_progress', progressListener);
socket.off('uninstall_progress', progressListener);
// eslint-disable-next-line no-undef
console.error('Uninstallation failed:', message.error);
this.$refs.toast.showToast("Model:\n" + model_object.title + "\nfailed to uninstall!", 4, false)
this.$refs.toast.showToast("Model:\n" + model_object.name + "\nfailed to uninstall!", 4, false)
this.$store.dispatch('refreshDiskUsage');
}
};
socket.on('install_progress', progressListener);
socket.emit('uninstall_model', { path: model_object.path });
socket.on('uninstall_progress', progressListener);
if(self.selected_variant!=undefined){
socket.emit('uninstall_model', { path: 'https://huggingface.co/'+model_object.model.quantizer+'/'+model_object.model.name+'/resolve/main/'+this.selected_variant.name, type: model_object.model.type });
}
else{
socket.emit('uninstall_model', { path: 'https://huggingface.co/'+model_object.model.quantizer+'/'+model_object.model.name, type: model_object.model.type });
}
}
@ -2994,7 +3017,6 @@ export default {
if (seachedPersonalities.length > 0) {
this.personalitiesFiltered = seachedPersonalities.sort()
} else {
this.personalitiesFiltered = this.personalities.filter((item) => item.category === this.configFile.personality_category)
@ -3007,7 +3029,6 @@ export default {
if (!this.searchModel) {
console.log("Searching model")
this.modelsFiltered = this.models
this.modelsFiltered.sort()
this.searchModelInProgress = false
return
}
@ -3016,7 +3037,7 @@ export default {
console.log("filtering models")
const seachedModels = this.models.filter((item) => {
if (item.title && item.title.toLowerCase().includes(searchTerm) || item.description && item.description.toLowerCase().includes(searchTerm) || item.path && item.path.toLowerCase().includes(searchTerm)) {
if (item.name && item.name.toLowerCase().includes(searchTerm) || item.description && item.description.toLowerCase().includes(searchTerm) || item.category && item.category.toLowerCase().includes(searchTerm)) {
return item
}
@ -3027,10 +3048,9 @@ export default {
if (seachedModels.length > 0) {
this.modelsFiltered = seachedModels.sort()
this.modelsFiltered = seachedModels
} else {
this.modelsFiltered = this.models
this.modelsFiltered.sort()
}
this.searchModelInProgress = false
@ -3578,7 +3598,21 @@ export default {
// console.log("Config file")
// console.log(this.configFile)
try {
return this.$refs.modelZoo[this.$refs.modelZoo.findIndex(item => item.title == this.configFile.model_name)].$refs.imgElement.src
let index = this.$refs.modelZoo.findIndex(item => item.model.name == this.configFile.model_name);
if(index==-1){
for (let model of this.$refs.modelZoo){
let v = model.model.variants;
console.log(model.model)
if(v!=undefined){
index = v.findIndex(item => item.name == this.configFile.model_name)
if(index!=-1){
break;
}
}
}
}
return this.$refs.modelZoo[index].$refs.imgElement.src
}
catch (error) {
return defaultModelImgPlaceholder