diff --git a/tests/run-tests.py b/tests/run-tests.py index 0277ccd3..263538c8 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -1,66 +1,102 @@ #!/usr/bin/env python import os import pytest -import shutil +import shutil import subprocess import sys from utils import Logger -class RunTests(): - # Grab the folders for the llmware and llmware-packaging repos. They are assumed to live in the same parent folder +class RunTests: + # Initialize and grab the folder paths for the llmware and llmware-packaging repos def __init__(self): tests_folder = os.path.dirname(os.path.realpath(__file__)) - self.repo_root = os.path.join(tests_folder, "..") - - # Ensure the latest/greatest llmware module is installed locally + self.repo_root = os.path.abspath(os.path.join(tests_folder, "..")) + self.logger = Logger() + + # Ensure the latest llmware module is installed locally def update_llmware_install(self): - self.run_command("pip uninstall llmware -y", self.repo_root) - self.run_command("pip install .", self.repo_root) + self.logger.log("Updating llmware installation...") + try: + self.run_command("pip uninstall llmware -y", self.repo_root) + self.run_command("pip install .", self.repo_root) + except Exception as e: + self.logger.log(f"Error updating llmware: {e}", level="error") + sys.exit(1) - # Try to start from as clean an environment as possible + # Clean the environment to start from a fresh state def clean_the_environment(self): - Logger().log("Cleaning the environment...") + self.logger.log("Cleaning the environment...") + + # Remove the default llmware data folders + self.remove_folder(os.path.join(os.environ["HOME"], "llmware_data")) + self.remove_folder(os.path.join(os.environ["HOME"], "llmware_data_custom")) - # Remove the default data folder: $HOME/llmware_data - llmware_data_dir = os.path.join(os.environ["HOME"],"llmware_data") - llmware_data_custom_dir = os.path.join(os.environ["HOME"],"llmware_data_custom") - Logger().log(f"Deleting {llmware_data_dir}") - if os.path.exists(llmware_data_dir): - shutil.rmtree(llmware_data_dir) + # Reset MongoDB + try: + self.logger.log("Resetting MongoDB (dropping the 'llmware' database)...") + from llmware.resources import MongoDBManager + MongoDBManager().client.drop_database("llmware") + except Exception as e: + self.logger.log(f"Error resetting MongoDB: {e}", level="error") + sys.exit(1) - if os.path.exists(llmware_data_custom_dir): - shutil.rmtree(llmware_data_custom_dir) - - # Reset Mongo - Logger().log("Resetting Mongo (deleting the llmware db)") - from llmware.resources import MongoDBManager - MongoDBManager().client.drop_database("llmware") + # Reset Milvus collections + try: + self.logger.log("Resetting Milvus (dropping all collections)...") + from llmware.configs import LLMWareConfig + from pymilvus import connections, utility + connections.connect("default", host=os.environ.get('MILVUS_HOST', 'localhost'), port=19530) + for collection in utility.list_collections(): + utility.drop_collection(collection) + self.logger.log("All Milvus collections dropped successfully.") + except Exception as e: + self.logger.log(f"Error resetting Milvus: {e}", level="error") + sys.exit(1) - # Reset Milvus - Logger().log("Resetting Milvus (deleting all collections)") - from llmware.configs import LLMWareConfig - from pymilvus import connections, utility, FieldSchema, CollectionSchema, DataType, Collection - connections.connect("default", host=os.environ.get('MILVUS_HOST','localhost') , port=19530) - for collection in utility.list_collections(): - utility.drop_collection(collection) + # Helper function to remove a folder if it exists + def remove_folder(self, folder_path): + if os.path.exists(folder_path): + try: + self.logger.log(f"Removing folder: {folder_path}") + shutil.rmtree(folder_path) + except Exception as e: + self.logger.log(f"Error removing folder {folder_path}: {e}", level="error") + else: + self.logger.log(f"Folder not found: {folder_path}") - # Run a system command in the given dir, wait for it to complete and print the output + # Run a system command in the given directory, wait for it to complete, and log the output def run_command(self, command, working_dir): - Logger().log(f"Running command '{command}' in '{working_dir}'...") + self.logger.log(f"Running command '{command}' in '{working_dir}'...") command_array = command.split(" ") - command_output = "" - p = subprocess.Popen(command_array, cwd=working_dir, stdout=subprocess.PIPE) - for line in p.stdout: - output_line = line.decode('utf8') - command_output += output_line - Logger().log(output_line) - p.wait() - Logger().log("") - return command_output + try: + process = subprocess.Popen(command_array, cwd=working_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + if stdout: + self.logger.log(stdout.decode('utf-8')) + if stderr: + self.logger.log(stderr.decode('utf-8'), level="error") + if process.returncode != 0: + raise subprocess.CalledProcessError(process.returncode, command) + except subprocess.CalledProcessError as e: + self.logger.log(f"Command '{command}' failed with error: {e}", level="error") + sys.exit(1) + except Exception as e: + self.logger.log(f"An unexpected error occurred while running '{command}': {e}", level="error") + sys.exit(1) + + +if __name__ == "__main__": + test_runner = RunTests() + + # Update and clean environment before running tests + test_runner.update_llmware_install() + test_runner.clean_the_environment() -test_runner = RunTests() -test_runner.update_llmware_install() -test_runner.clean_the_environment() -pytest.main(sys.argv[1:]) \ No newline at end of file + # Run the tests with pytest + try: + pytest.main(sys.argv[1:]) + except Exception as e: + test_runner.logger.log(f"Error running tests: {e}", level="error") + sys.exit(1) diff --git a/welcome_to_llmware_windows.sh b/welcome_to_llmware_windows.sh index 504ac0f3..5234f99c 100644 --- a/welcome_to_llmware_windows.sh +++ b/welcome_to_llmware_windows.sh @@ -1,66 +1,66 @@ -#! /bin/bash +#!/bin/bash -# Welcome to LLMWare script - handles some basic setup for first-time cloning of the repo +# Welcome to the LLMWare script - handles basic setup for first-time cloning of the repo # Windows version +# Function to handle errors +function error_exit { + echo "Error: $1" + exit 1 +} + # Install core dependencies -pip3 install -r ./llmware/requirements.txt +echo "Installing core dependencies..." +pip3 install -r ./llmware/requirements.txt || error_exit "Failed to install core dependencies." + +# Install optional dependencies (optional step) +echo "Installing optional dependencies..." +pip3 install -r ./llmware/requirements_extras.txt || echo "Optional dependencies installation skipped or failed." -# Note: this step is optional but adds many commonly-used optional dependencies (including in several examples) -pip3 install -r ./llmware/requirements_extras.txt +# Move selected examples into root path for easy execution from the command line +echo "Moving selected examples to the root path..." +declare -a examples=( + "examples/Getting_Started/welcome_example.py" + "fast_start/rag/*.py" + "examples/UI/gguf_streaming_chatbot.py" + "examples/SLIM-Agents/agent-llmfx-getting-started.py" + "examples/SLIM-Agents/using_slim_extract_model.py" + "examples/SLIM-Agents/using_slim_summary.py" + "examples/Models/bling_fast_start.py" + "examples/Models/dragon_gguf_fast_start.py" + "examples/Prompts/document_summarizer.py" + "examples/Use_Cases/web_services_slim_fx.py" + "examples/Use_Cases/invoice_processing.py" + "examples/Models/using-whisper-cpp-sample-files.py" + "examples/Parsing/parsing_microsoft_ir_docs.py" + "examples/Models/chat_models_gguf_fast_start.py" + "examples/Models/gguf_streaming.py" +) -# Move selected examples into root path for easy execution from command line -scp ./examples/Getting_Started/welcome_example.py . -scp ./fast_start/rag/*.py . -scp ./examples/UI/gguf_streaming_chatbot.py . -scp ./examples/SLIM-Agents/agent-llmfx-getting-started.py . -scp ./examples/SLIM-Agents/using_slim_extract_model.py . -scp ./examples/SLIM-Agents/using_slim_summary.py . -scp ./examples/Models/bling_fast_start.py . -scp ./examples/Models/dragon_gguf_fast_start.py . -scp ./examples/Prompts/document_summarizer.py . -scp ./examples/Use_Cases/web_services_slim_fx.py . -scp ./examples/Use_Cases/invoice_processing.py . -scp ./examples/Models/using-whisper-cpp-sample-files.py . -scp ./examples/Parsing/parsing_microsoft_ir_docs.py . -scp ./examples/Models/chat_models_gguf_fast_start.py . -scp ./examples/Models/gguf_streaming.py . +for example in "${examples[@]}"; do + cp "$example" . || error_exit "Failed to copy $example." +done echo "Welcome Steps Completed" -echo "1. Installed Core Dependencies" -echo "2. Installed Several Optional Dependencies Useful for Running Examples" -echo "3. Moved selected Getting Started examples into /root path" -echo " -- welcome_example.py" -echo " -- example-1-create_first_library.py" -echo " -- example-2-build_embeddings.py" -echo " -- example-3-prompts_and_models.py" -echo " -- example-4-rag-text-query.py" -echo " -- example-5-rag-semantic-query.py" -echo " -- example-6-rag-multi-step-query.py" -echo " -- gguf_streaming.py" -echo " -- bling_fast_start.py" -echo " -- using_slim_extract_model.py" -echo " -- using_slim_summary.py" -echo " -- dragon_gguf_fast_start.py" -echo " -- invoice_processing.py" -echo " -- gguf_streaming_chatbot.py" -echo " -- agent-llmfx-getting-started.py" -echo " -- whisper-cpp-sample-files.py" -echo " -- web_services_slim_fx.py" -echo " -- parsing_microsoft_ir_docs.py" -echo " -- document_summarizer.py" -echo " -- chat_models_gguf_fast_start.py ." +echo "1. Installed Core Dependencies" +echo "2. Installed Several Optional Dependencies Useful for Running Examples" +echo "3. Moved selected Getting Started examples into /root path" + +echo "Selected examples:" +for example in "${examples[@]}"; do + echo " -- $(basename "$example")" +done echo "" -echo "To run an example from command-line: py welcome_example.py" -echo "To run gguf_streaming_chatbot.py: streamlit run gguf_streaming_chatbot.py" -echo "Note: check the /examples folder for 100+ additional examples" -echo "Note: on first time use, models will be downloaded and cached locally" -echo "Note: open up the examples and edit for more configuration options" +echo "To run an example from the command line: py welcome_example.py" +echo "To run gguf_streaming_chatbot.py: streamlit run gguf_streaming_chatbot.py" +echo "Note: Check the /examples folder for 100+ additional examples." +echo "Note: On first-time use, models will be downloaded and cached locally." +echo "Note: Open up the examples and edit for more configuration options." echo "" -echo "Running welcome_example.py" -py welcome_example.py +echo "Running welcome_example.py..." +py welcome_example.py || error_exit "Failed to run welcome_example.py." -# keeps bash console open (may be in separate window) -bash +# Keeps the bash console open (may be in a separate window) +exec bash