mirror of
https://github.com/ParisNeo/lollms-webui.git
synced 2024-12-19 12:27:52 +00:00
Merge branch 'main' of https://github.com/nomic-ai/gpt4all-ui
This commit is contained in:
commit
d2f158876f
@ -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]
|
2
web/.env
2
web/.env
@ -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 = /
|
||||
|
@ -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
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-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>
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user