From 9298e9dcb60dd5ee5e6ec8228434e445029051cf Mon Sep 17 00:00:00 2001 From: saloui Date: Mon, 19 Jun 2023 16:51:41 +0200 Subject: [PATCH] upgraded --- examples/document_questions/docs.txt | 1 + .../document_questions/document_questions.py | 163 +++++++++++++++ examples/document_questions/questions.txt | 1 + lollms/server.py | 187 +++++++++--------- setup.py | 2 +- 5 files changed, 262 insertions(+), 92 deletions(-) create mode 100644 examples/document_questions/docs.txt create mode 100644 examples/document_questions/document_questions.py create mode 100644 examples/document_questions/questions.txt diff --git a/examples/document_questions/docs.txt b/examples/document_questions/docs.txt new file mode 100644 index 0000000..3fb70d1 --- /dev/null +++ b/examples/document_questions/docs.txt @@ -0,0 +1 @@ +C:\Users\sa226037\Downloads\CHLOE-Application-Form-Letter-of-Interest.pdf \ No newline at end of file diff --git a/examples/document_questions/document_questions.py b/examples/document_questions/document_questions.py new file mode 100644 index 0000000..e696b2f --- /dev/null +++ b/examples/document_questions/document_questions.py @@ -0,0 +1,163 @@ +import argparse +import socketio +from pathlib import Path +from lollms import MSG_TYPE +from lollms.helpers import ASCIIColors +import time +import json +from pathlib import Path +import PyPDF2 +from docx import Document +from bs4 import BeautifulSoup +import json +import csv +from pptx import Presentation + +# Connect to the Socket.IO server +sio = socketio.Client() + + + +def read_pdf_file(file_path): + with open(file_path, 'rb') as file: + pdf_reader = PyPDF2.PdfReader(file) + text = "" + for page in pdf_reader.pages: + text += page.extract_text() + return text + + +def read_docx_file(file_path): + doc = Document(file_path) + text = "" + for paragraph in doc.paragraphs: + text += paragraph.text + "\n" + return text + + +def read_json_file(file_path): + with open(file_path, 'r') as file: + data = json.load(file) + return data + + +def read_csv_file(file_path): + with open(file_path, 'r') as file: + csv_reader = csv.reader(file) + lines = [row for row in csv_reader] + return lines + + +def read_html_file(file_path): + with open(file_path, 'r') as file: + soup = BeautifulSoup(file, 'html.parser') + text = soup.get_text() + return text + +def read_pptx_file(file_path): + prs = Presentation(file_path) + text = "" + for slide in prs.slides: + for shape in slide.shapes: + if shape.has_text_frame: + for paragraph in shape.text_frame.paragraphs: + for run in paragraph.runs: + text += run.text + return text + +def read_text_file(file_path): + with open(file_path, 'r', encoding='utf-8') as file: + content = file.read() + return content + +def chunk(input_text, word_count): + # Check for empty text case (word count = 0) + if not input_text or word_count == 0: + return [] + + # Split the string into words using .split() method. Remove leading and trailing whitespace characters from each word by replacing them with an empty strinng "" + cleaned_words = [word.strip(' ') for word in input_text.lower().split()] + + return [' '.join(cleaned_words[i:i+word_count]) for i in range(0,len(cleaned_words),word_count)] + +# Event handler for receiving generated text +@sio.event +def text_generated(data): + print('Generated text:', data) + +def test_generate_text(host, port): + docs=Path(__file__).parent/"docs.txt" + questions_path = Path(__file__).parent/"questions.txt" + outputs=Path(__file__).parent/"outputs.txt" + files = [] + # Read the text file and split by multiple newlines + print("Loading files") + with open(docs, 'r') as file: + file = file.read().split('\n') + files.append(Path(file[0])) + + for file in files: + infos={ + "is_ready":False, + "answer":"" + } + if file.suffix.lower()==".pdf": + txt = read_pdf_file(file) + + file_chunks = chunk(txt,512) + # Event handler for successful connection + @sio.event + def connect(): + print('Connected to Socket.IO server') + questions = [] + with open(questions_path, 'r') as file: + questions = file.read().split('\n') + + for question in questions: + print(f"Question:{question}") + useful_chunks=[] + for chunk in file_chunks: + prompt="Document:\n"+chunk+"\n"+question + # Trigger the 'generate_text' event with the prompt + infos["is_ready"]=False + print(f"Sending prompt:{prompt}") + sio.emit('generate_text', {'prompt': prompt, 'personality':-1, "n_predicts":1024}) + while infos["is_ready"]==False: + time.sleep(0.1) + if(infos["answer"].lower()=="yes"): + ASCIIColors.info("Found useful chunk") + useful_chunks.append(chunk) + with open(outputs, 'w') as file: + file.writelines([question,"Useful chunks"]) + for i in range(len(useful_chunks)): + file.writelines([useful_chunks[i]]) + + + @sio.event + def text_chunk(data): + print(data["chunk"],end="",flush=True) + + @sio.event + def text_generated(data): + print("text_generated_ok") + print(data["text"]) + infos["answer"]=data["text"] + infos["is_ready"]=True + + print(f"Connecting to http://{host}:{port}") + # Connect to the Socket.IO server + sio.connect(f'http://{host}:{port}') + + # Start the event loop + sio.wait() + +if __name__ == '__main__': + # Parse command-line arguments + parser = argparse.ArgumentParser(description='Socket.IO endpoint test') + parser.add_argument('--host', type=str, default='localhost', help='Socket.IO server host') + parser.add_argument('--port', type=int, default=9601, help='Socket.IO server port') + parser.add_argument('--text-file', type=str, default=str(Path(__file__).parent/"example_text_gen.txt"),help='Path to the text file') + args = parser.parse_args() + + # Run the test with provided arguments + test_generate_text(args.host, args.port) diff --git a/examples/document_questions/questions.txt b/examples/document_questions/questions.txt new file mode 100644 index 0000000..43cbeae --- /dev/null +++ b/examples/document_questions/questions.txt @@ -0,0 +1 @@ +Does this document provide information about the buisinessplan (Yes/No): \ No newline at end of file diff --git a/lollms/server.py b/lollms/server.py index 699e8b8..b6da78e 100644 --- a/lollms/server.py +++ b/lollms/server.py @@ -21,22 +21,102 @@ from threading import Thread class LoLLMsServer: def __init__(self): - self.app = Flask("LoLLMsServer_Server") - #self.app.config['SECRET_KEY'] = 'lollmssecret' - CORS(self.app) # Enable CORS for all routes - self.socketio = SocketIO(self.app, cors_allowed_origins='*') + host = "localhost" + port = "9601" self.clients = {} self.current_binding = None self.current_model = None self.personalities = [] self.answer = [''] self.is_ready = True - - - - + + self.lollms_paths = LollmsPaths.find_paths(force_local=False) self.menu = MainMenu(self) + parser = argparse.ArgumentParser() + parser.add_argument('--host', '-hst', default=host, help='Host name') + parser.add_argument('--port', '-prt', default=port, help='Port number') + + parser.add_argument('--config', '-cfg', default=None, help='Path to the configuration file') + parser.add_argument('--bindings_path', '-bp', default=str(self.lollms_paths.bindings_zoo_path), + help='The path to the Bindings folder') + parser.add_argument('--personalities_path', '-pp', + default=str(self.lollms_paths.personalities_zoo_path), + help='The path to the personalities folder') + parser.add_argument('--models_path', '-mp', default=str(self.lollms_paths.personal_models_path), + help='The path to the models folder') + + parser.add_argument('--binding_name', '-b', default="llama_cpp_official", + help='Binding to be used by default') + parser.add_argument('--model_name', '-m', default=None, + help='Model name') + parser.add_argument('--personality_full_name', '-p', default="personality", + help='Personality path relative to the personalities folder (language/category/name)') + + parser.add_argument('--reset_personal_path', action='store_true', help='Reset the personal path') + parser.add_argument('--reset_config', action='store_true', help='Reset the configurations') + parser.add_argument('--reset_installs', action='store_true', help='Reset all installation status') + + + args = parser.parse_args() + + if args.reset_installs: + reset_all_installs() + + if args.reset_personal_path: + LollmsPaths.reset_configs() + + if args.reset_config: + cfg_path = LollmsPaths.find_paths().personal_configuration_path / "local_config.yaml" + try: + cfg_path.unlink() + ASCIIColors.success("LOLLMS configuration reset successfully") + except: + ASCIIColors.success("Couldn't reset LOLLMS configuration") + + # Configuration loading part + self.config = LOLLMSConfig.autoload(self.lollms_paths, args.config) + + + if args.binding_name: + self.config.binding_name = args.binding_name + + if args.model_name: + self.config.model_name = args.model_name + + # Recover bindings path + self.personalities_path = Path(args.personalities_path) + self.bindings_path = Path(args.bindings_path) + self.models_path = Path(args.models_path) + if self.config.binding_name is None: + self.menu.select_binding() + else: + self.binding_class = self.build_binding(self.bindings_path, self.config) + if self.config.model_name is None: + self.menu.select_model() + else: + try: + self.current_model = self.binding_class(self.config) + except Exception as ex: + print(f"{ASCIIColors.color_red}Couldn't load model Please select a valid model{ASCIIColors.color_reset}") + print(f"{ASCIIColors.color_red}{ex}{ASCIIColors.color_reset}") + self.menu.select_model() + + for p in self.config.personalities: + personality = AIPersonality(self.lollms_paths, self.config.lollms_paths.personalities_zoo_path/p, self.current_model) + self.personalities.append(personality) + + if self.config.active_personality_id>len(self.personalities): + self.config.active_personality_id = 0 + self.active_personality = self.personalities[self.config.active_personality_id] + + self.menu.show_logo() + + self.app = Flask("LoLLMsServer_Server") + #self.app.config['SECRET_KEY'] = 'lollmssecret' + CORS(self.app) # Enable CORS for all routes + + self.socketio = SocketIO(self.app, cors_allowed_origins='*', ping_timeout=1200, ping_interval=4000) # Set log level to warning self.app.logger.setLevel(logging.WARNING) @@ -333,11 +413,14 @@ class LoLLMsServer: @self.socketio.on('generate_text') def handle_generate_text(data): client_id = request.sid + ASCIIColors.info(f"Text generation requested by client: {client_id}") if not self.is_ready: emit("buzzy", {"message":"I am buzzy. Come back later."}) self.socketio.sleep(0) + ASCIIColors.warning(f"OOps request {client_id} refused!! Server buzy") return def generate_text(): + self.is_ready = False model = self.current_model self.clients[client_id]["is_generating"]=True self.clients[client_id]["requested_stop"]=False @@ -346,7 +429,6 @@ class LoLLMsServer: n_predicts = data["n_predicts"] if personality_id==-1: # Raw text generation - print(f"Text generation requested by client: {client_id}") self.answer = {"full_text":""} def callback(text, message_type: MSG_TYPE): if message_type == MSG_TYPE.MSG_TYPE_CHUNK: @@ -374,7 +456,7 @@ class LoLLMsServer: # Emit the generated text to the client self.socketio.emit('text_generated', {'text': generated_text}, room=client_id) self.socketio.sleep(0) - + self.is_ready = True else: personality: AIPersonality = self.personalities[personality_id] personality.model = model @@ -439,8 +521,9 @@ class LoLLMsServer: # Emit the generated text to the client self.socketio.emit('text_generated', {'text': generated_text}, room=client_id) self.socketio.sleep(0) + self.is_ready = True # Start the text generation task in a separate thread - self.socketio.start_background_task(target=generate_text,) + self.socketio.start_background_task(target=generate_text, once=True) generate_text() def build_binding(self, bindings_path: Path, cfg: LOLLMSConfig)->LLMBinding: @@ -467,88 +550,10 @@ class LoLLMsServer: def run(self, host="localhost", port="9601"): - parser = argparse.ArgumentParser() - parser.add_argument('--host', '-hst', default=host, help='Host name') - parser.add_argument('--port', '-prt', default=port, help='Port number') - - parser.add_argument('--config', '-cfg', default=None, help='Path to the configuration file') - parser.add_argument('--bindings_path', '-bp', default=str(self.lollms_paths.bindings_zoo_path), - help='The path to the Bindings folder') - parser.add_argument('--personalities_path', '-pp', - default=str(self.lollms_paths.personalities_zoo_path), - help='The path to the personalities folder') - parser.add_argument('--models_path', '-mp', default=str(self.lollms_paths.personal_models_path), - help='The path to the models folder') - - parser.add_argument('--binding_name', '-b', default="llama_cpp_official", - help='Binding to be used by default') - parser.add_argument('--model_name', '-m', default=None, - help='Model name') - parser.add_argument('--personality_full_name', '-p', default="personality", - help='Personality path relative to the personalities folder (language/category/name)') - - parser.add_argument('--reset_personal_path', action='store_true', help='Reset the personal path') - parser.add_argument('--reset_config', action='store_true', help='Reset the configurations') - parser.add_argument('--reset_installs', action='store_true', help='Reset all installation status') - - - args = parser.parse_args() - - if args.reset_installs: - reset_all_installs() - - if args.reset_personal_path: - LollmsPaths.reset_configs() - - if args.reset_config: - cfg_path = LollmsPaths.find_paths().personal_configuration_path / "local_config.yaml" - try: - cfg_path.unlink() - ASCIIColors.success("LOLLMS configuration reset successfully") - except: - ASCIIColors.success("Couldn't reset LOLLMS configuration") - - # Configuration loading part - self.config = LOLLMSConfig.autoload(self.lollms_paths, args.config) - - - if args.binding_name: - self.config.binding_name = args.binding_name - - if args.model_name: - self.config.model_name = args.model_name - - # Recover bindings path - self.personalities_path = Path(args.personalities_path) - self.bindings_path = Path(args.bindings_path) - self.models_path = Path(args.models_path) - if self.config.binding_name is None: - self.menu.select_binding() - else: - self.binding_class = self.build_binding(self.bindings_path, self.config) - if self.config.model_name is None: - self.menu.select_model() - else: - try: - self.current_model = self.binding_class(self.config) - except Exception as ex: - print(f"{ASCIIColors.color_red}Couldn't load model Please select a valid model{ASCIIColors.color_reset}") - print(f"{ASCIIColors.color_red}{ex}{ASCIIColors.color_reset}") - self.menu.select_model() - - for p in self.config.personalities: - personality = AIPersonality(self.lollms_paths, self.config.lollms_paths.personalities_zoo_path/p, self.current_model) - self.personalities.append(personality) - - if self.config.active_personality_id>len(self.personalities): - self.config.active_personality_id = 0 - self.active_personality = self.personalities[self.config.active_personality_id] - - self.menu.show_logo() print(f"{ASCIIColors.color_red}Current personality : {ASCIIColors.color_reset}{self.active_personality}") - ASCIIColors.info(f"Serving on address: http://{args.host}:{args.port}") + ASCIIColors.info(f"Serving on address: http://{host}:{port}") - self.socketio.run(self.app, host=args.host, port=args.port) + self.socketio.run(self.app, host=host, port=port) def main(): LoLLMsServer() diff --git a/setup.py b/setup.py index 3c9552a..412deba 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ def get_all_files(path): setuptools.setup( name="lollms", - version="1.2.8", + version="1.2.9", author="Saifeddine ALOUI", author_email="aloui.saifeddine@gmail.com", description="A python library for AI personality definition",