enhanced version

This commit is contained in:
Saifeddine ALOUI 2023-08-16 03:47:54 +02:00
parent c69adacf68
commit 5c4078c63a
11 changed files with 218 additions and 51 deletions

View File

@ -113,7 +113,7 @@ class LoLLMsAPPI(LollmsApplication):
def __init__(self, config:LOLLMSConfig, socketio, config_file_path:str, lollms_paths: LollmsPaths) -> None:
super().__init__("Lollms_webui",config, lollms_paths, callback=self.process_chunk)
self.is_ready = True
self.buzy = False
self.socketio = socketio
@ -516,7 +516,7 @@ class LoLLMsAPPI(LollmsApplication):
self.notify("Model not selected. Please select a model", False, client_id)
return
if self.is_ready:
if not self.buzy:
if self.connections[client_id]["current_discussion"] is None:
if self.db.does_last_discussion_have_messages():
self.connections[client_id]["current_discussion"] = self.db.create_discussion()
@ -540,6 +540,7 @@ class LoLLMsAPPI(LollmsApplication):
self.socketio.sleep(0.01)
ASCIIColors.info("Started generation task")
self.buzy=True
#tpe = threading.Thread(target=self.start_message_generation, args=(message, message_id, client_id))
#tpe.start()
else:
@ -761,7 +762,7 @@ class LoLLMsAPPI(LollmsApplication):
if self.config["debug"]:
ASCIIColors.yellow(discussion_messages)
ASCIIColors.yellow(f"prompt size:{len(tokens)} tokens")
ASCIIColors.info(f"prompt size:{tokens.shape} tokens")
return discussion_messages, message.content, tokens
@ -887,9 +888,7 @@ class LoLLMsAPPI(LollmsApplication):
)
def process_chunk(self, chunk, message_type:MSG_TYPE, metadata:dict={}, client_id:int=0):
"""
0 : a regular message
1 : a notification message
2 : A hidden message
Processes a chunk of generated text
"""
if message_type == MSG_TYPE.MSG_TYPE_STEP:
@ -945,7 +944,7 @@ class LoLLMsAPPI(LollmsApplication):
self.connections[client_id]["generated_text"] = chunk
self.nb_received_tokens += 1
ASCIIColors.green(f"Received {self.nb_received_tokens} tokens",end="\r",flush=True)
self.update_message(client_id, chunk, metadata)
self.update_message(client_id, chunk, metadata, msg_type=message_type)
return True
# Stream the generated text to the frontend
else:
@ -1055,6 +1054,8 @@ class LoLLMsAPPI(LollmsApplication):
ASCIIColors.success(f" ╔══════════════════════════════════════════════════╗ ")
ASCIIColors.success(f" ║ Done ║ ")
ASCIIColors.success(f" ╚══════════════════════════════════════════════════╝ ")
self.buzy=False
else:
ump = self.config.discussion_prompt_separator +self.config.user_name+": " if self.config.use_user_name_in_discussions else self.personality.user_message_prefix
@ -1065,5 +1066,6 @@ class LoLLMsAPPI(LollmsApplication):
self.notify("No discussion selected!!!",False, client_id)
print()
self.buzy=False
return ""

64
app.py
View File

