This commit is contained in:
ParisNeo 2023-05-05 22:35:11 +02:00
commit d2f158876f
8 changed files with 99 additions and 118 deletions

View File

@ -1,7 +1,39 @@
# GPT4ALL-UI Web interface VUE3 development log, todo's and more
## Installation for development
You must have [Node.js](https://nodejs.org/en) installed on your computer.
```
cd /web/
npm install
```
## Testing, running, debugging
After that to run development server locally and test the web page at http://localhost:5173/:
```
npm run dev
```
> Note
> To run the developmen environment you need to create copy of the `.env` file and name it either `.env.development` or if that dont work then `.env.dev`. Set `VITE_GPT4ALL_API_BASEURL = /api/ ` in the `.env.development`.
> Run your gpt backend by launching `webui.bat` or bash `webui.sh`.
## Building frontend - UI
```
npm run build
```
This will update `/dist/` folder with all the files. Also the build will show you if there are errors or not in your vue code.
> Note
> Make sure you test the built files too, because sometimes the builder dont catch all the errors, and if a component is not refernced it might not load in the built version, but it loads fine in development environment
# UI development log, todo's and more
The new UI is build using Node.js VUE3 + Vite. It uses tailwindcss, feathericons, openfonts and flowbite-vue components.
Here we keep track of things to implement and stuff we need to do.
## Todo's
- Add ability to select multiple discussions to export or delete [WIP]
@ -34,5 +66,4 @@ The new UI is build using Node.js VUE3 + Vite. It uses tailwindcss, feathericons
- Add clear filter button to search input field [DONE]
- Add modal to ask user if you sure about to delete [DONE but in different way]
- Fix up the discussion array to filter out the messages by type not by count. (conditionner and )[DONE]
- Add title of current discussion to page [DONE]
- Add title of current discussion to page [DONE]

View File

@ -1,4 +1,4 @@
VITE_GPT4ALL_API = http://localhost:9600 # http://localhost:9600
VITE_GPT4ALL_API_CHANGE_ORIGIN = 0 # FALSE
VITE_GPT4ALL_API_SECURE = 0 # FALSE
VITE_GPT4ALL_API_BASEURL = / # FALSE
VITE_GPT4ALL_API_BASEURL = /

View File

@ -1,65 +0,0 @@
# GPT4ALL-UI Web interface VUE3
## Dependencies for development
You mus have [Node.js](https://nodejs.org/en) installed on your computer.
```
git clone repo_URL
cd into-this-repo-dir
npm install
```
After that to run development server locally and test the web page at http://localhost:5173/:
```
npm run dev
```
To connect to GPT4ALL-UI API server you need to enter its URL in the `.env` or make a copy of `.env` file and name it `.env.local`. This .env.local is added to `.gitignore`.
All http requests made to GPT4ALL-UI api has to have /api/ prefix. This prefix gets rewritten in the vite.config.js file.
Make changes to your usecase in the `.env.local` file.
Once UI id done you can build static files for serving.
```
npm run build
```
This will create /dist/ folder with all the files. Also the build will show you if there are errors or not in your vue code.
> Make sure you test the static files too, because sometimes the builder dont catch all the errors, and if a component is not refernced it might not load in the built version, but it loads fine in development environment
### Overview of used dependencies and development
- Nodejs
- vue
- feather-icons
- axios
```
npm init vue@latest
```
```
cd gpt4all-ui-vue
npm install
npm run format
npm install axios dotenv
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
npm install feather-icons --save
```
### Running dev environment and building commands
To lint: (not very used)
```
npm run lint
```
To run test:
```
npm run dev
```
To build static files
```
npm run build
```

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-2f3efff7.js"></script>
<link rel="stylesheet" href="/assets/index-76ef06fb.css">
<script type="module" crossorigin src="/assets/index-c75a91fb.js"></script>
<link rel="stylesheet" href="/assets/index-13dee4e0.css">
</head>
<body>
<div id="app"></div>

View File

@ -143,12 +143,6 @@ export default {
checkBoxValue(newval, oldval) {
this.checkBoxValue_local = newval
},
selected(newval, oldval) {
if (newval) {
const realTitle= this.title ? this.title === "untitled" ? "New discussion" : this.title : "New discussion"
document.title = 'GPT4ALL - WEBUI - '+ realTitle
}
}
}
}

View File

@ -49,36 +49,36 @@
</div>
<hr v-if="isCheckbox" class="h-px bg-bg-light p-0 mb-4 px-4 mx-4 border-0 dark:bg-bg-dark">
<div v-if="isCheckbox" class="flex flex-row flex-grow p-4 pt-0 items-center">
<!-- CHECK BOX OPERATIONS -->
<div class="flex flex-row flex-grow gap-3">
Selected: {{ list.filter((item) => item.checkBoxValue == true).length }}
</div>
<div class="flex flex-row gap-3">
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 " title="Select All" type="button"
@click.stop="selectAllDiscussions">
<i data-feather="list"></i>
</button>
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 rotate-90"
title="Export selected to a file" type="button">
<i data-feather="log-out"></i>
</button>
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 " title="Remove selected"
type="button">
<i data-feather="trash"></i>
</button>
</div>
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 " title="Select All"
type="button" @click.stop="selectAllDiscussions">
<i data-feather="list"></i>
</button>
<button class="text-2xl hover:text-secondary duration-75 active:scale-90 rotate-90"
title="Export selected to a file" type="button">
<i data-feather="log-out"></i>
</button>
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 " title="Remove selected"
type="button">
<i data-feather="trash"></i>
</button>
</div>
</div>
</div>
<div class="relative overflow-y-scroll no-scrollbar">
<!-- DISCUSSION LIST -->
<div class="mx-4 flex-grow" :class="filterInProgress ? 'opacity-20 pointer-events-none' : ''">
<Discussion v-for="(item, index) in list" :key="index" :id="item.id" :title="item.title"
:selected="currentDiscussion.id == item.id" :loading="item.loading"
:isCheckbox="isCheckbox" :checkBoxValue="item.checkBoxValue" @select="selectDiscussion(item)"
@delete="deleteDiscussion(item.id)" @editTitle="editTitle" @checked="checkUncheckDiscussion" />
:selected="currentDiscussion.id == item.id" :loading="item.loading" :isCheckbox="isCheckbox"
:checkBoxValue="item.checkBoxValue" @select="selectDiscussion(item)" @delete="deleteDiscussion(item.id)"
@editTitle="editTitle" @checked="checkUncheckDiscussion" />
<div v-if="list.length < 1"
class="gap-2 py-2 my-2 hover:shadow-md hover:bg-primary-light dark:hover:bg-primary rounded-md p-2 duration-75 group cursor-pointer">
@ -148,12 +148,12 @@ export default {
try {
if (id) {
this.loading = true
this.setDiscussionLoading(id,this.loading)
this.setDiscussionLoading(id, this.loading)
const res = await axios.post('/load_discussion', {
id: id
})
this.loading = false
this.setDiscussionLoading(id,this.loading)
this.setDiscussionLoading(id, this.loading)
if (res) {
// Filter out the user and bot entries
this.discussionArr = res.data.filter((item) => item.type == 0)
@ -169,7 +169,7 @@ export default {
} catch (error) {
console.log(error)
this.loading = false
this.setDiscussionLoading(id,this.loading)
this.setDiscussionLoading(id, this.loading)
}
},
async new_discussion(title) {
@ -188,30 +188,30 @@ export default {
try {
if (id) {
this.loading = true
this.setDiscussionLoading(id,this.loading)
this.setDiscussionLoading(id, this.loading)
const res = await axios.post('/delete_discussion', {
id: id
})
this.loading = false
this.setDiscussionLoading(id,this.loading)
this.setDiscussionLoading(id, this.loading)
}
} catch (error) {
console.log(error)
this.loading = false
this.setDiscussionLoading(id,this.loading)
this.setDiscussionLoading(id, this.loading)
}
},
async edit_title(id, new_title) {
try {
if (id) {
this.loading = true
this.setDiscussionLoading(id,this.loading)
this.setDiscussionLoading(id, this.loading)
const res = await axios.post('/edit_title', {
id: id,
title: new_title
})
this.loading = false
this.setDiscussionLoading(id,this.loading)
this.setDiscussionLoading(id, this.loading)
if (res.status == 200) {
const index = this.list.findIndex((x) => x.id == id)
const discussionItem = this.list[index]
@ -222,7 +222,7 @@ export default {
} catch (error) {
console.log(error)
this.loading = false
this.setDiscussionLoading(id,this.loading)
this.setDiscussionLoading(id, this.loading)
}
},
filterDiscussions() {
@ -241,6 +241,8 @@ export default {
this.currentDiscussion = item
this.setPageTitle(item)
localStorage.setItem('selected_discussion', this.currentDiscussion.id)
await this.load_discussion(item.id)
@ -271,7 +273,7 @@ export default {
// "id": 112,
// "response_id": 113
// }
// Create user input message
let usrMessage = {
content: msgObj.message,
@ -305,14 +307,14 @@ export default {
if (this.currentDiscussion.title === '' || this.currentDiscussion.title === null) {
this.changeTitleUsingUserMSG(this.currentDiscussion.id, usrMessage.content)
}
this.isGenerating = false
this.setDiscussionLoading(this.currentDiscussion.id,this.isGenerating)
this.setDiscussionLoading(this.currentDiscussion.id, this.isGenerating)
},
sendMsg(msg) {
// Sends message to backend
this.isGenerating = true
this.setDiscussionLoading(this.currentDiscussion.id,this.isGenerating)
this.setDiscussionLoading(this.currentDiscussion.id, this.isGenerating)
websocket.emit('generate_msg', { prompt: msg })
},
steamMessageContent(content) {
@ -354,12 +356,12 @@ export default {
if (id) {
const index = this.list.findIndex((x) => x.id == id)
const discussionItem = this.list[index]
if(discussionItem){
if (discussionItem) {
this.selectDiscussion(discussionItem)
}
}
},
async deleteDiscussion(id) {
async deleteDiscussion(id) {
// Deletes discussion from backend and frontend
const index = this.list.findIndex((x) => x.id == id)
@ -368,9 +370,10 @@ export default {
await this.delete_discussion(id)
if (this.currentDiscussion.id == id) {
this.currentDiscussion = {}
this.discussionArr=[]
this.discussionArr = []
this.setPageTitle()
}
this.list.splice(this.list.findIndex(item => item.id==id),1)
this.list.splice(this.list.findIndex(item => item.id == id), 1)
this.createDiscussionList(this.list)
//await this.list_discussions()
@ -423,15 +426,32 @@ export default {
}
},
setDiscussionLoading(id,loading){
setDiscussionLoading(id, loading) {
const index = this.list.findIndex((x) => x.id == id)
const discussionItem = this.list[index]
discussionItem.loading = loading
},
setPageTitle(item) {
// item is either title:String or {id:Number, title:String}
if (item) {
if (item.id) {
const realTitle = item.title ? item.title === "untitled" ? "New discussion" : item.title : "New discussion"
document.title = 'GPT4ALL - WEBUI - ' + realTitle
} else {
const title = item || "Welcome"
document.title = 'GPT4ALL - WEBUI - ' + title
}
} else {
const title = item || "Welcome"
document.title = 'GPT4ALL - WEBUI - ' + title
}
}
},
async created() {
// Constructor
this.setPageTitle()
await this.list_discussions()
this.loadLastUsedDiscussion()
@ -475,7 +495,8 @@ export default {
if (!newval) {
this.isSelectAll = false
}
}
},
}
}
</script>