Merge pull request #229 from andzejsp/model-entry-fixes

Model entry fixes and bunch more stuff
This commit is contained in:
Saifeddine ALOUI 2023-05-27 18:33:11 +02:00 committed by GitHub
commit f4e177e948
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 599 additions and 331 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

1
web/dist/assets/index-99ba4d99.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>GPT4All - WEBUI</title>
<script type="module" crossorigin src="/assets/index-b192126f.js"></script>
<link rel="stylesheet" href="/assets/index-eacf4bd4.css">
<script type="module" crossorigin src="/assets/index-4ec4d9d4.js"></script>
<link rel="stylesheet" href="/assets/index-99ba4d99.css">
</head>
<body>
<div id="app"></div>

View File

@ -0,0 +1,84 @@
<template>
<div class=" items-start p-4 hover:bg-primary-light rounded-lg mb-2 shadow-lg border-2 cursor-pointer"
@click.stop="toggleSelected" :class="selected ? ' border-primary-light' : 'border-transparent'">
<div class="flex flex-row items-center flex-shrink-0 gap-3">
<img :src="getImgUrl()" @error="defaultImg($event)" class="w-10 h-10 rounded-full object-fill text-red-700">
<h3 class="font-bold font-large text-lg line-clamp-3">
{{ binding.name }}
</h3>
</div>
<div class="">
<div class="">
<div class="flex items-center">
<i data-feather="user" class="w-5 m-1"></i>
<b>Author:&nbsp;</b>
{{ binding.author }}
</div>
<div class="flex items-center">
<i data-feather="folder" class="w-5 m-1"></i>
<b>Folder:&nbsp;</b>
{{ binding.folder }}
</div>
<div class="flex items-center">
<i data-feather="git-merge" class="w-5 m-1"></i>
<b>Version:&nbsp;</b>
{{ binding.version }}
</div>
</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="binding.description">{{ binding.description }}</p>
</div>
</div>
</template>
<script>
import { nextTick } from 'vue'
import feather from 'feather-icons'
import botImgPlaceholder from "../assets/logo.svg"
import userImgPlaceholder from "../assets/default_user.svg"
const bUrl = import.meta.env.VITE_GPT4ALL_API_BASEURL
export default {
props: {
binding: {},
onSelected: Function,
selected: Boolean
},
data() {
return {
};
},
mounted() {
nextTick(() => {
feather.replace()
})
},
methods: {
getImgUrl() {
return bUrl + this.binding.icon
},
defaultImg(event) {
event.target.src = botImgPlaceholder
},
toggleSelected() {
this.onSelected(this)
},
}
};
</script>

View File

