enhanced ui

This commit is contained in:
Saifeddine ALOUI 2024-01-02 00:53:49 +01:00
parent 123b0fef72
commit 70dc2f4663
16 changed files with 4081 additions and 3880 deletions

@ -1 +1 @@
Subproject commit b3510e5f68acb56f944e380b6e69ac192b1ea3fb
Subproject commit 402d01cfe09f8f68771ffdebad09097dd368d6cb

View File

@ -19,4 +19,6 @@ packaging
fastapi
uvicorn
python-socketio
python-socketio[client]
python-socketio[asyncio_client]

View File

@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue</title>
<script type="module" crossorigin src="/assets/index-gD_iVx44.js"></script>
<script type="module" crossorigin src="/assets/index-xU-eXePa.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-tsveoIuX.css">
</head>
<body>

View File

@ -1,7 +1,8 @@
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import { createStore } from 'vuex'
import App from './App.vue';
import Install from './components/Install.vue';
import Install from './views/Install.vue';
import './style.css';
const routes = [
{
@ -16,4 +17,51 @@ const router = createRouter({
routes,
});
// Create a new store instance.
export const store = createStore({
state () {
return {
// count: 0,
yesNoDialog:null,
universalForm:null,
toast:null,
messageBox:null,
api_get_req:null,
startSpeechRecognition:null,
ready:false,
loading_infos: "",
loading_progress: 0,
version : "unknown",
settingsChanged:false,
isConnected: false, // Add the isConnected property
isModelOk: false,
isGenerating: false,
config:null,
mountedPers:null,
mountedPersArr:[],
mountedExtensions:[],
bindingsZoo:[],
modelsArr:[],
selectedModel:null,
personalities:[],
diskUsage:null,
ramUsage:null,
vramUsage:null,
modelsZoo:[],
installedModels:[],
currentModel:null,
extensionsZoo:[],
databases:[],
}
},
mutations: {
},
getters: {
},
actions: {
}
})
createApp(App).use(router).mount('#app');

View File

@ -1,5 +1,6 @@
<template>
<div class="flex flex-col items-center justify-center rounded-lg m-2 shadow-lg hover:border-primary dark:hover:border-primary hover:border-solid hover:border-2 border-2 border-transparent even:bg-bg-light-discussion-odd dark:even:bg-bg-dark-discussion-odd flex flex-col flex-grow flex-wrap overflow-visible p-4 pb-2">
<img :src = "LoLLMSLogo">
<h1 class="text-4xl font-bold mb-4">LOLLMS installation tool</h1>
<p class="text-left">
Welcome to the installer of lollms. Here you can select your install profile.<br>
@ -7,11 +8,11 @@
</p>
<div class="flex flex-col gap-2">
<label class="flex items-center">
<input type="radio" value="nvidia" v-model="selectedOption" class="mr-2">
<input type="radio" value="cuda" v-model="selectedOption" class="mr-2">
Use NVIDIA GPU with CUDA
</label>
<label class="flex items-center">
<input type="radio" value="amd" v-model="selectedOption" class="mr-2">
<input type="radio" value="rocm" v-model="selectedOption" class="mr-2">
Use AMD GPU with ROCm
</label>
<label class="flex items-center">
@ -27,16 +28,23 @@
Install
</button>
</div>
<MessageBox ></MessageBox>
</template>
<script>
import MessageBox from '../components/messageBox.vue';
import axios from 'axios';
import LoLLMSLogo from '../assets/logo.png'
export default {
data() {
return {
LoLLMSLogo:LoLLMSLogo,
selectedOption: "cpu",
};
},
components:{
MessageBox
},
methods: {
install() {
axios.post("/start_installing",{mode:this.selectedOption}).then(()=>{

View File

@ -1,10 +1,18 @@
"""
Project: lollms_installer
Author: Your Name
Description: This tool is designed to install and configure the LoLLMS system on your machine. LoLLMS is a multi-bindings, multi-personalities LLM full-stack system for AI applications in robotics. It provides a user-friendly interface for setting up and managing the system.
"""
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
import uvicorn
from lollms.paths import LollmsPaths
from lollms.main_config import LOLLMSConfig
from lollms.utilities import check_and_install_torch, PackageManager
from lollms.utilities import check_and_install_torch, PackageManager, check_torch_version, reinstall_pytorch_with_cuda, reinstall_pytorch_with_cpu, reinstall_pytorch_with_rocm
from lollms.com import NotificationType, NotificationDisplayType, LoLLMsCom
from lollms.types import MSG_TYPE, SENDER_TYPES
from lollms.app import LollmsApplication
from pathlib import Path
from ascii_colors import ASCIIColors
import subprocess
@ -13,6 +21,7 @@ from pathlib import Path
from starlette.responses import FileResponse
from starlette.requests import Request
import webbrowser
import socketio
root_path = Path(__file__).parent.parent.parent.parent
global_path = root_path/"global_paths_cfg.yaml"
@ -34,8 +43,12 @@ ASCIIColors.red("|_____|_____|_____|_____|_|_|_|_____|")
ASCIIColors.red(" Configurator ")
ASCIIColors.red(" LoLLMS configuratoin tool")
ASCIIColors.yellow(f"Root dir : {root_path}")
app = FastAPI(debug=True)
sio = socketio.AsyncServer(async_mode='asgi')
app = FastAPI(debug=True)
app.mount("/socket.io", socketio.ASGIApp(sio))
lollms_app = LollmsApplication("lollms_installer",config=config,lollms_paths=lollms_paths, load_binding=False, load_model=False, socketio=sio)
# Serve the index.html file for all routes
@app.get("/{full_path:path}")
@ -50,21 +63,60 @@ async def serve_index(request: Request, full_path: Path):
# app.mount("/", StaticFiles(directory=root_path/"scripts/python/lollms_installer/frontend/dist"), name="static")
class InstallProperties(BaseModel):
mode: str
@app.post("/start_installing")
def start_installing(data: InstallProperties):
"""
Handle the start_installing endpoint.
Parameters:
- **data**: An instance of the `InstallProperties` model containing the installation mode.
Returns:
- A dictionary with a "message" key indicating the success of the installation.
"""
if data.mode=="cpu":
config.enable_gpu=False
config.save_config()
else:
config.enable_gpu=False
try:
lollms_app.ShowBlockingMessage("Installing pytorch for CPU")
reinstall_pytorch_with_cpu()
config.save_config()
lollms_app.HideBlockingMessage()
except:
lollms_app.HideBlockingMessage()
elif data.mode=="cuda":
config.enable_gpu=True
config.save_config()
try:
lollms_app.ShowBlockingMessage("Installing pytorch for nVidia GPU (cuda)")
reinstall_pytorch_with_cuda()
config.save_config()
lollms_app.HideBlockingMessage()
except:
lollms_app.HideBlockingMessage()
elif data.mode=="rocm":
config.enable_gpu=True
try:
lollms_app.ShowBlockingMessage("Installing pytorch for AMD GPU (rocm)")
reinstall_pytorch_with_rocm()
config.save_config()
lollms_app.HideBlockingMessage()
except:
lollms_app.HideBlockingMessage()
elif data.mode=="metal":
try:
lollms_app.ShowBlockingMessage("Installing pytorch for Apple Silicon (Metal)")
config.enable_gpu=False
reinstall_pytorch_with_cpu()
config.save_config()
lollms_app.HideBlockingMessage()
except:
lollms_app.HideBlockingMessage()
# Your code here
return {"message": "Item created successfully"}
if __name__ == "__main__":
webbrowser.open(f"http://localhost:8000")
uvicorn.run(app, host="0.0.0.0", port=8000)
uvicorn.run(app, host="localhost", port=8000)

3845
web/dist/assets/index-0655b628.js 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

File diff suppressed because one or more lines are too long

4
web/dist/index.html vendored
View File

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI - Welcome</title>
<script type="module" crossorigin src="/assets/index-5f09bbb6.js"></script>
<link rel="stylesheet" href="/assets/index-fdc1d634.css">
<script type="module" crossorigin src="/assets/index-0655b628.js"></script>
<link rel="stylesheet" href="/assets/index-a45078bc.css">
</head>
<body>
<div id="app"></div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -72,7 +72,7 @@
title="Edit message" @click.stop="editMsgMode = true">
<i data-feather="edit"></i>
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer hover:border-2"
title="Add python block" @click.stop="addBlock('python')">
<img :src="python_block" width="25" height="25">
</div>
@ -80,6 +80,11 @@
title="Add javascript block" @click.stop="addBlock('javascript')">
<img :src="javascript_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add json block" @click.stop="addBlock('json')">
<img :src="json_block" width="25" height="25">
</div>
<div v-if="editMsgMode" class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add c++ block" @click.stop="addBlock('c++')">
<img :src="cpp_block" width="25" height="25">
@ -268,6 +273,7 @@ import axios from 'axios';
import python_block from '@/assets/python_block.png';
import javascript_block from '@/assets/javascript_block.svg';
import json_block from '@/assets/json_block.png';
import cpp_block from '@/assets/cpp_block.png';
import html5_block from '@/assets/html5_block.png';
import LaTeX_block from '@/assets/LaTeX_block.png';
@ -299,6 +305,7 @@ export default {
cpp_block:cpp_block,
html5_block:html5_block,
LaTeX_block:LaTeX_block,
json_block:json_block,
javascript_block:javascript_block,
python_block:python_block,
bash_block:bash_block,
@ -342,21 +349,76 @@ export default {
const textarea = event.target;
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const textBefore = textarea.value.substring(0, start);
const textAfter = textarea.value.substring(end);
// Insert a tab character (or spaces if you prefer) at the cursor position
const newText = textBefore + ' ' + textAfter;
// Update the textarea content and cursor position
this.message.content = newText;
this.$nextTick(() => {
textarea.selectionStart = textarea.selectionEnd = start + 4;
});
const isShiftPressed = event.shiftKey;
if (start === end) {
// If no text is selected, insert a tab or backtab as usual
if (isShiftPressed) {
if(textarea.value.substring(start - 4,start)==" "){
// Backtab
const textBefore = textarea.value.substring(0, start - 4);
const textAfter = textarea.value.substring(end);
// Remove the tab character (or spaces if you prefer) before the cursor position
const newText = textBefore + textAfter;
// Update the textarea content and cursor position
this.message.content = newText;
this.$nextTick(() => {
textarea.selectionStart = textarea.selectionEnd = start - 4;
});
}
} else {
// Tab
const textBefore = textarea.value.substring(0, start);
const textAfter = textarea.value.substring(end);
// Insert a tab character (or spaces if you prefer) at the cursor position
const newText = textBefore + ' ' + textAfter;
// Update the textarea content and cursor position
this.message.content = newText;
this.$nextTick(() => {
textarea.selectionStart = textarea.selectionEnd = start + 4;
});
}
} else {
// If text is selected, insert a tab or backtab at the beginning of each selected line
const lines = textarea.value.substring(start, end).split('\n');
const updatedLines = lines.map((line) => {
if (line.trim() === '') {
return line; // Skip empty lines
} else if (isShiftPressed) {
// Backtab
if (line.startsWith(' ')) {
return line.substring(4); // Remove the tab character (or spaces if you prefer)
} else {
return line; // Line doesn't start with a tab, skip backtab
}
} else {
// Tab
return ' ' + line; // Insert a tab character (or spaces if you prefer) at the beginning of the line
}
});
const textBefore = textarea.value.substring(0, start);
const textAfter = textarea.value.substring(end);
// Update the textarea content with the modified lines
const newText = textBefore + updatedLines.join('\n') + textAfter;
this.message.content = newText;
// Update the textarea selection range
this.$nextTick(() => {
textarea.selectionStart = start;
textarea.selectionEnd = end + (updatedLines.length * 4); // Adjust selection end based on the added tabs
});
}
event.preventDefault();
},
onVoicesChanged() {
// This event will be triggered when the voices are loaded
this.voices = this.speechSynthesis.getVoices();
@ -460,15 +522,29 @@ export default {
this.expanded = !this.expanded;
},
addBlock(bloc_name){
let p =this.$refs.mdTextarea.selectionStart
if(p==0 || this.message.content[p-1]=="\n"){
this.message.content = this.message.content.slice(0, p) + "```"+bloc_name+"\n\n```\n" + this.message.content.slice(p)
p = p+4+bloc_name.length
let ss =this.$refs.mdTextarea.selectionStart
let se =this.$refs.mdTextarea.selectionEnd
if(ss==se){
if(speechSynthesis==0 || this.message.content[ss-1]=="\n"){
this.message.content = this.message.content.slice(0, ss) + "```"+bloc_name+"\n\n```\n" + this.message.content.slice(ss)
ss = ss+4+bloc_name.length
}
else{
this.message.content = this.message.content.slice(0, ss) + "\n```"+bloc_name+"\n\n```\n" + this.message.content.slice(ss)
ss = ss+3+bloc_name.length
}
}
else{
this.message.content = this.message.content.slice(0, p) + "\n```"+bloc_name+"\n\n```\n" + this.message.content.slice(p)
p = p+3+bloc_name.length
if(speechSynthesis==0 || this.message.content[ss-1]=="\n"){
this.message.content = this.message.content.slice(0, ss) + "```"+bloc_name+"\n"+this.message.content.slice(ss, se)+"\n```\n" + this.message.content.slice(se)
ss = ss+4+bloc_name.length
}
else{
this.message.content = this.message.content.slice(0, ss) + "\n```"+bloc_name+"\n"+this.message.content.slice(ss, se)+"\n```\n" + this.message.content.slice(se)
p = p+3+bloc_name.length
}
}
this.$refs.mdTextarea.focus();
this.$refs.mdTextarea.selectionStart = this.$refs.mdTextarea.selectionEnd = p;
},

View File

@ -66,6 +66,10 @@
title="Add javascript block" @click.stop="addBlock('javascript')">
<img :src="javascript_block" width="25" height="25">
</div>
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add json block" @click.stop="addBlock('json')">
<img :src="json_block" width="25" height="25">
</div>
<div class="text-lg hover:text-secondary duration-75 active:scale-90 p-2 cursor-pointer"
title="Add c++ block" @click.stop="addBlock('c++')">
<img :src="cpp_block" width="25" height="25">
@ -210,6 +214,8 @@ const bUrl = import.meta.env.VITE_LOLLMS_API_BASEURL
import python_block from '@/assets/python_block.png';
import javascript_block from '@/assets/javascript_block.svg';
import json_block from '@/assets/json_block.png';
import cpp_block from '@/assets/cpp_block.png';
import html5_block from '@/assets/html5_block.png';
import LaTeX_block from '@/assets/LaTeX_block.png';
@ -368,6 +374,7 @@ export default {
html5_block:html5_block,
LaTeX_block:LaTeX_block,
javascript_block:javascript_block,
json_block:json_block,
python_block:python_block,
bash_block:bash_block,

View File

@ -2445,8 +2445,9 @@ export default {
//this.settingsChanged = true
if (pers.isMounted && this.configFile.personalities.includes(pers.full_path)) {
let pth = pers.language==null?pers.full_path:pers.full_path+":"+pers.language
console.log("pth",pth)
if (pers.isMounted && this.configFile.personalities.includes(pth)) {
const res = await this.select_personality(pers)
console.log('pers is mounted', res)
@ -3553,7 +3554,9 @@ export default {
},
async select_personality(pers) {
if (!pers) { return { 'status': false, 'error': 'no personality - select_personality' } }
const id = this.configFile.personalities.findIndex(item => item === pers.full_path)
let pth = pers.language==null?pers.full_path:pers.full_path+":"+pers.language
console.log("pth",pth)
const id = this.configFile.personalities.findIndex(item => item === pth)
const obj = {
id: id

@ -1 +1 @@
Subproject commit ea9afc3e5630611af10f19106ee28927dd587587
Subproject commit c3f213ff684684c65b26262303a206a66cd9e638