mirror of
https://github.com/ParisNeo/lollms-webui.git
synced 2025-01-29 15:44:12 +00:00
Upgraded to V7.0
This commit is contained in:
parent
5f67de4868
commit
70a65f84f2
8
CHANGELOG.md
Normal file
8
CHANGELOG.md
Normal file
@ -0,0 +1,8 @@
|
||||
# V 7.0:
|
||||
Added changelog
|
||||
Separated images from text in file upload
|
||||
Added support for multimodal models
|
||||
Added Dalle and gpt4 vision
|
||||
enhanced interface
|
||||
Upgraded the code execution
|
||||
Now it is possible to execute lollms multiple times on the same PC. You can now have multiple instances with different port numbers and so a work in parallel.
|
@ -726,6 +726,7 @@ class LoLLMsAPPI(LollmsApplication):
|
||||
|
||||
try:
|
||||
ASCIIColors.print("warming up", ASCIIColors.color_bright_cyan)
|
||||
|
||||
generated_text = model.generate(fd,
|
||||
n_predict=n_predicts,
|
||||
callback=callback,
|
||||
@ -1192,7 +1193,8 @@ class LoLLMsAPPI(LollmsApplication):
|
||||
chunk:str,
|
||||
message_type:MSG_TYPE
|
||||
):
|
||||
title[0] += chunk
|
||||
if chunk:
|
||||
title[0] += chunk
|
||||
antiprompt = self.personality.detect_antiprompt(title[0])
|
||||
if antiprompt:
|
||||
ASCIIColors.warning(f"\nDetected hallucination with antiprompt: {antiprompt}")
|
||||
@ -1239,7 +1241,7 @@ class LoLLMsAPPI(LollmsApplication):
|
||||
|
||||
# Check if there are document files to add to the prompt
|
||||
documentation = ""
|
||||
if len(self.personality.files) > 0 and self.personality.vectorizer:
|
||||
if len(self.personality.text_files) > 0 and self.personality.vectorizer:
|
||||
if documentation=="":
|
||||
documentation="Documentation:\n"
|
||||
docs, sorted_similarities = self.personality.vectorizer.recover_text(current_message.content, top_k=self.config.data_vectorization_nb_chunks)
|
||||
@ -1344,11 +1346,9 @@ class LoLLMsAPPI(LollmsApplication):
|
||||
ASCIIColors.yellow(history)
|
||||
ASCIIColors.bold("DISCUSSION")
|
||||
# TODO: upghrade to asciicolors 0.1.4
|
||||
# ASCIIColors.hilight(discussion_messages,"!@>",ASCIIColors.color_yellow,ASCIIColors.color_bright_red,False)
|
||||
ASCIIColors.yellow(discussion_messages)
|
||||
ASCIIColors.hilight(discussion_messages,"!@>",ASCIIColors.color_yellow,ASCIIColors.color_bright_red,False)
|
||||
ASCIIColors.bold("Final prompt")
|
||||
#ASCIIColors.hilight(prompt_data,"!@>",ASCIIColors.color_yellow,ASCIIColors.color_bright_red,False)
|
||||
ASCIIColors.yellow(prompt_data)
|
||||
ASCIIColors.hilight(prompt_data,"!@>",ASCIIColors.color_yellow,ASCIIColors.color_bright_red,False)
|
||||
ASCIIColors.info(f"prompt size:{len(tokens)} tokens")
|
||||
ASCIIColors.info(f"available space after doc and history:{available_space} tokens")
|
||||
|
||||
@ -1356,81 +1356,6 @@ class LoLLMsAPPI(LollmsApplication):
|
||||
return prompt_data, current_message.content, tokens
|
||||
|
||||
|
||||
"""
|
||||
def prepare_query(self, client_id, message_id=-1, is_continue=False):
|
||||
messages = self.connections[client_id]["current_discussion"].get_messages()
|
||||
full_message_list = []
|
||||
for i, message in enumerate(messages):
|
||||
if message.id< message_id or (message_id==-1 and i<len(messages)-1):
|
||||
if message.content!='' and (message.message_type<=MSG_TYPE.MSG_TYPE_FULL_INVISIBLE_TO_USER.value and message.message_type!=MSG_TYPE.MSG_TYPE_FULL_INVISIBLE_TO_AI.value):
|
||||
full_message_list.append("\n"+self.config.discussion_prompt_separator+message.sender+": "+message.content.strip())
|
||||
else:
|
||||
break
|
||||
|
||||
link_text = "\n" #self.personality.link_text
|
||||
if not is_continue:
|
||||
full_message_list.append(self.config.discussion_prompt_separator +message.sender.strip().replace(":","")+": "+message.content.strip()+link_text+self.personality.ai_message_prefix.strip())
|
||||
else:
|
||||
full_message_list.append(self.config.discussion_prompt_separator +message.sender.strip().replace(":","")+": "+message.content.strip())
|
||||
|
||||
|
||||
composed_messages = link_text.join(full_message_list)
|
||||
t = self.model.tokenize(composed_messages)
|
||||
cond_tk = self.model.tokenize(self.personality.personality_conditioning)
|
||||
n_t = len(t)
|
||||
n_cond_tk = len(cond_tk)
|
||||
max_prompt_stx_size = 3*int(self.config.ctx_size/4)
|
||||
if n_cond_tk+n_t>max_prompt_stx_size:
|
||||
nb_tk = max_prompt_stx_size-n_cond_tk
|
||||
composed_messages = self.model.detokenize(t[-nb_tk:])
|
||||
ASCIIColors.warning(f"Cropping discussion to fit context [using {nb_tk} tokens/{self.config.ctx_size}]")
|
||||
discussion_messages = composed_messages
|
||||
|
||||
|
||||
conditionning = self.personality.personality_conditioning
|
||||
if self.config["override_personality_model_parameters"]:
|
||||
conditionning = conditionning+ "\n!@>user description:\nName:"+self.config["user_name"]+"\n"+self.config["user_description"]+"\n"
|
||||
|
||||
str_docs = ""
|
||||
|
||||
if self.config.use_discussions_history:
|
||||
if self.discussions_store is not None:
|
||||
pr = PromptReshaper("{{conditionning}}\n!@>document chunks:\n{{doc}}\n{{content}}")
|
||||
docs, sorted_similarities = self.discussions_store.recover_text(message.content, top_k=self.config.data_vectorization_nb_chunks)
|
||||
for doc, infos in zip(docs, sorted_similarities):
|
||||
str_docs+=f"discussion chunk:\ndiscussion title: {infos[0]}\nchunk content:{doc}"
|
||||
|
||||
|
||||
if len(self.personality.files)>0 and self.personality.vectorizer:
|
||||
docs, sorted_similarities = self.personality.vectorizer.recover_text(message.content, top_k=self.config.data_vectorization_nb_chunks)
|
||||
for doc, infos in zip(docs, sorted_similarities):
|
||||
str_docs+=f"document chunk:\nchunk path: {infos[0]}\nchunk content:{doc}"
|
||||
|
||||
if str_docs!="":
|
||||
pr = PromptReshaper("{{conditionning}}\n!@>document chunks:\n{{doc}}\n{{content}}")
|
||||
discussion_messages = pr.build({
|
||||
"doc":str_docs,
|
||||
"conditionning":conditionning,
|
||||
"content":discussion_messages
|
||||
}, self.model.tokenize, self.model.detokenize, self.config.ctx_size-self.config.min_n_predict, place_holders_to_sacrifice=["content"])
|
||||
else:
|
||||
pr = PromptReshaper("{{conditionning}}\n{{content}}")
|
||||
discussion_messages = pr.build({
|
||||
"conditionning":conditionning,
|
||||
"content":discussion_messages
|
||||
}, self.model.tokenize, self.model.detokenize, self.config.ctx_size-self.config.min_n_predict, place_holders_to_sacrifice=["content"])
|
||||
# remove extra returns
|
||||
discussion_messages = self.clean_string(discussion_messages)
|
||||
tokens = self.model.tokenize(discussion_messages)
|
||||
if self.config["debug"]:
|
||||
ASCIIColors.yellow(discussion_messages)
|
||||
ASCIIColors.info(f"prompt size:{len(tokens)} tokens")
|
||||
|
||||
return discussion_messages, message.content, tokens
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def get_discussion_to(self, client_id, message_id=-1):
|
||||
messages = self.connections[client_id]["current_discussion"].get_messages()
|
||||
full_message_list = []
|
||||
@ -1625,7 +1550,7 @@ class LoLLMsAPPI(LollmsApplication):
|
||||
self.close_message(client_id)
|
||||
|
||||
elif message_type == MSG_TYPE.MSG_TYPE_CHUNK:
|
||||
if self.nb_received_tokens:
|
||||
if self.nb_received_tokens==0:
|
||||
self.start_time = datetime.now()
|
||||
dt =(datetime.now() - self.start_time).seconds
|
||||
if dt==0:
|
||||
@ -1634,7 +1559,8 @@ class LoLLMsAPPI(LollmsApplication):
|
||||
ASCIIColors.green(f"Received {self.nb_received_tokens} tokens (speed: {spd:.2f}t/s) ",end="\r",flush=True)
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stdout.flush()
|
||||
self.connections[client_id]["generated_text"] += chunk
|
||||
if chunk:
|
||||
self.connections[client_id]["generated_text"] += chunk
|
||||
antiprompt = self.personality.detect_antiprompt(self.connections[client_id]["generated_text"])
|
||||
if antiprompt:
|
||||
ASCIIColors.warning(f"\nDetected hallucination with antiprompt: {antiprompt}")
|
||||
|
20
api/db.py
20
api/db.py
@ -243,16 +243,16 @@ class DiscussionsDB:
|
||||
discussion = {"id": discussion_id, "title":discussion_title, "messages": []}
|
||||
rows = self.select(f"SELECT sender, content, message_type, rank, parent_message_id, binding, model, personality, created_at, finished_generating_at FROM message WHERE discussion_id=?",(discussion_id,))
|
||||
for message_row in rows:
|
||||
sender = message_row[1]
|
||||
content = message_row[2]
|
||||
content_type = message_row[3]
|
||||
rank = message_row[4]
|
||||
parent_message_id = message_row[5]
|
||||
binding = message_row[6]
|
||||
model = message_row[7]
|
||||
personality = message_row[8]
|
||||
created_at = message_row[9]
|
||||
finished_generating_at = message_row[10]
|
||||
sender = message_row[0]
|
||||
content = message_row[1]
|
||||
content_type = message_row[2]
|
||||
rank = message_row[3]
|
||||
parent_message_id = message_row[4]
|
||||
binding = message_row[5]
|
||||
model = message_row[6]
|
||||
personality = message_row[7]
|
||||
created_at = message_row[8]
|
||||
finished_generating_at = message_row[9]
|
||||
|
||||
discussion["messages"].append(
|
||||
{"sender": sender, "content": content, "message_type": content_type, "rank": rank, "parent_message_id": parent_message_id, "binding": binding, "model":model, "personality":personality, "created_at":created_at, "finished_generating_at":finished_generating_at}
|
||||
|
24
app.py
24
app.py
@ -13,7 +13,7 @@ __github__ = "https://github.com/ParisNeo/lollms-webui"
|
||||
__copyright__ = "Copyright 2023, "
|
||||
__license__ = "Apache 2.0"
|
||||
|
||||
__version__ ="6.8"
|
||||
__version__ ="7.0 (Alpha)"
|
||||
|
||||
main_repo = "https://github.com/ParisNeo/lollms-webui.git"
|
||||
import os
|
||||
@ -144,7 +144,6 @@ try:
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
|
||||
|
||||
def get_ip_address():
|
||||
# Create a socket object
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
@ -194,7 +193,7 @@ try:
|
||||
if config.auto_update:
|
||||
if check_update_():
|
||||
ASCIIColors.info("New version found. Updating!")
|
||||
self.update_software()
|
||||
run_update_script()
|
||||
|
||||
if len(config.personalities)==0:
|
||||
config.personalities.append("generic/lollms")
|
||||
@ -360,6 +359,8 @@ try:
|
||||
self.add_endpoint("/edit_title", "edit_title", self.edit_title, methods=["POST"])
|
||||
self.add_endpoint("/make_title", "make_title", self.make_title, methods=["POST"])
|
||||
|
||||
self.add_endpoint("/get_server_address", "get_server_address", self.get_server_address, methods=["GET"])
|
||||
|
||||
|
||||
self.add_endpoint(
|
||||
"/delete_discussion",
|
||||
@ -481,6 +482,10 @@ try:
|
||||
|
||||
|
||||
|
||||
def get_server_address(self):
|
||||
server_address = request.host_url
|
||||
return server_address
|
||||
|
||||
def execute_python(self, code, discussion_id, message_id):
|
||||
def spawn_process(code):
|
||||
"""Executes Python code and returns the output as JSON."""
|
||||
@ -1716,7 +1721,7 @@ try:
|
||||
def get_current_personality_files_list(self):
|
||||
if self.personality is None:
|
||||
return jsonify({"state":False, "error":"No personality selected"})
|
||||
return jsonify({"state":True, "files":[{"name":Path(f).name, "size":Path(f).stat().st_size} for f in self.personality.files]})
|
||||
return jsonify({"state":True, "files":[{"name":Path(f).name, "size":Path(f).stat().st_size} for f in self.personality.text_files]})
|
||||
|
||||
def clear_personality_files_list(self):
|
||||
if self.personality is None:
|
||||
@ -2540,9 +2545,14 @@ try:
|
||||
# if autoshow
|
||||
if config.auto_show_browser:
|
||||
webbrowser.open(f"http://{config['host']}:{config['port']}")
|
||||
socketio.run(app, host=config["host"], port=config["port"],
|
||||
# prevent error: The Werkzeug web server is not designed to run in production
|
||||
allow_unsafe_werkzeug=True)
|
||||
|
||||
|
||||
try:
|
||||
socketio.run(app, host=config["host"], port=config["port"],
|
||||
# prevent error: The Werkzeug web server is not designed to run in production
|
||||
allow_unsafe_werkzeug=True)
|
||||
except Exception as ex:
|
||||
trace_exception(ex)
|
||||
# http_server = WSGIServer((config["host"], config["port"]), app, handler_class=WebSocketHandler)
|
||||
# http_server.serve_forever()
|
||||
except Exception as ex:
|
||||
|
@ -15,4 +15,4 @@ GitPython
|
||||
setuptools
|
||||
numpy==1.24
|
||||
flask_compress
|
||||
ascii_colors>=0.1.3
|
||||
ascii_colors>=0.1.4
|
||||
|
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>LoLLMS WebUI - Welcome</title>
|
||||
<script type="module" crossorigin src="/assets/index-5d95834b.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-f06a4c0c.css">
|
||||
<script type="module" crossorigin src="/assets/index-6d02e1a1.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-78770f39.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
@ -43,6 +43,11 @@ hljs.configure({ languages: ['bash'] }); // Set bash as the default language
|
||||
hljs.highlightAll();
|
||||
export default {
|
||||
props: {
|
||||
host: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "http://localhost:9600",
|
||||
},
|
||||
language: {
|
||||
type: String,
|
||||
required: true,
|
||||
@ -120,7 +125,7 @@ export default {
|
||||
executeCode() {
|
||||
const json = JSON.stringify({ 'code': this.code, 'discussion_id': this.discussion_id, 'message_id': this.message_id, 'language': this.language})
|
||||
console.log(json)
|
||||
fetch('http://localhost:9600/execute_code', {
|
||||
fetch(`${this.host}/execute_code`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: json
|
||||
@ -141,7 +146,7 @@ export default {
|
||||
openFolder() {
|
||||
const json = JSON.stringify({ 'discussion_id': this.discussion_id })
|
||||
console.log(json)
|
||||
fetch('http://localhost:9600/open_code_folder', {
|
||||
fetch(`${this.host}/open_code_folder`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: json
|
||||
|
@ -4,6 +4,7 @@
|
||||
<div v-for="(item, index) in markdownItems" :key="index">
|
||||
<code-block
|
||||
v-if="item.type === 'code'"
|
||||
:host="host"
|
||||
:language="item.language"
|
||||
:code="item.code"
|
||||
:discussion_id="discussion_id"
|
||||
@ -40,6 +41,11 @@ function escapeHtml(unsafe) {
|
||||
export default {
|
||||
name: 'MarkdownRenderer',
|
||||
props: {
|
||||
host: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "http://localhost:9600",
|
||||
},
|
||||
markdownText: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -144,7 +144,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MarkdownRenderer ref="mdRender" v-if="!editMsgMode" :markdown-text="message.content" :message_id="message.id">
|
||||
<MarkdownRenderer ref="mdRender" v-if="!editMsgMode" :host="host" :markdown-text="message.content" :message_id="message.id">
|
||||
</MarkdownRenderer>
|
||||
<div >
|
||||
<textarea v-if="editMsgMode" ref="mdTextarea" @keydown.tab.prevent="insertTab"
|
||||
@ -224,6 +224,11 @@ export default {
|
||||
DynamicUIRenderer,
|
||||
},
|
||||
props: {
|
||||
host: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "http://localhost:9600",
|
||||
},
|
||||
message: Object,
|
||||
avatar: ''
|
||||
},
|
||||
|
@ -230,8 +230,12 @@
|
||||
<!-- CHAT AREA -->
|
||||
<div class=" container pt-4 pb-10 mb-28">
|
||||
<TransitionGroup v-if="discussionArr.length > 0" name="list">
|
||||
<Message v-for="(msg, index) in discussionArr" :key="msg.id" :message="msg" :id="'msg-' + msg.id"
|
||||
ref="messages" @copy="copyToClipBoard" @delete="deleteMessage" @rankUp="rankUpMessage"
|
||||
<Message v-for="(msg, index) in discussionArr"
|
||||
:key="msg.id" :message="msg" :id="'msg-' + msg.id"
|
||||
:host="host"
|
||||
ref="messages"
|
||||
|
||||
@copy="copyToClipBoard" @delete="deleteMessage" @rankUp="rankUpMessage"
|
||||
@rankDown="rankDownMessage" @updateMessage="updateMessage" @resendMessage="resendMessage" @continueMessage="continueMessage"
|
||||
:avatar="getAvatar(msg.sender)" />
|
||||
|
||||
@ -362,6 +366,7 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
host:"",
|
||||
// To be synced with the backend database types
|
||||
msgTypes: {
|
||||
// Messaging
|
||||
@ -545,8 +550,6 @@ export default {
|
||||
this.loading = false
|
||||
this.setDiscussionLoading(id, this.loading)
|
||||
if (data) {
|
||||
console.log("received discussion")
|
||||
console.log(data)
|
||||
// Filter out the user and bot entries
|
||||
this.discussionArr = data.filter((item) =>
|
||||
item.message_type == this.msgTypes.MSG_TYPE_CHUNK ||
|
||||
@ -1128,7 +1131,6 @@ export default {
|
||||
},
|
||||
streamMessageContent(msgObj) {
|
||||
// Streams response message content from binding
|
||||
console.log("Received message",msgObj)
|
||||
const discussion_id = msgObj.discussion_id
|
||||
this.setDiscussionLoading(discussion_id, true);
|
||||
if (this.currentDiscussion.id == discussion_id) {
|
||||
@ -1724,6 +1726,16 @@ export default {
|
||||
this.isCreated = true
|
||||
},
|
||||
async mounted() {
|
||||
try {
|
||||
const response = await fetch('/get_server_address'); // Replace with the actual endpoint on your Flask server
|
||||
const serverAddress = await response.text();
|
||||
console.log(`Server address: ${serverAddress}`)
|
||||
this.host = `${serverAddress}`; // Construct the full server address dynamically
|
||||
} catch (error) {
|
||||
console.error('Error fetching server address:', error);
|
||||
// Handle error if necessary
|
||||
this.host = process.env.VITE_LOLLMS_API
|
||||
}
|
||||
//console.log('chatbox mnt',this.$refs)
|
||||
this.$nextTick(() => {
|
||||
feather.replace();
|
||||
|
@ -3,8 +3,23 @@ import { fileURLToPath, URL } from 'node:url'
|
||||
import { defineConfig,loadEnv } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default ({ mode }) => {
|
||||
export default async ({ mode }) => {
|
||||
async function getFlaskServerURL() {
|
||||
try {
|
||||
const response = await fetch('/get_server_address'); // Replace with the actual endpoint on your Flask server
|
||||
const serverAddress = await response.text();
|
||||
console.log(`Server address: ${serverAddress}`)
|
||||
return `${serverAddress}`; // Construct the full server address dynamically
|
||||
} catch (error) {
|
||||
// console.error('Error fetching server address:', error);
|
||||
// Handle error if necessary
|
||||
return process.env.VITE_LOLLMS_API
|
||||
}
|
||||
}
|
||||
const serverURL = await getFlaskServerURL()
|
||||
console.log(serverURL)
|
||||
// Load app-level env vars to node-level env vars.
|
||||
process.env = {...process.env, ...loadEnv(mode, process.cwd())};
|
||||
|
||||
@ -21,7 +36,7 @@ export default ({ mode }) => {
|
||||
server: {
|
||||
proxy: {
|
||||
"/api/": {
|
||||
target: process.env.VITE_LOLLMS_API,
|
||||
target: serverURL,//process.env.VITE_LOLLMS_API,//getFlaskServerURL(),// process.env.VITE_LOLLMS_API,
|
||||
changeOrigin: process.env.VITE_LOLLMS_API_CHANGE_ORIGIN,
|
||||
secure: process.env.VITE_LOLLMS_API_SECURE,
|
||||
rewrite: (path) => path.replace(/^\/api/, ""),
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit fdfae6890b123726e6f86fcaa845a6cb5f32dc85
|
||||
Subproject commit dd3ace5dd06cb02b1c13b83aa785266f50ff663c
|
Loading…
x
Reference in New Issue
Block a user