@ -120,7 +120,7 @@ export default {
}, methods: {
copyContentToClipboard() {
this.$emit('copy', this.message.content)
navigator.clipboard.writeText(this.message.content);
},
deleteMsg() {
this.$emit('delete', this.message.id)

View File

@ -13,37 +13,56 @@
</div>
<div class="flex-1" v-if="!model.isCustomModel">
<div class="flex gap-3 items-center">
<img :src="getImgUrl()" @error="defaultImg($event)" class="w-10 h-10 rounded-lg object-fill">
<img :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">
{{ title }}
</h3>
</div>
<div class="flex flex-shrink-0">
<div class="flex flex-shrink-0 items-center ">
<i data-feather="link" class="w-5 m-1" ></i>
<b>Manual download:&nbsp;</b>
<a :href="path" @click.stop class="flex hover:text-secondary duration-75 active:scale-90"
<a :href="path" @click.stop class="flex items-center hover:text-secondary duration-75 active:scale-90"
title="Download this manually (faster) and put it in the models/<your binding> folder then refresh">
<i data-feather="link" class="w-5 p-1"></i>
{{ title }}
</a>
</div>
<div class="flex flex-shrink-0">
<div class="flex flex-shrink-0 items-center">
<div class="flex flex-shrink-0 items-center" :class="linkNotValid? 'text-red-600':''">
<i data-feather="file" class="w-5 m-1"></i>
<b>File size:&nbsp;</b>
{{ fileSize }}
</div>
</div>
<div class="flex flex-shrink-0 items-center">
<i data-feather="key" class="w-5 m-1"></i>
<b>License:&nbsp;</b>
{{ license }}
</div>
<div class="flex flex-shrink-0">
<div class="flex flex-shrink-0 items-center">
<i data-feather="user" class="w-5 m-1"></i>
<b>Owner:&nbsp;</b>
<a :href="owner_link" target="_blank" @click.stop class="flex hover:text-secondary duration-75 active:scale-90"
<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">
<i data-feather="link" class="w-5 p-1"></i>
{{ owner }}
</a>
</div>
<div class="flex items-center">
<i data-feather="info" class="w-5 m-1"></i>
<b>Description:&nbsp;</b><br>
<p class="opacity-80">{{ description }}</p>
</div>
<div class="flex-shrink-0" v-if="!model.isCustomModel">
<p class="mx-1 opacity-80">{{ description }}</p>
</div>
<div class="flex-shrink-0" >
<button class="px-4 py-2 rounded-md text-white font-bold transition-colors duration-300"
:class="[isInstalled ? 'bg-red-500 hover:bg-red-600' : 'bg-green-500 hover:bg-green-600']"
:class="[isInstalled ? 'bg-red-500 hover:bg-red-600' : linkNotValid ? 'bg-gray-500 hover:bg-gray-600' : 'bg-green-500 hover:bg-green-600']"
:disabled="installing || uninstalling" @click.stop="toggleInstall">
<template v-if="installing">
<div class="flex items-center space-x-2">
@ -62,7 +81,7 @@
</div>
</template>
<template v-else>
{{ isInstalled ? 'Uninstall' : 'Install' }}
{{ isInstalled ? model.isCustomModel ? 'Delete' : 'Uninstall' : linkNotValid ? 'Link is not valid':'Install' }}
</template>
</button>
</div>
@ -71,6 +90,7 @@
</template>
<script>
import axios from "axios";
import { nextTick } from 'vue'
import feather from 'feather-icons'
import defaultImgPlaceholder from "../assets/default_model.png"
@ -96,10 +116,14 @@ export default {
progress: 0,
installing: false,
uninstalling: false,
failedToLoad: false
failedToLoad: false,
fileSize: '',
linkNotValid:false,
};
},
mounted() {
async mounted() {
this.fileSize = await this.getFileSize(this.model.path)
//console.log('model path', this.model.path)
nextTick(() => {
feather.replace()
@ -107,6 +131,88 @@ export default {
})
},
methods: {
async getFileSize(url) {
try {
const res = await axios.head(url)
//console.log("addddd",url, res.headers)
if (res) {
if (res.headers["content-length"]) {
return this.humanFileSize(res.headers["content-length"])
}
if (this.model.filesize) {
return this.humanFileSize(this.model.filesize)
}
return 'Could not be determined'
}
if (this.model.filesize) {
return this.humanFileSize(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'
}
},
/** From https://stackoverflow.com/a/14919494/14106028
* Format bytes as human-readable text.
*
* @param bytes Number of bytes.
* @param si True to use metric (SI) units, aka powers of 1000. False to use
* binary (IEC), aka powers of 1024.
* @param dp Number of decimal places to display.
*
* @return Formatted string.
*/
humanFileSize(bytes, si = false, dp = 1) {
const thresh = si ? 1000 : 1024;
if (Math.abs(bytes) < thresh) {
return bytes + ' B';
}
const units = si
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
let u = -1;
const r = 10 ** dp;
do {
bytes /= thresh;
++u;
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
return bytes.toFixed(dp) + ' ' + units[u];
},
getImgUrl() {
if (this.icon === '/images/default_model.png') {
@ -137,6 +243,15 @@ export default {
this.onSelected(this);
}
}
},
watch:{
linkNotValid(){
nextTick(() => {
feather.replace()
})
}
}
};
</script>

View File

@ -14,8 +14,10 @@
<div class="">
<div class="">
<div class="">
<div class="flex items-center">
<i data-feather="user" class="w-5 m-1"></i>
<b>Author:&nbsp;</b>
{{ personality.author }}
</div>
<!-- <div class="">
@ -27,9 +29,11 @@
{{ personality.category }}
</div> -->
</div>
<div class="flex items-center">
<i data-feather="info" class="w-5 m-1"></i>
<b>Description:&nbsp;</b><br>
<p class="opacity-80 line-clamp-3" :title="personality.description">{{ personality.description }}</p>
</div>
<p class="mx-1 opacity-80 line-clamp-3" :title="personality.description">{{ personality.description }}</p>
</div>

View File

@ -168,24 +168,7 @@
<style scoped>
.expand-enter-active,
.expand-leave-active {
transition: all 0.5s ease;
}
.expand-enter{
transition: all 0.5s ease;
opacity: 1;
transform: translatey(30px);
}
.expand-leave-to {
transform: translatey(-30px);
opacity: 0;
}
/* THESE ARE FOR TransitionGroup components */
.list-move, /* apply transition to moving elements */
.list-enter-active,
.list-leave-active {
@ -241,7 +224,7 @@ export default {
}
} catch (error) {
console.log(error)
console.log(error.message,'api_get_req')
return
}
@ -257,7 +240,7 @@ export default {
return res.data
}
} catch (error) {
console.log("Error: Could not list discussions", error)
console.log("Error: Could not list discussions", error.message)
return []
}
},
@ -278,7 +261,7 @@ export default {
}
}
} catch (error) {
console.log(error)
console.log(error.message,'load_discussion')
this.loading = false
this.setDiscussionLoading(id, this.loading)
}
@ -291,7 +274,7 @@ export default {
return res.data
}
} catch (error) {
console.log("Error: Could not create new discussion", error)
console.log("Error: Could not create new discussion", error.message)
return {}
}
},
@ -307,7 +290,7 @@ export default {
this.setDiscussionLoading(id, this.loading)
}
} catch (error) {
console.log("Error: Could not delete discussion", error)
console.log("Error: Could not delete discussion", error.message)
this.loading = false
this.setDiscussionLoading(id, this.loading)
}
@ -331,7 +314,7 @@ export default {
}
}
} catch (error) {
console.log("Error: Could not edit title", error)
console.log("Error: Could not edit title", error.message)
this.loading = false
this.setDiscussionLoading(id, this.loading)
}
@ -344,7 +327,7 @@ export default {
return res.data
}
} catch (error) {
console.log("Error: Could delete message", error)
console.log("Error: Could delete message", error.message)
return {}
}
},
@ -356,7 +339,7 @@ export default {
return res.data
}
} catch (error) {
console.log("Error: Could not stop generating", error)
console.log("Error: Could not stop generating", error.message)
return {}
}
},
@ -368,7 +351,7 @@ export default {
return res.data
}
} catch (error) {
console.log("Error: Could not rank up message", error)
console.log("Error: Could not rank up message", error.message)
return {}
}
},
@ -380,7 +363,7 @@ export default {
return res.data
}
} catch (error) {
console.log("Error: Could not rank down message", error)
console.log("Error: Could not rank down message", error.message)
return {}
}
},
@ -392,7 +375,7 @@ export default {
return res.data
}
} catch (error) {
console.log("Error: Could not update message", error)
console.log("Error: Could not update message", error.message)
return {}
}
},
@ -409,7 +392,7 @@ export default {
}
} catch (error) {
console.log("Error: Could not export multiple discussions", error)
console.log("Error: Could not export multiple discussions", error.message)
return {}
}
},
@ -419,7 +402,12 @@ export default {
if (!this.filterInProgress) {
this.filterInProgress = true
setTimeout(() => {
if(this.filterTitle){
this.list = this.tempList.filter((item) => item.title && item.title.includes(this.filterTitle))
}else{
this.list = this.tempList
}
this.filterInProgress = false
}, 100)
}
@ -567,7 +555,7 @@ export default {
sendMsg(msg) {
// Sends message to binding
if(!msg){
this.$refs.toast.showToast("Message contains no centent!", 4, false)
this.$refs.toast.showToast("Message contains no content!", 4, false)
return
}
this.isGenerating = true;
@ -599,11 +587,8 @@ export default {
},
streamMessageContent(msgObj) {
// Streams response message content from binding
//console.log("stream", JSON.stringify(content))
const parent = msgObj.user_message_id
const discussion_id = msgObj.discussion_id
// next statement - incorrect comparison: was '=' and should be '=='
this.setDiscussionLoading(discussion_id, true);
if (this.currentDiscussion.id == discussion_id) {
@ -612,14 +597,10 @@ export default {
const messageItem = this.discussionArr[index]
if (messageItem) {
messageItem.content = msgObj.data
//console.log("user-msg-id",parent, "ai-msg-id",msgObj.ai_message_id, index, discussion_id, msgObj.data)
}
}
//const lastMsg = this.discussionArr[this.discussionArr.length - 1]
//lastMsg.content = content.data
},
async changeTitleUsingUserMSG(id, msg) {
// If discussion is untitled or title is null then it sets the title to first user message.
@ -649,7 +630,6 @@ export default {
const selectedDisElement = document.getElementById('dis-' + res.id)
this.scrollToElement(selectedDisElement)
})
//console.log("disc",JSON.stringify(discussionItem))
},
loadLastUsedDiscussion() {
// Checks local storage for last selected discussion
@ -665,9 +645,6 @@ export default {
async deleteDiscussion(id) {
// Deletes discussion from binding and frontend
//const index = this.list.findIndex((x) => x.id == id)
//const discussionItem = this.list[index]
//discussionItem.loading = true
await this.delete_discussion(id)
if (this.currentDiscussion.id == id) {
this.currentDiscussion = {}
@ -677,7 +654,6 @@ export default {
this.list.splice(this.list.findIndex(item => item.id == id), 1)
this.createDiscussionList(this.list)
//await this.list_discussions()
},
async deleteDiscussionMulti() {
// Delete selected discussions
@ -697,6 +673,8 @@ export default {
}
this.tempList = this.list
this.isCheckbox = false
this.$refs.toast.showToast("Removed ("+deleteList.length+") items", 4, true)
console.log("Multi delete done")
},
async deleteMessage(msgId) {
@ -706,7 +684,7 @@ export default {
this.discussionArr.splice(this.discussionArr.findIndex(item => item.id == msgId), 1)
}).catch(() => {
this.$refs.toast.showToast("Could not remove message", 4, false)
console.log("Error: Could not delete message")
})
@ -788,7 +766,7 @@ export default {
const message = this.discussionArr[this.discussionArr.findIndex(item => item.id == msgId)]
message.rank = res.new_rank
}).catch(() => {
this.$refs.toast.showToast("Could not rank up message", 4, false)
console.log("Error: Could not rank up message")
})
@ -799,6 +777,7 @@ export default {
const message = this.discussionArr[this.discussionArr.findIndex(item => item.id == msgId)]
message.rank = res.new_rank
}).catch(() => {
this.$refs.toast.showToast("Could not rank down message", 4, false)
console.log("Error: Could not rank down message")
})
@ -811,6 +790,7 @@ export default {
message.content = msg
}).catch(() => {
this.$refs.toast.showToast("Could not update message", 4, false)
console.log("Error: Could not update message")
})
@ -861,8 +841,9 @@ export default {
this.chime.play()
},
copyToClipBoard(content) {
this.$refs.toast.showToast("Copied to clipboard successfully", 4, true)
navigator.clipboard.writeText(content);
this.$refs.toast.showToast("Copied to clipboard successfully")
nextTick(() => {
feather.replace()
@ -965,9 +946,7 @@ export default {
}
return newItem
})
// const index = personalities.findIndex((x) => x.name === sender)
// const pers = personalities[index]
// return pers.avatar
},
getAvatar(sender) {

View File

@ -65,7 +65,64 @@
</div>
<div :class="isLoading ? 'pointer-events-none opacity-30' : ''">
<!-- BINDING ZOO -->
<div
class="flex flex-col mb-2 rounded-lg bg-bg-light-tone dark:bg-bg-dark-tone hover:bg-bg-light-tone-panel hover:dark:bg-bg-dark-tone-panel duration-150 shadow-lg">
<div class="flex flex-row p-3">
<button @click.stop="bzc_collapsed = !bzc_collapsed"
class="text-2xl hover:text-primary duration-75 p-2 -m-2 w-full text-left active:translate-y-1 flex flex-row items-center">
<i data-feather="chevron-right" class="mr-2"></i>
<h3 class="text-lg font-semibold cursor-pointer select-none mr-2">
Binding zoo</h3>
<div v-if="configFile.binding" class="mr-2">|</div>
<div v-if="configFile.binding" class=" text-base font-semibold cursor-pointer select-none items-center">
{{configFile.binding}} </div>
</button>
</div>
<div :class="{ 'hidden': bzc_collapsed }" class="flex flex-col mb-2 px-3 pb-0">
<!-- <div class="mx-2 mb-4">
<label for="binding" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
Bindings: ({{ bindingsArr.length }})
</label>
<select id="binding" @change="update_binding($event.target.value)"
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">
<option v-for="item in bindingsArr" :selected="item.folder === configFile.binding"
:value="item.folder">
{{ item.name }} by ({{ item.author }})
</option>
</select>
</div> -->
<div v-if="bindings.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: ({{ bindings.length }})
</label>
<div ref="bindingZoo" class="overflow-y-auto no-scrollbar p-2 pb-0 grid lg:grid-cols-3 md:grid-cols-2 gap-4"
:class="bzl_collapsed ? '' : 'max-h-96'">
<TransitionGroup name="list">
<BindingEntry v-for="(binding, index) in bindings"
:key="'index-' + index + '-' + binding.folder" :binding="binding" :on-selected="onSelectedBinding" :selected="binding.folder === configFile.binding"></BindingEntry>
</TransitionGroup>
</div>
</div>
<!-- EXPAND / COLLAPSE BUTTON -->
<button v-if="bzl_collapsed"
class="text-2xl hover:text-secondary duration-75 flex justify-center hover:bg-bg-light-tone hover:dark:bg-bg-dark-tone rounded-lg "
title="Collapse" type="button" @click="bzl_collapsed = !bzl_collapsed">
<i data-feather="chevron-up"></i>
</button>
<button v-else
class="text-2xl hover:text-secondary duration-75 flex justify-center hover:bg-bg-light-tone hover:dark:bg-bg-dark-tone rounded-lg "
title="Expand" type="button" @click="bzl_collapsed = !bzl_collapsed">
<i data-feather="chevron-down"></i>
</button>
</div>
</div>
<!-- MODELS ZOO -->
<div
@ -74,23 +131,15 @@
<button @click.stop="mzc_collapsed = !mzc_collapsed"
class="text-2xl hover:text-primary duration-75 p-2 -m-2 w-full text-left active:translate-y-1 flex items-center">
<i :data-feather="mzc_collapsed ? 'chevron-right' : 'chevron-down'" class="mr-2"></i>
<h3 class="text-lg font-semibold cursor-pointer select-none">
<h3 class="text-lg font-semibold cursor-pointer select-none mr-2">
Models zoo</h3>
<div v-if="configFile.model" class="mr-2">|</div>
<div v-if="configFile.model" class=" text-base font-semibold cursor-pointer select-none items-center">
{{configFile.model}} </div>
</button>
</div>
<div :class="{ 'hidden': mzc_collapsed }" class="flex flex-col mb-2 px-3 pb-0">
<div class="mx-2 mb-4">
<label for="binding" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
Binding: ({{ bindingsArr.length }})
</label>
<select id="binding" @change="update_binding($event.target.value)"
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">
<option v-for="item in bindingsArr" :selected="item.folder === configFile.binding" :value="item.folder">
{{ item.name }} by ({{item.author}})
</option>
</select>
</div>
<div v-if="models.length > 0" class="mb-2">
<label for="model" class="block ml-2 mb-2 text-sm font-medium text-gray-900 dark:text-white">
Models: ({{ models.length }})
@ -98,11 +147,11 @@
<div ref="modelZoo" class="overflow-y-auto no-scrollbar p-2 pb-0 "
:class="mzl_collapsed ? '' : 'max-h-96'">
<TransitionGroup name="list">
<model-entry v-for="(model, index) in models" :key="index" :title="model.title"
:icon="model.icon" :path="model.path" :owner="model.owner" :owner_link="model.owner_link"
:license="model.license" :description="model.description" :is-installed="model.isInstalled"
:on-install="onInstall" :on-uninstall="onUninstall" :on-selected="onSelected"
:selected="model.title === configFile.model" :model="model" />
<model-entry v-for="(model, index) in 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"
:is-installed="model.isInstalled" :on-install="onInstall" :on-uninstall="onUninstall"
:on-selected="onSelected" :selected="model.title === configFile.model" :model="model" />
</TransitionGroup>
</div>
</div>
@ -130,8 +179,12 @@
<button @click.stop="pzc_collapsed = !pzc_collapsed"
class="text-2xl hover:text-primary duration-75 p-2 -m-2 w-full text-left active:translate-y-1 flex items-center">
<i :data-feather="pzc_collapsed ? 'chevron-right' : 'chevron-down'" class="mr-2"></i>
<h3 class="text-lg font-semibold cursor-pointer select-none">
<h3 class="text-lg font-semibold cursor-pointer select-none mr-2">
Personalities zoo</h3>
<div v-if="configFile.personality" class="mr-2">|</div>
<div v-if="configFile.personality" class=" text-base font-semibold cursor-pointer select-none items-center">
{{configFile.personality}} </div>
</button>
</div>
<div :class="{ 'hidden': pzc_collapsed }" class="flex flex-col mb-2 px-3 pb-0">
@ -184,8 +237,8 @@
class="overflow-y-auto no-scrollbar p-2 pb-0 grid lg:grid-cols-3 md:grid-cols-2 gap-4"
:class="pzl_collapsed ? '' : 'max-h-96'">
<TransitionGroup name="bounce">
<personality-entry v-for="(pers, index) in personalitiesFiltered" :key="index"
:personality="pers"
<personality-entry v-for="(pers, index) in personalitiesFiltered"
:key="'index-' + index + '-' + pers.name" :personality="pers"
:selected="pers.name === configFile.personality && pers.category === configFile.personality_category && pers.language === configFile.personality_language"
:on-selected="onPersonalitySelected" />
</TransitionGroup>
@ -224,7 +277,8 @@
<input id="override-model-parameters" type="checkbox"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-700 dark:focus:ring-offset-gray-700 focus:ring-2 dark:bg-gray-600 dark:border-gray-500"
@click.stop v-model="configFile.override_personality_model_parameters" @change="update_setting('override_personality_model_parameters', configFile.override_personality_model_parameters)">
@click.stop v-model="configFile.override_personality_model_parameters"
@change="update_setting('override_personality_model_parameters', configFile.override_personality_model_parameters)">
<label for="override-model-parameters" class="block text-sm font-medium ">
Override personality model parameters
</label>
@ -380,11 +434,11 @@
<YesNoDialog ref="yesNoDialog" />
<MessageBox ref="messageBox" />
<Toast ref="toast" />
</template>
<style scoped>
.list-move, /* apply transition to moving elements */
/* THESE ARE FOR TransitionGroup components */
.list-move,
/* apply transition to moving elements */
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
@ -393,10 +447,12 @@
.list-enter-from {
transform: translatey(-30px);
}
.list-leave-to {
opacity: 0;
transform: translatey(30px);
}
/* ensure leaving items are taken out of layout flow so that moving
animations can be calculated correctly. */
.list-leave-active {
@ -406,16 +462,20 @@
.bounce-enter-active {
animation: bounce-in 0.5s;
}
.bounce-leave-active {
animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
@ -431,6 +491,7 @@ import Toast from '../components/Toast.vue'
import ModelEntry from '@/components/ModelEntry.vue';
import PersonalityViewer from '@/components/PersonalityViewer.vue';
import PersonalityEntry from "../components/PersonalityEntry.vue";
import BindingEntry from "../components/BindingEntry.vue";
import socket from '@/services/websocket.js'
axios.defaults.baseURL = import.meta.env.VITE_GPT4ALL_API_BASEURL
@ -443,25 +504,29 @@ export default {
PersonalityViewer,
Toast,
PersonalityEntry,
BindingEntry,
},
data() {
return {
// Models zoo installer stuff
// Zoo stuff
models: [],
personalities: [],
personalitiesFiltered: [],
bindings: [],
// Accordeon stuff
collapsedArr: [],
all_collapsed: true,
bec_collapsed: true,
mzc_collapsed: true, // models zoo
pzc_collapsed: true, // personalities zoo
bzc_collapsed: true, // binding zoo
pc_collapsed: true,
mc_collapsed: true,
// Zoo accordeoon
mzl_collapsed: false,
pzl_collapsed: false,
bzl_collapsed: false,
// Settings stuff
bindingsArr: [],
modelsArr: [], // not used anymore but still have references in some methods
@ -489,30 +554,30 @@ export default {
this.mc_collapsed = val
},
fetchModels() {
console.log("Fetching models")
axios.get('/get_available_models')
.then(response => {
//console.log(`Models list recovered successfuly: ${JSON.stringify(response.data)}`)
console.log(" models", response.data.length)
this.models = response.data;
this.fetchCustomModels()
})
.catch(error => {
console.log(error);
console.log(error.message, 'fetchModels');
});
},
fetchCustomModels() {
console.log("Fetching Custom models")
axios.get('/list_models')
.then(response => {
// Returns array of model filenames which are = to title of models zoo entry
for (let i = 0; i < response.data.length; i++) {
const customModel = response.data[i]
const index = this.models.findIndex(x => x.title == customModel)
console.log("model-ccc", customModel, index)
if (index == -1) {
let newModelEntry = {}
newModelEntry.title = customModel
newModelEntry.path = customModel
newModelEntry.isCustomModel = true
newModelEntry.isInstalled = true
this.models.push(newModelEntry)
@ -522,17 +587,17 @@ export default {
})
.catch(error => {
console.log(error);
console.log(error.message, 'fetchCustomModels');
});
},
onPersonalitySelected(pers) {
console.log("Selected personality")
// eslint-disable-next-line no-unused-vars
if (this.isLoading) {
this.$refs.toast.showToast("Loading... please wait", 4, false)
}
if (pers.personality) {
// if (model_object.isInstalled) {
this.settingsChanged = true
const res = this.update_setting('personality', pers.personality.name, () => {
this.$refs.toast.showToast("Selected personality:\n" + pers.personality.name, 4, true)
@ -541,12 +606,6 @@ export default {
this.configFile.personality_language = pers.personality.language
})
nextTick(() => {
feather.replace()
@ -555,7 +614,7 @@ export default {
},
onSelected(model_object) {
console.log("Selected model")
// eslint-disable-next-line no-unused-vars
if (this.isLoading) {
this.$refs.toast.showToast("Loading... please wait", 4, false)
@ -563,8 +622,6 @@ export default {
if (model_object) {
if (model_object.isInstalled) {
if (this.configFile.model != model_object.title) {
this.update_model(model_object.title)
this.configFile.model = model_object.title
@ -587,6 +644,11 @@ export default {
// Model installation
onInstall(model_object) {
if (model_object.linkNotValid) {
model_object.installing = false
this.$refs.toast.showToast("Link is not valid, file does not exist", 4, false)
return
}
let path = model_object.path;
this.showProgress = true;
this.progress = 0;
@ -598,9 +660,12 @@ export default {
if (response.status === 'progress') {
console.log(`Progress = ${response.progress}`);
model_object.progress = response.progress
model_object.installing = true
if (model_object.progress == 100) {
const index = this.models.findIndex((model) => model.path === path);
this.models[index].isInstalled = true;
this.showProgress = false;
model_object.installing = false
}
} else if (response.status === 'succeeded') {
console.log("Received succeeded")
@ -610,18 +675,23 @@ export default {
const index = this.models.findIndex((model) => model.path === path);
this.models[index].isInstalled = true;
this.showProgress = false;
model_object.installing = false
this.$refs.toast.showToast("Model:\n" + model_object.title + "\ninstalled!", 4, true)
} else if (response.status === 'failed') {
socket.off('install_progress', progressListener);
console.log("Install failed")
// Installation failed or encountered an error
model_object.installing = false;
v
this.showProgress = false;
console.error('Installation failed:', response.error);
this.$refs.toast.showToast("Model:\n" + model_object.title + "\nfailed to install!", 4, false)
}
};
socket.on('install_progress', progressListener);
socket.emit('install_model', { path: path });
console.log("Started installation, please wait");
},
@ -631,25 +701,35 @@ export default {
if (response.status === 'progress') {
this.progress = response.progress;
} else if (response.status === 'succeeded') {
console.log(model_object)
// Installation completed
model_object.uninstalling = false;
socket.off('install_progress', progressListener);
this.showProgress = false;
const index = this.models.findIndex((model) => model.path === model_object.path);
this.models[index].isInstalled = false;
if (model_object.model.isCustomModel) {
this.models = this.models.filter((model) => model.title !== model_object.title)
}
this.$refs.toast.showToast("Model:\n" + model_object.title + "\nwas uninstalled!", 4, true)
} else if (response.status === 'failed') {
// Installation failed or encountered an error
model_object.uninstalling = false;
this.showProgress = false;
socket.off('install_progress', progressListener);
// eslint-disable-next-line no-undef
console.error('Installation failed:', message.error);
console.error('Uninstallation failed:', message.error);
this.$refs.toast.showToast("Model:\n" + model_object.title + "\nfailed to uninstall!", 4, false)
}
};
socket.on('install_progress', progressListener);
socket.emit('uninstall_model', { path: model_object.path });
},
onSelectedBinding(binding_object){
this.update_binding(binding_object.binding.folder)
//console.log('lol',binding_object)
},
// messagebox ok stuff
onMessageBoxOk() {
console.log("OK button clicked");
@ -657,7 +737,7 @@ export default {
// Refresh stuff
refresh() {
console.log("Refreshing")
// No need to refresh all lists because they never change during using application.
// On settings change only config file chnages.
//
@ -669,9 +749,9 @@ export default {
//this.api_get_req("list_languages").then(response => { this.langArr = response })
this.api_get_req("get_config").then(response => {
this.configFile = response
console.log("selecting model")
this.models.forEach(model => {
console.log(`${model} -> ${response["model"]}`)
if (model.title == response["model"]) {
model.selected = true;
@ -693,13 +773,13 @@ export default {
setting_name: setting_name_val,
setting_value: setting_value_val
}
console.log("change", setting_name_val, setting_value_val, obj)
axios.post('/update_setting', obj).then((res) => {
console.log("Update setting done")
if (res) {
console.log("res is ok")
if (next !== undefined) {
console.log("Calling next")
next(res)
}
return res.data;
@ -710,13 +790,11 @@ export default {
},
update_binding(value) {
console.log("Upgrading binding")
// eslint-disable-next-line no-unused-vars
this.isLoading = true
this.update_setting('binding', value, (res) => {
this.refresh();
console.log("Binding changed");
console.log(res);
this.$refs.toast.showToast("Binding changed.", 4, true)
this.settingsChanged = true
this.isLoading = false
@ -731,19 +809,17 @@ export default {
},
update_model(value) {
if (!value) this.isModelSelected = false
console.log("Upgrading model")
// eslint-disable-next-line no-unused-vars
this.isLoading = true
this.update_setting('model', value, (res) => {
console.log("Model changed");
this.fetchModels();
//this.fetchModels();
this.isLoading = false
})
},
applyConfiguration() {
if (!this.configFile.model) {
console.log("applying configuration failed")
this.$refs.toast.showToast("Configuration changed failed.\nPlease select model first", 4, false)
nextTick(() => {
feather.replace()
@ -753,14 +829,14 @@ export default {
this.isLoading = true;
axios.post('/apply_settings').then((res) => {
this.isLoading = false;
console.log(res.data)
if (res.data.status === "succeeded") {
console.log("applying configuration succeeded")
this.$refs.toast.showToast("Configuration changed successfully.", 4, true)
this.settingsChanged = false
this.save_configuration()
} else {
console.log("applying configuration failed")
this.$refs.toast.showToast("Configuration change failed.", 4, false)
}
@ -784,7 +860,7 @@ export default {
}
})
.catch(error => {
console.log(error)
console.log(error.message, 'save_configuration')
this.$refs.messageBox.showMessage("Couldn't save settings!")
return { 'status': false }
});
@ -805,7 +881,7 @@ export default {
}
})
.catch(error => {
console.log(error)
console.log(error.message, 'reset_configuration')
this.$refs.messageBox.showMessage("Couldn't reset settings!")
return { 'status': false }
});
@ -827,7 +903,7 @@ export default {
}
} catch (error) {
console.log(error)
console.log(error.message, 'api_get_req - settings')
return
}
@ -889,6 +965,7 @@ export default {
this.persArr = await this.api_get_req("list_personalities")
this.langArr = await this.api_get_req("list_languages")
await this.getPersonalitiesArr()
this.bindings = await this.api_get_req("list_bindings")
this.isLoading = false
},
@ -931,6 +1008,13 @@ export default {
})
},
bzl_collapsed() {
nextTick(() => {
feather.replace()
})
},
all_collapsed(val) {
this.collapseAll(val)
@ -951,12 +1035,6 @@ export default {
})
},
isModelSelected(val) {
console.log('iss selected:', val)
},
}
}