@ -99,6 +99,7 @@ log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)
app = Flask("Lollms-WebUI", static_url_path="/static", static_folder="static")
# async_mode='gevent', ping_timeout=1200, ping_interval=120,
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading',engineio_options={'websocket_compression': False, 'websocket_ping_interval': 20, 'websocket_ping_timeout': 120, 'websocket_max_queue': 100})
@ -236,6 +237,8 @@ class LoLLMsWebUI(LoLLMsAPPI):
self.add_endpoint("/list_mounted_personalities", "list_mounted_personalities", self.list_mounted_personalities, methods=["POST"])
self.add_endpoint("/mount_personality", "mount_personality", self.p_mount_personality, methods=["POST"])
self.add_endpoint("/remount_personality", "remount_personality", self.p_remount_personality, methods=["POST"])
self.add_endpoint("/unmount_personality", "unmount_personality", self.p_unmount_personality, methods=["POST"])
self.add_endpoint("/select_personality", "select_personality", self.p_select_personality, methods=["POST"])
@ -288,9 +291,10 @@ class LoLLMsWebUI(LoLLMsAPPI):
)
self.add_endpoint("/delete_personality", "delete_personality", self.delete_personality, methods=["GET"])
self.add_endpoint("/", "", self.index, methods=["GET"])
self.add_endpoint("/settings/", "", self.index, methods=["GET"])
self.add_endpoint("/<path:filename>", "serve_static", self.serve_static, methods=["GET"])
self.add_endpoint("/user_infos/<path:filename>", "serve_user_infos", self.serve_user_infos, methods=["GET"])
@ -932,7 +936,7 @@ class LoLLMsWebUI(LoLLMsAPPI):
def get_generation_status(self):
return jsonify({"status":not self.is_ready})
return jsonify({"status":self.buzy})
def stop_gen(self):
self.cancel_gen = True
@ -1244,6 +1248,60 @@ class LoLLMsWebUI(LoLLMsAPPI):
ASCIIColors.error(f"nok : Personality not found @ {pth}")
return jsonify({"status": False, "error":f"Personality not found @ {pth}"})
def p_remount_personality(self):
print("- Remounting personality")
try:
data = request.get_json()
# Further processing of the data
except Exception as e:
print(f"Error occurred while parsing JSON: {e}")
return
language = data['language']
category = data['category']
name = data['folder']
package_path = f"{language}/{category}/{name}"
package_full_path = self.lollms_paths.personalities_zoo_path/package_path
config_file = package_full_path / "config.yaml"
if config_file.exists():
ASCIIColors.info(f"Unmounting personality {package_path}")
index = self.config["personalities"].index(f"{language}/{category}/{name}")
self.config["personalities"].remove(f"{language}/{category}/{name}")
if self.config["active_personality_id"]>=index:
self.config["active_personality_id"]=0
if len(self.config["personalities"])>0:
self.mounted_personalities = self.rebuild_personalities()
self.personality = self.mounted_personalities[self.config["active_personality_id"]]
else:
self.personalities = ["english/generic/lollms"]
self.mounted_personalities = self.rebuild_personalities()
self.personality = self.mounted_personalities[self.config["active_personality_id"]]
ASCIIColors.info(f"Mounting personality {package_path}")
self.config["personalities"].append(package_path)
self.mounted_personalities = self.rebuild_personalities()
self.personality = self.mounted_personalities[self.config["active_personality_id"]]
self.apply_settings()
ASCIIColors.success("ok")
if self.config["active_personality_id"]<0:
return jsonify({"status": False,
"personalities":self.config["personalities"],
"active_personality_id":self.config["active_personality_id"]
})
else:
return jsonify({"status": True,
"personalities":self.config["personalities"],
"active_personality_id":self.config["active_personality_id"]
})
else:
pth = str(config_file).replace('\\','/')
ASCIIColors.error(f"nok : Personality not found @ {pth}")
return jsonify({"status": False, "error":f"Personality not found @ {pth}"})
def p_unmount_personality(self):
print("- Unmounting personality ...")
try:

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-c75baf49.js"></script>
<link rel="stylesheet" href="/assets/index-9c82748a.css">
<script type="module" crossorigin src="/assets/index-16e1e498.js"></script>
<link rel="stylesheet" href="/assets/index-498e6c2a.css">
</head>
<body>
<div id="app"></div>

View File

