mirror of
https://github.com/ParisNeo/lollms-webui.git
synced 2025-02-01 00:45:34 +00:00
Merge pull request #224 from andzejsp/model-parameter-override
Model parameter override
This commit is contained in:
commit
4c949bc02e
BIN
web/dist/assets/default_model-9e24e852.png
vendored
Normal file
BIN
web/dist/assets/default_model-9e24e852.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 245 KiB |
1
web/dist/assets/index-1332cfe4.css
vendored
Normal file
1
web/dist/assets/index-1332cfe4.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
web/dist/assets/index-25bebe4f.css
vendored
1
web/dist/assets/index-25bebe4f.css
vendored
File diff suppressed because one or more lines are too long
43
web/dist/assets/index-2b959387.js
vendored
Normal file
43
web/dist/assets/index-2b959387.js
vendored
Normal file
File diff suppressed because one or more lines are too long
43
web/dist/assets/index-a26c9cba.js
vendored
43
web/dist/assets/index-a26c9cba.js
vendored
File diff suppressed because one or more lines are too long
4
web/dist/index.html
vendored
4
web/dist/index.html
vendored
@ -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-a26c9cba.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-25bebe4f.css">
|
||||
<script type="module" crossorigin src="/assets/index-2b959387.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-1332cfe4.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<!-- FOOTER -->
|
||||
<!-- <Footer /> -->
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -28,4 +28,3 @@ import Footer from './components/Footer.vue';
|
||||
|
||||
|
||||
</script>
|
||||
<!-- <script src="../node_modules/feather-icons/dist/feather"></script> -->
|
BIN
web/src/assets/default_model.png
Normal file
BIN
web/src/assets/default_model.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 245 KiB |
@ -5,8 +5,8 @@
|
||||
<!-- SENDER -->
|
||||
<div class="w-10 h-10 rounded-lg object-fill drop-shadow-md">
|
||||
|
||||
<img :src="getImgUrl()" class="w-10 h-10 rounded-full object-fill text-red-700">
|
||||
|
||||
<img :src="getImgUrl()" @error="defaultImg($event)" class="w-10 h-10 rounded-full object-fill text-red-700">
|
||||
|
||||
</div>
|
||||
<p class="drop-shadow-sm py-0 px-2 text-lg text-opacity-95 font-bold ">{{ message.sender }}</p>
|
||||
@ -16,15 +16,15 @@
|
||||
<MarkdownRenderer ref="mdRender" v-if="!editMsgMode" :markdown-text="message.content"></MarkdownRenderer>
|
||||
<textarea v-if="editMsgMode" ref="mdTextarea" :rows="4"
|
||||
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 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"
|
||||
:style="{minHeight:mdRenderHeight+`px`}"
|
||||
placeholder="Enter message here..." v-model="new_message_content"></textarea>
|
||||
:style="{ minHeight: mdRenderHeight + `px` }" placeholder="Enter message here..."
|
||||
v-model="new_message_content"></textarea>
|
||||
</div>
|
||||
<div class="invisible group-hover:visible flex flex-row mt-3 -mb-2">
|
||||
<!-- MESSAGE CONTROLS -->
|
||||
<!-- EDIT CONFIRMATION -->
|
||||
<div v-if="editMsgMode" class="flex items-center duration-75">
|
||||
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2" title="Cancel edit" type="button"
|
||||
@click.stop="editMsgMode = false">
|
||||
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2" title="Cancel edit"
|
||||
type="button" @click.stop="editMsgMode = false">
|
||||
<i data-feather="x"></i>
|
||||
</button>
|
||||
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 p-2" title="Update message"
|
||||
@ -33,21 +33,22 @@
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div v-if="!editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2" title="Edit message"
|
||||
@click.stop="editMsgMode =true">
|
||||
<div v-if="!editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2"
|
||||
title="Edit message" @click.stop="editMsgMode = true">
|
||||
<i data-feather="edit"></i>
|
||||
</div>
|
||||
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2" title="Copy message to clipboard"
|
||||
@click.stop="copyContentToClipboard()">
|
||||
<i data-feather="copy"></i>
|
||||
</div>
|
||||
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2" title="Resend message" @click.stop="resendMessage()">
|
||||
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2" title="Resend message"
|
||||
@click.stop="resendMessage()">
|
||||
<i data-feather="refresh-cw"></i>
|
||||
</div>
|
||||
<!-- DELETE CONFIRMATION -->
|
||||
<div v-if="deleteMsgMode" class="flex items-center duration-75">
|
||||
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2" title="Cancel removal" type="button"
|
||||
@click.stop="deleteMsgMode = false">
|
||||
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 p-2" title="Cancel removal"
|
||||
type="button" @click.stop="deleteMsgMode = false">
|
||||
<i data-feather="x"></i>
|
||||
</button>
|
||||
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 p-2" title="Confirm removal"
|
||||
@ -79,41 +80,43 @@
|
||||
<script>
|
||||
import botImgPlaceholder from "../assets/logo.svg"
|
||||
import userImgPlaceholder from "../assets/default_user.svg"
|
||||
const bUrl = import.meta.env.VITE_GPT4ALL_API_BASEURL
|
||||
import { nextTick } from 'vue'
|
||||
import feather from 'feather-icons'
|
||||
import MarkdownRenderer from './MarkdownRenderer.vue';
|
||||
export default {
|
||||
// eslint-disable-next-line vue/multi-word-component-names
|
||||
name: 'Message',
|
||||
emits: ['copy', 'delete', 'rankUp', 'rankDown','updateMessage','resendMessage'],
|
||||
emits: ['copy', 'delete', 'rankUp', 'rankDown', 'updateMessage', 'resendMessage'],
|
||||
components: {
|
||||
MarkdownRenderer
|
||||
},
|
||||
props: {
|
||||
message: Object
|
||||
message: Object,
|
||||
avatar: ''
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
senderImg: '',
|
||||
|
||||
new_message_content: '',
|
||||
showConfirmation: false,
|
||||
editMsgMode: false,
|
||||
deleteMsgMode: false,
|
||||
mdRenderHeight:Number
|
||||
mdRenderHeight: Number
|
||||
|
||||
}
|
||||
}, mounted() {
|
||||
this.senderImg = botImgPlaceholder
|
||||
|
||||
this.new_message_content = this.message.content
|
||||
nextTick(() => {
|
||||
feather.replace()
|
||||
|
||||
this.mdRenderHeight=this.$refs.mdRender.$el.offsetHeight
|
||||
|
||||
|
||||
|
||||
this.mdRenderHeight = this.$refs.mdRender.$el.offsetHeight
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
}, methods: {
|
||||
copyContentToClipboard() {
|
||||
this.$emit('copy', this.message.content)
|
||||
@ -135,33 +138,40 @@ export default {
|
||||
this.$emit('updateMessage', this.message.id, this.new_message_content)
|
||||
this.editMsgMode = false
|
||||
},
|
||||
resendMessage(){
|
||||
resendMessage() {
|
||||
this.$emit('resendMessage', this.message.id, this.new_message_content)
|
||||
},
|
||||
getImgUrl() {
|
||||
|
||||
getImgUrl() {
|
||||
|
||||
if (this.message.sender == "user") {
|
||||
if (this.avatar) {
|
||||
|
||||
return this.avatar
|
||||
}
|
||||
|
||||
return userImgPlaceholder;
|
||||
|
||||
}
|
||||
console.log("Message data")
|
||||
console.log(this.message)
|
||||
|
||||
return bUrl + this.avatar
|
||||
|
||||
return botImgPlaceholder;
|
||||
}
|
||||
},
|
||||
defaultImg(event) {
|
||||
event.target.src = botImgPlaceholder
|
||||
},
|
||||
|
||||
}, watch: {
|
||||
showConfirmation() {
|
||||
nextTick(() => {
|
||||
feather.replace()
|
||||
|
||||
|
||||
})
|
||||
},
|
||||
|
||||
editMsgMode(val){
|
||||
|
||||
if(!val){
|
||||
this.new_message_content = this.message.content
|
||||
editMsgMode(val) {
|
||||
|
||||
if (!val) {
|
||||
this.new_message_content = this.message.content
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
@ -169,12 +179,16 @@ export default {
|
||||
|
||||
})
|
||||
},
|
||||
deleteMsgMode(){
|
||||
deleteMsgMode() {
|
||||
nextTick(() => {
|
||||
feather.replace()
|
||||
|
||||
})
|
||||
},
|
||||
|
||||
},
|
||||
computed: {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,75 +1,80 @@
|
||||
<template>
|
||||
<div class="flex items-center 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-shrink-0">
|
||||
<i :class="`fas ${icon} text-xl`"></i>
|
||||
</div>
|
||||
<div v-if="model.isCustomModel">
|
||||
<h3 class="font-bold font-large text-lg">
|
||||
{{ title }}
|
||||
</h3>
|
||||
|
||||
|
||||
|
||||
<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">
|
||||
<h3 class="font-bold font-large text-lg">
|
||||
{{ title }}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1" v-if="!model.isCustomModel">
|
||||
<h3 class="font-bold font-large text-lg">
|
||||
{{ title }}
|
||||
</h3>
|
||||
<div class="flex gap-3 items-center">
|
||||
<img :src="getImgUrl()" @error="defaultImg($event)" class="w-10 h-10 rounded-lg object-fill">
|
||||
<h3 class="font-bold font-large text-lg">
|
||||
{{ title }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="flex flex-shrink-0">
|
||||
<b>Manual download: </b>
|
||||
<a :href="path" @click.stop class="flex hover:text-secondary duration-75 active:scale-90"
|
||||
title="Download this manually (faster) and put it in the models/<your backend> folder then refresh">
|
||||
<i data-feather="link" class="w-5 p-1"></i>
|
||||
{{ title }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex flex-shrink-0">
|
||||
<b>License: </b>
|
||||
{{ license }}
|
||||
</div>
|
||||
<div class="flex flex-shrink-0">
|
||||
<b>Owner: </b>
|
||||
<a :href="owner_link" target="_blank" @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>
|
||||
<b>Description: </b><br>
|
||||
<p class="opacity-80">{{ description }}</p>
|
||||
</div>
|
||||
<div class="flex-shrink-0" v-if="!model.isCustomModel">
|
||||
<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']"
|
||||
:disabled="installing || uninstalling" @click.stop="toggleInstall">
|
||||
<template v-if="installing">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="h-2 w-20 bg-gray-300 rounded">
|
||||
<div :style="{ width: progress + '%' }" class="h-full bg-red-500 rounded"></div>
|
||||
</div>
|
||||
<span>Installing...{{ Math.floor(progress) }}%</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="uninstalling">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="h-2 w-20 bg-gray-300 rounded">
|
||||
<div :style="{ width: progress + '%' }" class="h-full bg-green-500"></div>
|
||||
</div>
|
||||
<span>Uninstalling...</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ isInstalled ? 'Uninstall' : 'Install' }}
|
||||
</template>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-shrink-0">
|
||||
<b>Manual download: </b>
|
||||
<a :href="path" @click.stop class="flex hover:text-secondary duration-75 active:scale-90"
|
||||
title="Download this manually (faster) and put it in the models/<your backend> folder then refresh">
|
||||
<i data-feather="link" class="w-5 p-1"></i>
|
||||
{{ title }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex flex-shrink-0">
|
||||
<b>License: </b>
|
||||
{{ license }}
|
||||
</div>
|
||||
<div class="flex flex-shrink-0">
|
||||
<b>Owner: </b>
|
||||
<a :href="owner_link" target="_blank" @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>
|
||||
<b>Description: </b><br>
|
||||
<p class="opacity-80">{{ description }}</p>
|
||||
</div>
|
||||
<div class="flex-shrink-0" v-if="!model.isCustomModel">
|
||||
<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']"
|
||||
:disabled="installing || uninstalling" @click.stop="toggleInstall">
|
||||
<template v-if="installing">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="h-2 w-20 bg-gray-300 rounded">
|
||||
<div :style="{ width: progress + '%' }" class="h-full bg-red-500 rounded"></div>
|
||||
</div>
|
||||
<span>Installing...{{ Math.floor(progress) }}%</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="uninstalling">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="h-2 w-20 bg-gray-300 rounded">
|
||||
<div :style="{ width: progress + '%' }" class="h-full bg-green-500"></div>
|
||||
</div>
|
||||
<span>Uninstalling...</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ isInstalled ? 'Uninstall' : 'Install' }}
|
||||
</template>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { nextTick } from 'vue'
|
||||
import feather from 'feather-icons'
|
||||
import defaultImgPlaceholder from "../assets/default_model.png"
|
||||
const bUrl = import.meta.env.VITE_GPT4ALL_API_BASEURL
|
||||
export default {
|
||||
props: {
|
||||
title: String,
|
||||
@ -91,7 +96,7 @@ export default {
|
||||
progress: 0,
|
||||
installing: false,
|
||||
uninstalling: false,
|
||||
failedToLoad:false
|
||||
failedToLoad: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
@ -102,6 +107,17 @@ export default {
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getImgUrl() {
|
||||
|
||||
if (this.icon === '/images/default_model.png') {
|
||||
return defaultImgPlaceholder
|
||||
}
|
||||
|
||||
return this.icon
|
||||
},
|
||||
defaultImg(event) {
|
||||
event.target.src = defaultImgPlaceholder
|
||||
},
|
||||
toggleInstall() {
|
||||
if (this.isInstalled) {
|
||||
this.uninstalling = true;
|
||||
|
@ -1,42 +1,47 @@
|
||||
<template>
|
||||
<div v-if="show" class="absolute bottom-16 right-2 z-20">
|
||||
<div id="toast-success"
|
||||
class="flex items-center w-full max-w-xs p-4 mb-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800"
|
||||
role="alert">
|
||||
<div class="flex flex-row items-center">
|
||||
<slot>
|
||||
<div v-if="success"
|
||||
class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-green-500 bg-green-100 rounded-lg dark:bg-green-800 dark:text-green-200">
|
||||
<i data-feather="check"></i>
|
||||
<span class="sr-only">Check icon</span>
|
||||
<div class="absolute bottom-16 right-2 z-20 flex flex-col gap-3">
|
||||
<TransitionGroup name="toastItem" tag="div">
|
||||
<div v-for=" t in toastArr" :key="t.id">
|
||||
<div id="toast-success"
|
||||
class="flex items-center w-full max-w-xs p-4 mb-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800"
|
||||
role="alert">
|
||||
<div class="flex flex-row items-center">
|
||||
<slot>
|
||||
<div v-if="t.success"
|
||||
class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-green-500 bg-green-100 rounded-lg dark:bg-green-800 dark:text-green-200">
|
||||
<i data-feather="check"></i>
|
||||
<span class="sr-only">Check icon</span>
|
||||
</div>
|
||||
<div v-if="!t.success"
|
||||
class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-red-500 bg-red-100 rounded-lg dark:bg-red-800 dark:text-red-200">
|
||||
<i data-feather="x"></i>
|
||||
<span class="sr-only">Cross icon</span>
|
||||
</div>
|
||||
<div class="ml-3 text-sm font-normal whitespace-pre-wrap">{{ t.message }}</div>
|
||||
|
||||
</slot>
|
||||
</div>
|
||||
<button type="button" @click="close(t.id)"
|
||||
class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700"
|
||||
data-dismiss-target="#toast-success" aria-label="Close">
|
||||
<span class="sr-only">Close</span>
|
||||
<svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div v-if="!success" class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-red-500 bg-red-100 rounded-lg dark:bg-red-800 dark:text-red-200">
|
||||
<i data-feather="x"></i>
|
||||
<span class="sr-only">Cross icon</span>
|
||||
</div>
|
||||
<div class="ml-3 text-sm font-normal whitespace-pre-wrap">{{ message }}</div>
|
||||
|
||||
</slot>
|
||||
</div>
|
||||
<button type="button" @click="close"
|
||||
class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700"
|
||||
data-dismiss-target="#toast-success" aria-label="Close">
|
||||
<span class="sr-only">Close</span>
|
||||
<svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import feather from 'feather-icons'
|
||||
import { nextTick } from 'vue'
|
||||
import { nextTick, TransitionGroup } from 'vue'
|
||||
export default {
|
||||
name: 'Toast',
|
||||
emits: ['close'],
|
||||
@ -47,27 +52,38 @@ export default {
|
||||
return {
|
||||
show: false,
|
||||
success: true,
|
||||
message: ''
|
||||
message: '',
|
||||
toastArr: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$emit('close')
|
||||
this.show = false
|
||||
},
|
||||
showToast(message, duration_s=3, success= true){
|
||||
this.success = success;
|
||||
this.message = message;
|
||||
this.show = true;
|
||||
nextTick(() => {
|
||||
feather.replace()
|
||||
close(id) {
|
||||
|
||||
})
|
||||
this.toastArr = this.toastArr.filter(item => item.id != id)
|
||||
},
|
||||
showToast(message, duration_s = 3, success = true) {
|
||||
const id = parseInt(((new Date()).getTime() * Math.random()).toString()).toString()
|
||||
const toastObj = {
|
||||
id: id,
|
||||
success: success,
|
||||
message: message,
|
||||
show: true
|
||||
}
|
||||
|
||||
|
||||
this.toastArr.push(toastObj)
|
||||
|
||||
nextTick(() => {
|
||||
feather.replace()
|
||||
|
||||
})
|
||||
setTimeout(() => {
|
||||
this.$emit('close')
|
||||
this.show = false
|
||||
}, duration_s*1000);
|
||||
|
||||
this.toastArr = this.toastArr.filter(item => item.id != id)
|
||||
|
||||
}, duration_s * 1000);
|
||||
}
|
||||
|
||||
},
|
||||
watch: {
|
||||
showProp(val) {
|
||||
@ -77,10 +93,22 @@ export default {
|
||||
this.$emit('close')
|
||||
this.show = false
|
||||
}, 3000);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.toastItem-enter-active,
|
||||
.toastItem-leave-active {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.toastItem-enter-from,
|
||||
.toastItem-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
</style>
|
@ -144,7 +144,7 @@
|
||||
<!-- Removed reference to copyToClipBoard() ; function was moved to Message.vue -->
|
||||
<Message v-for="(msg, index) in discussionArr" :key="index" :message="msg" :id="'msg-' + msg.id" ref="messages"
|
||||
@copy="copyToClipBoard" @delete="deleteMessage" @rankUp="rankUpMessage" @rankDown="rankDownMessage"
|
||||
@updateMessage="updateMessage" @resendMessage="resendMessage" />
|
||||
@updateMessage="updateMessage" @resendMessage="resendMessage" :avatar="getAvatar(msg.sender)" />
|
||||
|
||||
<WelcomeComponent v-if="!currentDiscussion.id" />
|
||||
|
||||
@ -187,9 +187,26 @@ export default {
|
||||
showToast: false,
|
||||
isSearch: false,
|
||||
isDiscussionBottom: false,
|
||||
personalityAvatars: [] // object array of personality name: and avatar: props
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async api_get_req(endpoint) {
|
||||
try {
|
||||
const res = await axios.get("/" + endpoint);
|
||||
|
||||
if (res) {
|
||||
|
||||
return res.data
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
async list_discussions() {
|
||||
try {
|
||||
const res = await axios.get('/list_discussions')
|
||||
@ -542,10 +559,10 @@ export default {
|
||||
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 );
|
||||
|
||||
this.setDiscussionLoading(discussion_id, true);
|
||||
if (this.currentDiscussion.id == discussion_id) {
|
||||
|
||||
|
||||
this.isGenerating = true;
|
||||
const index = this.discussionArr.findIndex((x) => x.parent == parent && x.id == msgObj.ai_message_id)
|
||||
const messageItem = this.discussionArr[index]
|
||||
@ -692,7 +709,7 @@ export default {
|
||||
}
|
||||
return newItem
|
||||
|
||||
}).sort(function(a,b){
|
||||
}).sort(function (a, b) {
|
||||
return b.id - a.id
|
||||
})
|
||||
this.list = newDisList
|
||||
@ -854,17 +871,69 @@ export default {
|
||||
const filename = 'discussions_export_' + formattedDate + '.json'
|
||||
this.loading = true
|
||||
const res = await this.export_multiple_discussions(discussionIdArr)
|
||||
|
||||
|
||||
if (res) {
|
||||
this.saveJSONtoFile(res, filename)
|
||||
this.$refs.toast.showToast("Successfully exported", 4, true)
|
||||
this.isCheckbox=false
|
||||
}else{
|
||||
this.isCheckbox = false
|
||||
} else {
|
||||
this.$refs.toast.showToast("Failed to export discussions", 4, false)
|
||||
}
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
},
|
||||
async getPersonalityAvatars() {
|
||||
|
||||
let personalities = []
|
||||
const dictionary = await this.api_get_req("get_all_personalities")
|
||||
const langkeys = Object.keys(dictionary); // returns languages folder names
|
||||
for (let i = 0; i < langkeys.length; i++) {
|
||||
const langkey = langkeys[i];
|
||||
const catdictionary = dictionary[langkey];
|
||||
const catkeys = Object.keys(catdictionary); // returns categories
|
||||
|
||||
for (let j = 0; j < catkeys.length; j++) {
|
||||
const catkey = catkeys[j];
|
||||
const personalitiesArray = catdictionary[catkey];
|
||||
const modPersArr = personalitiesArray.map((item) => {
|
||||
let newItem = {}
|
||||
newItem = item
|
||||
newItem.category = catkey // add new props to items
|
||||
newItem.language = langkey // add new props to items
|
||||
return newItem
|
||||
})
|
||||
|
||||
|
||||
if (personalities.length == 0) {
|
||||
personalities = modPersArr
|
||||
} else {
|
||||
personalities = personalities.concat(modPersArr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.personalityAvatars = personalities.map(item => {
|
||||
const newItem = {
|
||||
name: item.name,
|
||||
avatar: item.avatar
|
||||
}
|
||||
return newItem
|
||||
})
|
||||
// const index = personalities.findIndex((x) => x.name === sender)
|
||||
// const pers = personalities[index]
|
||||
// return pers.avatar
|
||||
|
||||
},
|
||||
getAvatar(sender) {
|
||||
const index = this.personalityAvatars.findIndex((x) => x.name === sender)
|
||||
const pers = this.personalityAvatars[index]
|
||||
if(pers){
|
||||
return pers.avatar
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -890,12 +959,14 @@ export default {
|
||||
socket.on("final", this.finalMsgEvent)
|
||||
|
||||
},
|
||||
activated() {
|
||||
async activated() {
|
||||
// This lifecycle hook runs every time you switch from other page back to this page (vue-router)
|
||||
// To fix scrolling back to last message, this hook is needed.
|
||||
// If anyone knows hor to fix scroll issue when changing pages, please do fix it :D
|
||||
console.log("Websocket connected (activated)", this.socketConnected)
|
||||
|
||||
await this.getPersonalityAvatars()
|
||||
|
||||
if (this.isCreated) {
|
||||
this.loadLastUsedDiscussion()
|
||||
}
|
||||
|
@ -200,7 +200,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- MODEL -->
|
||||
<!-- MODEL CONFIGURATION -->
|
||||
<div
|
||||
class="flex flex-col mb-2 p-3 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">
|
||||
@ -212,6 +212,24 @@
|
||||
</button>
|
||||
</div>
|
||||
<div :class="{ 'hidden': mc_collapsed }" class="flex flex-col mb-2 p-2">
|
||||
<div class="m-2">
|
||||
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
|
||||
<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)">
|
||||
<label for="override-model-parameters" class="block text-sm font-medium ">
|
||||
Override personality model parameters
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- DISABLE PARAMETER SELECTION -->
|
||||
<div :class="!configFile.override_personality_model_parameters ? 'pointer-events-none opacity-30' : ''">
|
||||
|
||||
|
||||
<div class="m-2">
|
||||
<label for="seed" class="block mb-2 text-sm font-medium ">
|
||||
Seed:
|
||||
@ -346,6 +364,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- sdasdas -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -354,6 +374,8 @@
|
||||
<YesNoDialog ref="yesNoDialog" />
|
||||
<MessageBox ref="messageBox" />
|
||||
<Toast ref="toast" />
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -367,6 +389,7 @@ import ModelEntry from '@/components/ModelEntry.vue';
|
||||
import PersonalityViewer from '@/components/PersonalityViewer.vue';
|
||||
import PersonalityEntry from "../components/PersonalityEntry.vue";
|
||||
import socket from '@/services/websocket.js'
|
||||
|
||||
axios.defaults.baseURL = import.meta.env.VITE_GPT4ALL_API_BASEURL
|
||||
export default {
|
||||
components: {
|
||||
@ -377,7 +400,7 @@ export default {
|
||||
PersonalityViewer,
|
||||
Toast,
|
||||
PersonalityEntry,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
||||
return {
|
||||
@ -468,18 +491,18 @@ export default {
|
||||
if (pers.personality) {
|
||||
// if (model_object.isInstalled) {
|
||||
this.settingsChanged = true
|
||||
const res = this.update_setting('personality', pers.personality.name,()=>{
|
||||
const res = this.update_setting('personality', pers.personality.name, () => {
|
||||
this.$refs.toast.showToast("Personality:\n" + pers.personality.name + "\nselected", 4, true)
|
||||
this.configFile.personality = pers.personality.name
|
||||
this.configFile.personality_category = pers.personality.category
|
||||
this.configFile.personality_language = pers.personality.language
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
nextTick(() => {
|
||||
feather.replace()
|
||||
@ -705,7 +728,7 @@ export default {
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
if (res.status) {
|
||||
// this.$refs.messageBox.showMessage("Settings saved!")
|
||||
// this.$refs.messageBox.showMessage("Settings saved!")
|
||||
}
|
||||
else
|
||||
this.$refs.messageBox.showMessage("Error: Couldn't save settings!")
|
||||
@ -767,7 +790,7 @@ export default {
|
||||
},
|
||||
async getPersonalitiesArr() {
|
||||
this.isLoading = true
|
||||
this.personalities=[]
|
||||
this.personalities = []
|
||||
const dictionary = await this.api_get_req("get_all_personalities")
|
||||
const langkeys = Object.keys(dictionary); // returns languages folder names
|
||||
for (let i = 0; i < langkeys.length; i++) {
|
||||
@ -797,7 +820,7 @@ export default {
|
||||
}
|
||||
this.personalitiesFiltered = this.personalities.filter((item) => item.category === this.configFile.personality_category && item.language === this.configFile.personality_language)
|
||||
this.isLoading = false
|
||||
|
||||
|
||||
}
|
||||
|
||||
}, async mounted() {
|
||||
@ -861,6 +884,7 @@ export default {
|
||||
})
|
||||
},
|
||||
all_collapsed(val) {
|
||||
|
||||
this.collapseAll(val)
|
||||
nextTick(() => {
|
||||
feather.replace()
|
||||
@ -882,36 +906,11 @@ export default {
|
||||
isModelSelected(val) {
|
||||
|
||||
console.log('iss selected:', val)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
.loader {
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #3498db;
|
||||
border-radius: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
animation: spin 2s linear infinite;
|
||||
margin-left: 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.height-64 {
|
||||
min-height: 64px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}</style>
|
@ -1,41 +1,39 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./index.html","./src/**/*.{vue,js,ts,jsx,tsx}", 'node_modules/flowbite-vue/**/*.{js,jsx,ts,tsx}'],
|
||||
darkMode:'class',
|
||||
content: [
|
||||
'./index.html',
|
||||
'./src/**/*.{vue,js,ts,jsx,tsx}',
|
||||
'node_modules/flowbite-vue/**/*.{js,jsx,ts,tsx}'
|
||||
],
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
colors:{
|
||||
"primary": "#0e8ef0",
|
||||
"primary-light": "#3dabff",
|
||||
"secondary": "#0fd974",
|
||||
"accent": "#f0700e",
|
||||
"bg-dark": "#132e59",
|
||||
"bg-dark-tone": "#25477d",
|
||||
"bg-dark-tone-panel": "#4367a3",
|
||||
"bg-dark-code-block": "#2254a7",
|
||||
"bg-light": "#e2edff",
|
||||
"bg-light-tone": "#b9d2f7",
|
||||
"bg-light-code-block": "#cad7ed",
|
||||
"bg-light-tone-panel": "#8fb5ef",
|
||||
"bg-dark-discussion": "#435E8A",
|
||||
"bg-dark-discussion-odd": "#284471",
|
||||
"bg-light-discussion": "#c5d8f8",
|
||||
"bg-light-discussion-odd": "#d6e7ff",
|
||||
colors: {
|
||||
primary: '#0e8ef0',
|
||||
'primary-light': '#3dabff',
|
||||
secondary: '#0fd974',
|
||||
accent: '#f0700e',
|
||||
'bg-dark': '#132e59',
|
||||
'bg-dark-tone': '#25477d',
|
||||
'bg-dark-tone-panel': '#4367a3',
|
||||
'bg-dark-code-block': '#2254a7',
|
||||
'bg-light': '#e2edff',
|
||||
'bg-light-tone': '#b9d2f7',
|
||||
'bg-light-code-block': '#cad7ed',
|
||||
'bg-light-tone-panel': '#8fb5ef',
|
||||
'bg-dark-discussion': '#435E8A',
|
||||
'bg-dark-discussion-odd': '#284471',
|
||||
'bg-light-discussion': '#c5d8f8',
|
||||
'bg-light-discussion-odd': '#d6e7ff'
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ["PTSans","Roboto", "sans-serif"],
|
||||
sans: ['PTSans', 'Roboto', 'sans-serif']
|
||||
},
|
||||
container: {
|
||||
padding: "2rem",
|
||||
center: true,
|
||||
},
|
||||
|
||||
},
|
||||
padding: '2rem',
|
||||
center: true
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
require('flowbite/plugin'),
|
||||
require('tailwind-scrollbar'),
|
||||
|
||||
]
|
||||
plugins: [require('flowbite/plugin'), require('tailwind-scrollbar')]
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user