Merge branch 'main' into dev

This commit is contained in:
AndzejsP 2023-07-01 14:59:14 +03:00
commit 8f90bb5038
5 changed files with 84 additions and 217 deletions

View File

@ -28,6 +28,7 @@ import traceback
import sys
from lollms.console import MainMenu
import urllib
import traceback
__author__ = "parisneo"
__github__ = "https://github.com/ParisNeo/lollms-webui"
@ -444,6 +445,19 @@ class LoLLMsAPPI():
ASCIIColors.green(f"{self.lollms_paths.personal_path}")
@socketio.on('continue_generate_msg_from')
def handle_connection(data):
message_id = int(data['id'])
message = data["prompt"]
self.current_user_message_id = message_id
tpe = threading.Thread(target=self.start_message_generation, args=(message, message_id))
tpe.start()
# generation status
self.generating=False
ASCIIColors.blue(f"Your personal data is stored here :",end="")
ASCIIColors.green(f"{self.lollms_paths.personal_path}")
def rebuild_personalities(self):
loaded = self.mounted_personalities
loaded_names = [f"{p.language}/{p.category}/{p.personality_folder_name}" for p in loaded]
@ -645,7 +659,7 @@ class LoLLMsAPPI():
self.condition_chatbot()
return timestamp
def prepare_query(self, message_id=-1):
def prepare_query(self, message_id=-1, is_continue=False):
messages = self.current_discussion.get_messages()
self.full_message_list = []
for message in messages:
@ -658,17 +672,20 @@ class LoLLMsAPPI():
else:
break
if self.personality.processor is not None:
preprocessed_prompt = self.personality.processor.process_model_input(message["content"])
else:
preprocessed_prompt = message["content"]
if preprocessed_prompt is not None:
self.full_message_list.append(self.personality.user_message_prefix+preprocessed_prompt+self.personality.link_text+self.personality.ai_message_prefix)
else:
self.full_message_list.append(self.personality.user_message_prefix+message["content"]+self.personality.link_text+self.personality.ai_message_prefix)
link_text = self.personality.link_text
if not is_continue:
if self.personality.processor is not None:
preprocessed_prompt = self.personality.processor.process_model_input(message["content"])
else:
preprocessed_prompt = message["content"]
if preprocessed_prompt is not None:
self.full_message_list.append(self.personality.user_message_prefix+preprocessed_prompt+self.personality.link_text+self.personality.ai_message_prefix)
else:
self.full_message_list.append(self.personality.user_message_prefix+message["content"]+self.personality.link_text+self.personality.ai_message_prefix)
else:
self.full_message_list.append(self.personality.ai_message_prefix+message["content"])
discussion_messages = self.personality.personality_conditioning+ link_text.join(self.full_message_list)
@ -719,6 +736,8 @@ class LoLLMsAPPI():
1 : a notification message
2 : A hidden message
"""
if message_type == MSG_TYPE.MSG_TYPE_STEP:
ASCIIColors.info("--> Step:"+chunk)
if message_type == MSG_TYPE.MSG_TYPE_STEP_START:
ASCIIColors.info("--> Step started:"+chunk)
if message_type == MSG_TYPE.MSG_TYPE_STEP_END:
@ -797,7 +816,12 @@ class LoLLMsAPPI():
output = self.personality.processor.run_workflow( prompt, full_prompt, self.process_chunk)
self.process_chunk(output, MSG_TYPE.MSG_TYPE_FULL)
except Exception as ex:
# Catch the exception and get the traceback as a list of strings
traceback_lines = traceback.format_exception(type(ex), ex, ex.__traceback__)
# Join the traceback lines into a single string
traceback_text = ''.join(traceback_lines)
ASCIIColors.error(f"Workflow run failed.\nError:{ex}")
ASCIIColors.error(traceback_text)
self.process_chunk(f"Workflow run failed\nError:{ex}", MSG_TYPE.MSG_TYPE_EXCEPTION)
print("Finished executing the workflow")
return
@ -843,41 +867,44 @@ class LoLLMsAPPI():
output = ""
return output
def start_message_generation(self, message, message_id):
def start_message_generation(self, message, message_id, is_continue=False):
ASCIIColors.info(f"Text generation requested by client: {self.current_room_id}")
# send the message to the bot
print(f"Received message : {message}")
if self.current_discussion:
# First we need to send the new message ID to the client
self.current_ai_message_id = self.current_discussion.add_message(
self.personality.name,
"",
parent = self.current_user_message_id,
binding = self.config["binding_name"],
model = self.config["model_name"],
personality = self.config["personalities"][self.config["active_personality_id"]]
) # first the content is empty, but we'll fill it at the end
self.socketio.emit('infos',
{
"status":'generation_started',
"type": "input_message_infos",
"bot": self.personality.name,
"user": self.personality.user_name,
"message":message,#markdown.markdown(message),
"user_message_id": self.current_user_message_id,
"ai_message_id": self.current_ai_message_id,
if is_continue:
self.current_ai_message_id = message_id
else:
self.current_ai_message_id = self.current_discussion.add_message(
self.personality.name,
"",
parent = self.current_user_message_id,
binding = self.config["binding_name"],
model = self.config["model_name"],
personality = self.config["personalities"][self.config["active_personality_id"]]
) # first the content is empty, but we'll fill it at the end
self.socketio.emit('infos',
{
"status":'generation_started',
"type": "input_message_infos",
"bot": self.personality.name,
"user": self.personality.user_name,
"message":message,#markdown.markdown(message),
"user_message_id": self.current_user_message_id,
"ai_message_id": self.current_ai_message_id,
'binding': self.current_discussion.current_message_binding,
'model': self.current_discussion.current_message_model,
'personality': self.current_discussion.current_message_personality,
'created_at': self.current_discussion.current_message_created_at,
'finished_generating_at': self.current_discussion.current_message_finished_generating_at,
}, room=self.current_room_id
'binding': self.current_discussion.current_message_binding,
'model': self.current_discussion.current_message_model,
'personality': self.current_discussion.current_message_personality,
'created_at': self.current_discussion.current_message_created_at,
'finished_generating_at': self.current_discussion.current_message_finished_generating_at,
}, room=self.current_room_id
)
self.socketio.sleep(0)
# prepare query and reception
self.discussion_messages, self.current_message = self.prepare_query(message_id)
self.discussion_messages, self.current_message = self.prepare_query(message_id, is_continue)
self.prepare_reception()
self.generating = True
self.generate(self.discussion_messages, self.current_message, n_predict = self.config['n_predict'], callback=self.process_chunk)
@ -913,14 +940,21 @@ class LoLLMsAPPI():
)
self.socketio.sleep(0)
print()
print("## Done ##")
print()
ASCIIColors.success(f" ╔══════════════════════════════════════════════════╗ ")
ASCIIColors.success(f" ║ Done ║ ")
ASCIIColors.success(f" ╚══════════════════════════════════════════════════╝ ")
else:
#No discussion available
print("No discussion selected!!!")
print("## Done ##")
print()
self.cancel_gen = False
#No discussion available
ASCIIColors.warning("No discussion selected!!!")
self.socketio.emit('message', {
'data': "No discussion selected!!!",
'user_message_id':self.current_user_message_id,
'ai_message_id':self.current_ai_message_id,
'discussion_id':0,
'message_type': MSG_TYPE.MSG_TYPE_EXCEPTION.value
}, room=self.current_room_id
)
print()
return ""

View File

@ -1,88 +0,0 @@
######
# Project : lollms-webui
# File : binding.py
# Author : ParisNeo with the help of the community
# Supported by Nomic-AI
# license : Apache 2.0
# Description :
# This is an interface class for lollms-webui bindings.
######
from pathlib import Path
from typing import Callable
import inspect
import yaml
import sys
__author__ = "parisneo"
__github__ = "https://github.com/ParisNeo/lollms-webui"
__copyright__ = "Copyright 2023, "
__license__ = "Apache 2.0"
class LLMBinding:
file_extension='*.bin'
binding_path = Path(__file__).parent
def __init__(self, config:dict, inline:bool) -> None:
self.config = config
self.inline = inline
def generate(self,
prompt:str,
n_predict: int = 128,
new_text_callback: Callable[[str], None] = None,
verbose: bool = False,
**gpt_params ):
"""Generates text out of a prompt
This should ber implemented by child class
Args:
prompt (str): The prompt to use for generation
n_predict (int, optional): Number of tokens to prodict. Defaults to 128.
new_text_callback (Callable[[str], None], optional): A callback function that is called everytime a new text element is generated. Defaults to None.
verbose (bool, optional): If true, the code will spit many informations about the generation process. Defaults to False.
"""
pass
def tokenize(self, prompt):
"""
Tokenizes the given prompt using the model's tokenizer.
Args:
prompt (str): The input prompt to be tokenized.
Returns:
list: A list of tokens representing the tokenized prompt.
"""
pass
def detokenize(self, tokens_list):
"""
Detokenizes the given list of tokens using the model's tokenizer.
Args:
tokens_list (list): A list of tokens to be detokenized.
Returns:
str: The detokenized text as a string.
"""
pass
@staticmethod
def list_models(config:dict):
"""Lists the models for this binding
"""
models_dir = Path('./models')/config["binding_name"] # replace with the actual path to the models folder
return [f.name for f in models_dir.glob(LLMBinding.file_extension)]
@staticmethod
def get_available_models():
# Create the file path relative to the child class's directory
binding_path = Path(__file__).parent
file_path = binding_path/"models.yaml"
with open(file_path, 'r') as file:
yaml_data = yaml.safe_load(file)
return yaml_data

View File

@ -1,84 +0,0 @@
try:
from langchain.llms.base import LLM
except ImportError:
raise ImportError(
'To use the ctransformers.langchain module, please install the '
'`langchain` python package: `pip install langchain`')
from typing import Any, Dict, Optional, Sequence
from pydantic import root_validator
from langchain.callbacks.manager import CallbackManagerForLLMRun
from api.binding import LLMBinding
class GenericBinding(LLM):
"""Wrapper around All compatible LLM interfaces.
Thanks to Marella for providing the base for this work.
To follow him, here is his github profile:
To use, you should have the `langchain` python package installed.
"""
client: Any #: :meta private:
model: str
"""The path to a model file or directory or the name of a Hugging Face Hub
model repo."""
model_type: Optional[str] = None
"""The model type."""
model_file: Optional[str] = None
"""The name of the model file in repo or directory."""
config: Optional[Dict[str, Any]] = None
"""The config parameters."""
lib: Optional[Any] = None
"""The path to a shared library or one of `avx2`, `avx`, `basic`."""
@property
def _identifying_params(self) -> Dict[str, Any]:
"""Get the identifying parameters."""
return {
'model': self.model,
'model_type': self.model_type,
'model_file': self.model_file,
'config': self.config,
}
@property
def _llm_type(self) -> str:
"""Return type of llm."""
return 'generic_binding'
@root_validator()
def validate_environment(cls, values: Dict) -> Dict:
"""Validate and load model from a local file or remote repo."""
config = values['config'] or {}
values['client'] = LLMBinding(config, True)
return values
def _call(
self,
prompt: str,
stop: Optional[Sequence[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
) -> str:
"""Generate text from a prompt.
Args:
prompt: The prompt to generate text from.
stop: A list of sequences to stop generation when encountered.
Returns:
The generated text.
"""
text = []
for chunk in self.client(prompt, stop=stop, stream=True):
text.append(chunk)
if run_manager:
run_manager.on_llm_new_token(chunk, verbose=self.verbose)
return ''.join(text)

8
app.py
View File

@ -507,7 +507,13 @@ class LoLLMsWebUI(LoLLMsAPPI):
try:
self.model = self.binding.build_model()
except Exception as ex:
print(f"Couldn't load model: [{ex}]")
# Catch the exception and get the traceback as a list of strings
traceback_lines = traceback.format_exception(type(ex), ex, ex.__traceback__)
# Join the traceback lines into a single string
traceback_text = ''.join(traceback_lines)
ASCIIColors.error(f"Couldn't load model: [{ex}]")
ASCIIColors.error(traceback_text)
return jsonify({ "status":False, 'error':str(ex)})
print("update_settings : New model selected")

View File

@ -15,7 +15,6 @@ import 'highlight.js/styles/tokyo-night-dark.css';
import hljs from 'highlight.js/lib/common';
import 'highlight.js/styles/tomorrow-night-blue.css';
import 'highlight.js/styles/tokyo-night-dark.css';
import attrs from 'markdown-it-attrs';