From 41547195c2f89b0cce1a006e649e2cd674f421c7 Mon Sep 17 00:00:00 2001 From: labri Date: Thu, 11 Apr 2024 21:37:49 +0200 Subject: [PATCH 1/6] updated the load_credentials() method --- src/utils/utils.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/utils/utils.py b/src/utils/utils.py index 78d0428..9389712 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -1,16 +1,15 @@ import yaml +import os -def load_credentials(credentials_path): +def load_credentials(credentials_path="secrets/credentials.yml"): """ - Load credentials from a YAML file. - - Parameters: - credentials_path (str): The file path to the credentials YAML file. - - Returns: - dict: The loaded credentials. + Load credentials from the environment or a YAML file. ( depends on the environment ) """ + openai_api_key = os.getenv('OPENAI_API_KEY') + if openai_api_key: + return {'OPENAI_CREDENTIALS': openai_api_key} + with open(credentials_path, "r") as credentials_file: return yaml.safe_load(credentials_file) From 35faf8dc21eb3e1a178d2216e9302d86c074a28f Mon Sep 17 00:00:00 2001 From: labri Date: Thu, 11 Apr 2024 21:38:10 +0200 Subject: [PATCH 2/6] added tests for pytest --- tests/__init__.py | 0 tests/test_index_creation.py | 27 ++++++++++++++++++++++ tests/test_rag_query.py | 43 ++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 tests/__init__.py create mode 100644 tests/test_index_creation.py create mode 100644 tests/test_rag_query.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_index_creation.py b/tests/test_index_creation.py new file mode 100644 index 0000000..b6f26ba --- /dev/null +++ b/tests/test_index_creation.py @@ -0,0 +1,27 @@ +from src.pipelines.query_pipeline import QueryPipeline +from src.utils.utils import load_models_config, load_credentials +import os + +def test_index_creation(tmpdir): + output_directory = tmpdir.strpath + credentials = load_credentials("secrets/credentials.yml") + openai_api_key = credentials["OPENAI_CREDENTIALS"] + models_config = load_models_config("config/models_config.yml") + + query_pipeline = QueryPipeline(openai_api_key, models_config) + + total_cost = query_pipeline.setup_semantic_database( + markdown_path="data/raw/mock_markdown.md", + embedding_model="text-embedding-3-small", + save_index=True, + directory_path=output_directory, + ) + + # Check if the total cost is a float number + assert isinstance(total_cost, float) + + # Check if the index file (.bin) and texts file (.json) are created in the directory + files = os.listdir(output_directory) + print(files) + assert any(os.path.splitext(f)[1] == ".bin" for f in files) + assert any(os.path.splitext(f)[1] == ".json" for f in files) diff --git a/tests/test_rag_query.py b/tests/test_rag_query.py new file mode 100644 index 0000000..1892615 --- /dev/null +++ b/tests/test_rag_query.py @@ -0,0 +1,43 @@ +from src.pipelines.query_pipeline import QueryPipeline +from src.utils.utils import load_models_config, load_credentials +import json +import os + +def test_rag_query(): + credentials = load_credentials("secrets/credentials.yml") + openai_api_key = credentials["OPENAI_CREDENTIALS"] + models_config = load_models_config("config/models_config.yml") + directory_path = "data/processed" + + query_pipeline = QueryPipeline(openai_api_key, models_config) + query_pipeline.set_model("text-embedding-3-small") + query_pipeline.load_and_merge_databases(directory_path) + + # Load all text documents from JSON files in the directory + all_original_docs = [] + for filename in os.listdir(directory_path): + if filename.endswith(".json"): + with open(os.path.join(directory_path, filename), "r") as file: + docs = json.load(file) + all_original_docs.extend(docs) + + # Mock a query + user_query = "test query" + print(f"Querying with: '{user_query}'") + + # Execute the RAG query process + similar_docs = query_pipeline.find_similar_documents( + query_text=user_query, num_results=2 + ) + + # Print the similar documents + print("Similar documents found:") + for doc in similar_docs: + print(doc) + + # Assert that similar documents returned is a list + assert isinstance(similar_docs, list), "The result should be a list." + + # Assert that each similar document is a string and exists in the concatenated list of original documents + assert all(isinstance(doc, str) for doc in similar_docs), "Each item in results should be a string." + assert all(doc in all_original_docs for doc in similar_docs), "Each similar document should be in the list of all original documents." \ No newline at end of file From beb50ab5f0279b14690a55f9788730f23df1f3db Mon Sep 17 00:00:00 2001 From: labri Date: Thu, 11 Apr 2024 21:48:56 +0200 Subject: [PATCH 3/6] updated the mock data --- data/processed/faiss_db_mock_markdown.bin | Bin 0 -> 36909 bytes data/processed/faiss_db_mock_markdown.json | 1 + data/raw/mock_markdown.md | 17 +++++++++++++---- 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 data/processed/faiss_db_mock_markdown.bin create mode 100644 data/processed/faiss_db_mock_markdown.json diff --git a/data/processed/faiss_db_mock_markdown.bin b/data/processed/faiss_db_mock_markdown.bin new file mode 100644 index 0000000000000000000000000000000000000000..d8c7b967221ab245b9fbc0d128e11c39144d1571 GIT binary patch literal 36909 zcmY&gd0Y)z*H$VjB}#*&qJ)StRA;YEks)Jd5#gFMEAx;<5h+up$W+pRjCJHxzL0i~lYAD0WdOg{xuS}o;6^%&oq|phaLml;JWe#3j2!R!e3 z{y0lqy~5DscN9Fx`rqeVRnIZ*Qn^5Sm8yGQ3S<=r_p zDk2+?Tb_g;Gxg=#**}oEY}eL~s3&bsci=AmX^^{HM-I8Lk3}u0C7TQukg%vG%bxoY zL)~w%d5{iQ|E<&NT)K-TZN|g&F_Y0bRp8Ag0br1PMg(8XhKQ`jFvh-`eA4L$be6&1 zwmPqcJ*y)#C)n^&1BQwtt)@X#gQw!k{eGzKG$ghF+*Yo|9yK1~HO^#u%L>&;aq)Q* zIlomL9)A&nH}V4H?TvjAZ(GQOhNHmbP8Qg|UV@9hJ+JB!AAgZ8*`URa9S!BNty3X? zjw@8x4C9UV#^IxdJ8(qBG&xC=30-}nm<;xT*zse4?gKA2_k>DOo&OH)3SM80hC?0>eKoFmyn?dK_EdX*5(kT#3W}oWbdlP35gxyTP|p z59zhK7q9F879t0kNQ2lM7@YAD^c>velB>Jn$d(pdVV>{~0}d97{WbP69=%Fdyh*`J z)2_qk@g8#6haA{reijEjw&B0Z^zgCA4)5Kg$Oell znU(b*dX9s*FThRg^cz97-3VVctwidDx2omnD^q1)s5SrW_eBh~{0MGCym?XTE39Ez zif6McS)13#*yJM}`Nf4VaqP$}jQP)z@AP{h!uf6}?$J;66Eb4&X}0W$0{>YlyjMap zW(`}89zIvt!HHI~jrdRMANhdO2bG}0*_|kFZ0@09152v2ryGof{ezbpoN^1ho%7(? zHxqGAYJZ&Ce*<4WJs)W%&~(&oW>Ie=HtKMl>%6y?T8%Gw>N@gzrF$`bNhEwdNO$!a z$A=^jgF!9t;qo?paa3+Nyd8H~9^P{rzS