@ -111,6 +111,7 @@
<MountedPersonalitiesList ref="mountedPersList"
:onShowPersList="onShowPersListFun"
:on-mount-unmount="onMountUnmountFun"
:on-remount="onRemount"
:on-talk="handleOnTalk"
:discussionPersonalities="allDiscussionPersonalities" />
</div>
@ -338,6 +339,10 @@ export default {
console.log('Mounting/unmounting chat')
this.$refs.mountedPers.constructor()
},
onRemount(comp){
console.log('Remounting chat')
this.$refs.mountedPers.constructor()
},
computedFileSize(size) {
nextTick(() => {
feather.replace()

View File

@ -38,7 +38,7 @@
<personality-entry ref="personalitiesZoo" v-for="(pers, index) in this.$store.state.mountedPersArr"
:key="'index-' + index + '-' + pers.name" :personality="pers" :full_path="pers.full_path"
:selected="configFile.personalities[configFile.active_personality_id] === pers.full_path"
:on-selected="onPersonalitySelected" :on-mounted="onPersonalityMounted"
:on-selected="onPersonalitySelected" :on-mounted="onPersonalityMounted" :on-remount="onPersonalityRemount"
:on-settings="onSettingsPersonality" :on-reinstall="onPersonalityReinstall"
:on-talk="handleOnTalk"
/>
@ -91,6 +91,7 @@ export default {
props: {
onTalk:Function,
onMountUnmount: Function,
onRemount: Function,
discussionPersonalities: Array,
onShowPersList: Function,
@ -221,6 +222,9 @@ export default {
}
},
onPersonalityRemount(persItem){
this.reMountPersonality(persItem)
},
async handleOnTalk(pers){
// eslint-disable-next-line no-unused-vars
@ -346,6 +350,28 @@ export default {
}
},
async remount_personality(pers) {
if (!pers) { return { 'status': false, 'error': 'no personality - mount_personality' } }
try {
const obj = {
language: pers.language,
category: pers.category,
folder: pers.folder
}
const res = await axios.post('/remount_personality', obj);
if (res) {
return res.data
}
} catch (error) {
console.log(error.message, 'remount_personality - settings')
return
}
},
async unmount_personality(pers) {
if (!pers) { return { 'status': false, 'error': 'no personality - unmount_personality' } }
@ -432,6 +458,37 @@ export default {
}
},
async reMountPersonality(pers) {
console.log('remount pers', pers)
if (!pers) { return }
if (!this.configFile.personalities.includes(pers.personality.full_path)) {
this.$refs.toast.showToast("Personality not mounted", 4, false)
return
}
const res = await this.remount_personality(pers.personality)
console.log('remount_personality res', res)
if (res.status) {
this.configFile.personalities = res.personalities
this.$refs.toast.showToast("Personality remounted", 4, true)
pers.isMounted = true
this.toggleMountUnmount()
const res2 = await this.select_personality(pers.personality)
if (res2.status) {
this.$refs.toast.showToast("Selected personality:\n" + pers.personality.name, 4, true)
}
this.getMountedPersonalities()
} else {
pers.isMounted = false
this.$refs.toast.showToast("Could not mount personality\nError: " + res.error, 4, false)
}
},
async unmountPersonality(pers) {

View File

@ -3,32 +3,32 @@
<div class="w-full">
<ul class="flex flex-row font-medium">
<li>
<RouterLink :to="{ name: 'discussions' }" class="link-item">
<RouterLink :to="{ name: 'discussions' }" class="link-item dark:link-item-dark">
Discussions
</RouterLink>
</li>
<li>
<RouterLink :to="{ name: 'settings' }" class="link-item">
<RouterLink :to="{ name: 'settings' }" class="link-item dark:link-item-dark">
Settings
</RouterLink>
</li>
<li>
<RouterLink :to="{ name: 'extensions' }" class="link-item">
<RouterLink :to="{ name: 'extensions' }" class="link-item dark:link-item-dark">
Extensions
</RouterLink>
</li>
<li>
<RouterLink :to="{ name: 'training' }" class="link-item">
<RouterLink :to="{ name: 'training' }" class="link-item dark:link-item-dark">
Training
</RouterLink>
</li>
<li>
<RouterLink :to="{ name: 'quantizing' }" class="link-item">
<RouterLink :to="{ name: 'quantizing' }" class="link-item dark:link-item-dark">
Quantizing
</RouterLink>
</li>
<li>
<RouterLink :to="{ name: 'help' }" class="link-item">
<RouterLink :to="{ name: 'help' }" class="link-item dark:link-item-dark">
Help
</RouterLink>
</li>
@ -63,7 +63,7 @@
font-weight: bold; /* Optional: Add font-weight for emphasis */
/* Use different colors for dark and light modes */
background-color: #b9d2f7; /* Use your theme's 'bg-light-tone' color for light mode */
background-color: #82a1d4; /* Use your theme's 'bg-light-tone' color for light mode */
color: #000; /* Use your theme's 'primary' color for light mode */
@ -81,9 +81,45 @@
/* Optional: Change the color when the link is active */
.link-item.router-link-active {
background-color: #82a1d4; /* Use your theme's 'bg-dark-tone' color for active link in dark mode */
background-color: #b9d2f7; /* Use your theme's 'bg-dark-tone' color for active link in dark mode */
}
.link-item-dark {
/* Thin out the links */
padding: 0px 20px;
margin-bottom: -5px; /* Removes the gap between li elements */
display: flex;
align-items: center;
justify-content: center;
border: 1px solid transparent; /* Ensure all links have the same height */
border-radius: 5px 5px 0 0; /* Rounded corners on the top */
font-weight: bold; /* Optional: Add font-weight for emphasis */
/* Use different colors for dark and light modes */
background-color: #132e59; /* Use your theme's 'bg-light-tone' color for light mode */
color: #000; /* Use your theme's 'primary' color for light mode */
/* Animate the links when hovered */
transition: duration-300 ease-in-out transform;
}
.link-item-dark:hover {
background-color: #0cc96a; /* Use your theme's 'primary-light' color for the hover effect */
animation-timing-function: ease-in-out;
}
/* Optional: Change the color when the link is active */
.link-item-dark.router-link-active {
background-color: #25477d; /* Use your theme's 'bg-dark-tone' color for active link in dark mode */
}
/* Ensure each li extends to the bottom of its container */
ul {
display: flex;

View File

@ -48,7 +48,12 @@
<span class="sr-only">Remove</span>
</button>
<button v-if="isMounted" title="Remount personality (useful if you have changed it)" type="button" @click.stop="reMount"
class="inline-flex items-center gap-2 px-3 py-2 text-xs font-medium text-center focus:outline-none text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-red-300 rounded-lg dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-900">
<i data-feather="refresh-ccw" class="w-5"></i>
<span class="sr-only">Remount</span>
</button>
</div>
<div class="">
<div class="">
@ -99,6 +104,7 @@ export default {
onTalk:Function,
onSelected: Function,
onMounted: Function,
onRemount: Function,
onReinstall: Function,
onSettings: Function
},
@ -136,6 +142,9 @@ selected_computed(){
toggleSelected() {
this.onSelected(this)
},
reMount(){
this.onRemount(this)
},
toggleMounted() {
this.onMounted(this)
},

View File

@ -1256,6 +1256,7 @@ export default {
console.log("--------------------")
console.log(msgId);
if (!res.data.status) {
console.log('generate_msg_from');
socket.emit('generate_msg_from', { prompt: msg, id: msgId });
}
else {

View File

@ -932,7 +932,6 @@
<!-- SEARCH BAR -->
<div class="mx-2 mb-4">
<form>
<div class="relative">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
@ -973,7 +972,6 @@
<!-- @input="filterPersonalities()" -->
</div>
</form>
</div>
<div v-if="searchModel">
@ -1250,8 +1248,6 @@
<div :class="{ 'hidden': pzc_collapsed }" class="flex flex-col mb-2 px-3 pb-0">
<!-- SEARCH BAR -->
<div class="mx-2 mb-4">
<form>
<label for="personality-search"
class="mb-2 text-sm font-medium text-gray-900 sr-only dark:text-white">Search</label>
<div class="relative">
@ -1293,7 +1289,6 @@
<!-- @input="filterPersonalities()" -->
</div>
</form>
</div>
<div class="mx-2 mb-4" v-if="!searchPersonality">
@ -3010,6 +3005,7 @@ export default {
event.target.src = defaultPersonalityImgPlaceholder
},
searchPersonality_func() {
clearTimeout(this.searchPersonalityTimer)
if (this.searchPersonality) {
this.searchPersonalityInProgress = true
@ -3030,6 +3026,7 @@ export default {
console.log("Getting voices")
this.getVoices();
},
activated() {
if (this.isMounted) {
this.constructor()