From d4198c532630673c4d92320dc6203194c0c8c5b2 Mon Sep 17 00:00:00 2001 From: Riley LePrell <150089004+RileyLePrell@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:18:32 -0500 Subject: [PATCH] Updated File Fix + Updated Env + Add a Few Tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @wesslen brought up a great point about what happens if you want to update a document. Previously, if I uploaded an updated version of a document, the previous chunks would still exist alongside the new ones. To address this, I’ve updated the logic to identify when someone uploads the same document based on matching criteria (date, file type, and meeting type). The system now checks for matching chunks, lists how many exist, deletes them, and uploads the new ones. I’ve also updated the .env_example file to include AZURE_STORAGE_CONTAINER, which people need to configure. I forgot to include that earlier—oops! Additionally, I’ve added a few tests related to this functionality: metadata_deletion_test.py: Allows someone to test deleting chunks based on a specific date. metadata_by_date.py: Lets users retrieve all chunks associated with a specific date. --- Preprocessing/.env.example | 1 + Preprocessing/App/main.py | 41 +-- .../chunking_vector_embedding.py | 104 ++++--- .../Weaviate_Metadata_List_2000-10-27.docx | Bin 0 -> 40542 bytes Preprocessing/tests/metadata_by_date.py | 87 ++++++ Preprocessing/tests/metadata_deletion_test.py | 125 +++++++++ Preprocessing/tests/pytest.py | 255 ++++++++++++++++++ 7 files changed, 556 insertions(+), 57 deletions(-) create mode 100644 Preprocessing/tests/Weaviate_Metadata_List_2000-10-27.docx create mode 100644 Preprocessing/tests/metadata_by_date.py create mode 100644 Preprocessing/tests/metadata_deletion_test.py create mode 100644 Preprocessing/tests/pytest.py diff --git a/Preprocessing/.env.example b/Preprocessing/.env.example index 39a39ba5..85a4136e 100644 --- a/Preprocessing/.env.example +++ b/Preprocessing/.env.example @@ -11,6 +11,7 @@ ASSEMBLY_AI_KEY = #Azure Storage Container Connection AZURE_STORAGE_CONNECTION_STRING= +AZURE_STORAGE_CONTAINER = # Pathing Setup PYTHONPATH= \ No newline at end of file diff --git a/Preprocessing/App/main.py b/Preprocessing/App/main.py index e6546dfa..d6f339f8 100644 --- a/Preprocessing/App/main.py +++ b/Preprocessing/App/main.py @@ -18,7 +18,11 @@ from preprocessing_pipeline.pdf_conversion import convert_pdf_to_text from preprocessing_pipeline.audio_transcription import transcribe_audio from preprocessing_pipeline.text_cleaning import clean_text -from preprocessing_pipeline.chunking_vector_embedding import tokenize_and_embed_text +from preprocessing_pipeline.chunking_vector_embedding import ( + tokenize_and_embed_text, + fetch_matching_chunks, + delete_matching_chunks +) from utils.azure_blob_utils import ( upload_to_azure, download_from_azure, @@ -209,11 +213,21 @@ def upload_files_page(): upload_to_azure("clean", clean_file_name, cleaned_text) st.write(f"Uploaded cleaned text to `clean/` folder: {clean_file_name}") - # Display cleaned text - st.text_area("Cleaned Text:", cleaned_text, height=200) - st.download_button("Download Cleaned Text", data=cleaned_text, file_name=clean_file_name) + # Stage 4: Check and Delete Existing Embeddings + with st.spinner("Checking for existing embeddings..."): + matching_chunks = fetch_matching_chunks( + str(metadata["meeting_date"]), + metadata["meeting_type"], + metadata["file_type"], + clean_file_name + ) + if matching_chunks: + st.write(f"Found {len(matching_chunks)} existing chunks. Deleting...") + delete_matching_chunks(matching_chunks) + else: + st.write("No existing chunks found.") - # Stage 4: Chunk and Embed into Weaviate + # Stage 5: Chunk and Embed into Weaviate with st.spinner("Chunking and embedding text into Weaviate..."): tokenize_and_embed_text(clean_file_name, metadata) st.success("Document processed and embedded successfully!") @@ -242,33 +256,23 @@ def group_blobs_by_date(blobs): grouped = {} for blob in blobs: try: - # Extract the file name without folder prefix (e.g., "raw/") - file_name = blob.split("/")[-1] # Get only the file name part - - # Extract the date from the file name (assuming format: YYYY_MM_DD) - parts = file_name.split("_") # Split into ['2023', '12', '12', 'BOC', 'Agenda', ...] + file_name = blob.split("/")[-1] # Extract the file name + parts = file_name.split("_") # Split into parts: ['2023', '12', '12', 'BOC', 'Agenda', ...] date_str = "_".join(parts[:3]) # Join the first three parts: '2023_12_12' - - # Convert the date string to a readable format readable_date = datetime.strptime(date_str, "%Y_%m_%d").strftime("%B %d, %Y") - - # Group by the readable date if readable_date not in grouped: grouped[readable_date] = [] grouped[readable_date].append(blob) except (ValueError, IndexError): - # Handle files with unexpected formats if "Unknown Date" not in grouped: grouped["Unknown Date"] = [] grouped["Unknown Date"].append(blob) return grouped - # Group blobs by date raw_grouped = group_blobs_by_date(raw_blobs) dirty_grouped = group_blobs_by_date(dirty_blobs) clean_grouped = group_blobs_by_date(clean_blobs) - # Function to display blobs within a group def display_grouped_blobs(grouped_blobs, category): if grouped_blobs: st.subheader(f"{category.capitalize()} Documents") @@ -282,7 +286,6 @@ def display_grouped_blobs(grouped_blobs, category): else: st.info(f"No documents found in the {category} category.") - # Display grouped blobs display_grouped_blobs(raw_grouped, "raw") display_grouped_blobs(dirty_grouped, "dirty") display_grouped_blobs(clean_grouped, "clean") @@ -308,4 +311,4 @@ def display_grouped_blobs(grouped_blobs, category): elif st.session_state.page == "upload": upload_files_page() elif st.session_state.page == "view": - view_documents_page() \ No newline at end of file + view_documents_page() diff --git a/Preprocessing/preprocessing_pipeline/chunking_vector_embedding.py b/Preprocessing/preprocessing_pipeline/chunking_vector_embedding.py index 6e88de4c..380d96cd 100644 --- a/Preprocessing/preprocessing_pipeline/chunking_vector_embedding.py +++ b/Preprocessing/preprocessing_pipeline/chunking_vector_embedding.py @@ -23,6 +23,56 @@ # Initialize tiktoken for OpenAI's embedding model tokenizer = tiktoken.encoding_for_model("text-embedding-ada-002") + +def fetch_matching_chunks(meeting_date, meeting_type, file_type, source_document): + """ + Fetch matching chunks from Weaviate based on metadata. + + Args: + meeting_date (str): Date of the meeting. + meeting_type (str): Type of the meeting (e.g., "Board of Commissioners"). + file_type (str): File type (e.g., "Minutes"). + source_document (str): Name of the source document. + + Returns: + list: A list of matching documents. + """ + query = f""" + {{ + Get {{ + MeetingDocument(where: {{ + operator: And, + operands: [ + {{ path: ["meeting_date"], operator: Equal, valueString: "{meeting_date}" }}, + {{ path: ["meeting_type"], operator: Equal, valueString: "{meeting_type}" }}, + {{ path: ["file_type"], operator: Equal, valueString: "{file_type}" }}, + {{ path: ["source_document"], operator: Equal, valueString: "{source_document}" }} + ] + }}) {{ + _additional {{ + id + }} + }} + }} + }} + """ + response = client.query.raw(query) + return response.get("data", {}).get("Get", {}).get("MeetingDocument", []) + + +def delete_matching_chunks(documents): + """ + Delete matching chunks from Weaviate. + + Args: + documents (list): List of documents with IDs to delete. + """ + for doc in documents: + doc_id = doc["_additional"]["id"] + client.data_object.delete(doc_id) + print(f"Deleted chunk ID: {doc_id}") + + def tokenize_and_embed_text(clean_file_name, metadata, max_chunk_size=250): """ Tokenizes, chunks, and embeds cleaned text into Weaviate. @@ -33,68 +83,46 @@ def tokenize_and_embed_text(clean_file_name, metadata, max_chunk_size=250): max_chunk_size (int): Maximum token size for each chunk. """ try: - # Step 1: Download cleaned text from Azure + # Download cleaned text from Azure clean_text = download_from_azure("clean", clean_file_name) - print(f"Downloaded cleaned text from Azure for file: {clean_file_name}") - - # Step 2: Tokenize the text using tiktoken tokens = tokenizer.encode(clean_text) - - # Step 3: Chunk tokens into groups of max_chunk_size (default: 250 tokens per chunk) chunks = [ tokenizer.decode(tokens[i:i + max_chunk_size]) for i in range(0, len(tokens), max_chunk_size) ] - print(f"Tokenized and split text into {len(chunks)} chunks of {max_chunk_size} tokens each.") - # Extract metadata for embedding + # Metadata fields meeting_date = str(metadata["meeting_date"]) meeting_type = metadata["meeting_type"] file_type = metadata["file_type"] + source_document = clean_file_name - # Step 4: Check and delete existing embeddings in Weaviate (to prevent duplication) - query = f""" - {{ - Get {{ - MeetingDocument(where: {{ - path: ["meeting_date", "meeting_type", "file_type"], - operator: And, - valueString: "{meeting_date}" - }}) {{ - id - }} - }} - }} - """ - response = client.query.raw(query) - existing_documents = response.get("data", {}).get("Get", {}).get("MeetingDocument", []) - - for doc in existing_documents: - client.data_object.delete(doc["id"]) - print(f"Deleted {len(existing_documents)} existing embeddings for this file.") + # Check for existing embeddings + matching_chunks = fetch_matching_chunks(meeting_date, meeting_type, file_type, source_document) + if matching_chunks: + print(f"Found {len(matching_chunks)} existing chunks. Deleting...") + delete_matching_chunks(matching_chunks) + else: + print("No existing chunks found.") - # Step 5: Embed each chunk using OpenAI and store in Weaviate + # Embed and upload each chunk for i, chunk in enumerate(chunks): - # Generate embedding using OpenAI - response = openai_client.embeddings.create( - input=chunk, - model="text-embedding-ada-002" - ) - embedding = response.data[0].embedding # Correctly access embedding from the response object + response = openai_client.embeddings.create(input=chunk, model="text-embedding-ada-002") + embedding = response.data[0].embedding - # Upload chunk to Weaviate client.data_object.create( data_object={ "content": chunk, "meeting_date": meeting_date, "meeting_type": meeting_type, "file_type": file_type, - "chunk_index": i # Include chunk index for ordering + "chunk_index": i, + "source_document": source_document }, vector=embedding, class_name="MeetingDocument" ) - print(f"Uploaded chunk {i+1}/{len(chunks)} to Weaviate.") + print(f"Uploaded chunk {i + 1}/{len(chunks)} to Weaviate.") print("Successfully processed and embedded all chunks.") diff --git a/Preprocessing/tests/Weaviate_Metadata_List_2000-10-27.docx b/Preprocessing/tests/Weaviate_Metadata_List_2000-10-27.docx new file mode 100644 index 0000000000000000000000000000000000000000..8d72bb6f7441a89e018672aed3e4b336d67b4e69 GIT binary patch literal 40542 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 0, "Extracted text is empty!" + print(f"PDF conversion successful. Extracted text length: {len(extracted_text)} characters.") + except Exception as e: + assert False, f"PDF conversion failed with error: {e}" \ No newline at end of file