AyZCZWk460zv(ZF>*ydaMlX@SH|t5e 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 Date: Thu, 11 Apr 2024 21:49:25 +0200 Subject: [PATCH 4/6] updated the .gitignore and Makefile commands --- .gitignore | 8 +++++--- Makefile | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 947d618..fdf5a82 100644 --- a/.gitignore +++ b/.gitignore @@ -44,8 +44,10 @@ temp.txt # Secret files secrets/credentials.yml -# generated text files -data/processed/*.text +# generated json files +data/processed/*.json +!data/processed/faiss_db_mock_markdown.json # generated bin files -data/processed/*.bin \ No newline at end of file +data/processed/*.bin +!data/processed/faiss_db_mock_markdown.bin \ No newline at end of file diff --git a/Makefile b/Makefile index f5ccf87..32f9dd9 100644 --- a/Makefile +++ b/Makefile @@ -47,11 +47,17 @@ jupy: @echo ">>>>>> Jupyter Lab is running <<<<<<" app: + @$(VENV_ACTIVATE) @python app.py +test: + @$(VENV_ACTIVATE) + @pytest tests/ + # Display available make targets help: @echo Available targets: @echo make jupy - Activate the virtual environment and run Jupyter Lab + @echo make test - Tests the code using pytest @echo make app - Runs the App @echo Author: $(AUTHOR) \ No newline at end of file From a5ff0245e54b2bef184cfc646d440afc8152ed70 Mon Sep 17 00:00:00 2001 From: labri Date: Thu, 11 Apr 2024 21:51:29 +0200 Subject: [PATCH 5/6] added a LLM RAG testing workflow --- .github/workflows/test_app.yml | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/test_app.yml diff --git a/.github/workflows/test_app.yml b/.github/workflows/test_app.yml new file mode 100644 index 0000000..2f5795b --- /dev/null +++ b/.github/workflows/test_app.yml @@ -0,0 +1,38 @@ +name: LLM RAG testing + +on: + push: + branches: + - main + - dev + - test-and-cicd-workflow + pull_request: + branches: + - main + - dev + - test-and-cicd-workflow + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.8' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pytest + + - name: Run tests + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + run: | + pytest tests/ From 3b9b0478a089c2bc8612c8e3bb0f9b76fb30eaca Mon Sep 17 00:00:00 2001 From: labri Date: Thu, 11 Apr 2024 22:06:39 +0200 Subject: [PATCH 6/6] ignored the /tests in bandit --- .github/workflows/code_quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml index aa82ebf..8083a22 100644 --- a/.github/workflows/code_quality.yml +++ b/.github/workflows/code_quality.yml @@ -29,7 +29,7 @@ jobs: - name: Auto-fix Linting Errors with Ruff run: ruff --fix . - name: Security Check with Bandit - run: bandit -r . + run: bandit -r . --exclude ./tests/ - name: Commit & Push changes uses: actions-js/push@v1.4 with: