From 00e6d3ec388bc1755f541cbc72f12bc3a868af5d Mon Sep 17 00:00:00 2001 From: Nicholas Arquette Date: Fri, 31 Jan 2025 18:20:37 -0600 Subject: [PATCH] Feature: Added a chat RAG example with sample medical provide note data supplied from mtsamples.com. --- .../rag_chat_example/README.md | 37 +++ .../rag_chat_example/img.png | Bin 0 -> 90717 bytes .../test_patient_1_f/progress_note.txt | 44 +++ .../test_patient_2_f/progress_note.txt | 50 ++++ .../test_patient_3_m/progress_note.txt | 25 ++ .../test_patient_4_f/progress_note.txt | 54 ++++ .../rag_chat_example/run_rag_chat.py | 59 ++++ .../rag_chat_example/utils.py | 267 ++++++++++++++++++ 8 files changed, 536 insertions(+) create mode 100644 week5/community-contributions/rag_chat_example/README.md create mode 100644 week5/community-contributions/rag_chat_example/img.png create mode 100644 week5/community-contributions/rag_chat_example/knowledge_base/mtsample_dictations/test_patient_1_f/progress_note.txt create mode 100644 week5/community-contributions/rag_chat_example/knowledge_base/mtsample_dictations/test_patient_2_f/progress_note.txt create mode 100644 week5/community-contributions/rag_chat_example/knowledge_base/mtsample_dictations/test_patient_3_m/progress_note.txt create mode 100644 week5/community-contributions/rag_chat_example/knowledge_base/mtsample_dictations/test_patient_4_f/progress_note.txt create mode 100644 week5/community-contributions/rag_chat_example/run_rag_chat.py create mode 100644 week5/community-contributions/rag_chat_example/utils.py diff --git a/week5/community-contributions/rag_chat_example/README.md b/week5/community-contributions/rag_chat_example/README.md new file mode 100644 index 0000000..7f92b0c --- /dev/null +++ b/week5/community-contributions/rag_chat_example/README.md @@ -0,0 +1,37 @@ +# Overview + +This uses de-identified medical dictation data supplied by [mtsamples](https://mtsamples.com). The data from the mtsamples +website was download from [kaggle](https://www.kaggle.com/datasets/tboyle10/medicaltranscriptions). There are four +sample notes in different directories (see knowledge_base/mtsamples_dictations) that will added to a chromaDb +vector database and will be available during chat using RAG (Retrieval Augmented Generation). + +# How to run + +- Run example + +```shell +conda activate +cd +python run_rag_chat.py +``` + +# Chat example + +![Chat Example](img.png) + +# Questions to ask? + +1) How old is Ms. Connor? +2) What are Ms. Connor's vital signs? +3) How old is Ms. Mouse? +4) What is Ms. Mouse concerned about? +5) What are Ms. Mouse's vital signs? +6) How old is Mr. Duck? +7) Why did Mr. Duck go to the doctor? +8) How old is Ms. Barbara? +9) Why did Ms. Barbara go to the doctor? +10) Is Ms. Barbara allergic to anything? + + + + diff --git a/week5/community-contributions/rag_chat_example/img.png b/week5/community-contributions/rag_chat_example/img.png new file mode 100644 index 0000000000000000000000000000000000000000..e8b2ba7fce0159f5325ac56f8812483966ad6a17 GIT binary patch literal 90717 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%0DVg%|WdUg8SW3 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 str: + + """ + Get the chat data need for the gradio app + + :param question: + The question being asked in the chat app. + :type question: str + :param history: + A list of the conversation questions and answers. + :type history: list + :return: + The answer from the current question. + """ + + result = conversation_chain.invoke({"question": question}) + answer = result['answer'] + + # include source documents if they exist + # grab the first one as that should be related to the answer + source_doc = "" + if result.get('source_documents'): + source_doc = result['source_documents'][0] + + response = f"{answer}\n\n**Source:**\n{source_doc.metadata.get('source', 'Source')}" \ + if source_doc \ + else answer + return response + + +def main(): + + gr.ChatInterface(chat, type="messages").launch(inbrowser=True) + + +if __name__ == '__main__': + + create_new_db = False if Path('vector_db').exists() else True + + if create_new_db: + folders = Path('knowledge_base').glob('*') + chunks = get_chunks(folders=folders) + vector_store = create_vector_db(chunks=chunks, db_name=Rag.DB_NAME.value, embeddings=Rag.EMBED_MODEL.value) + else: + client = get_local_vector_db(path='../rag_chat_example/vector_db') + vector_store = Chroma(client=client, embedding_function=Rag.EMBED_MODEL.value) + + conversation_chain = get_conversation_chain(vectorstore=vector_store) + + main() + + + diff --git a/week5/community-contributions/rag_chat_example/utils.py b/week5/community-contributions/rag_chat_example/utils.py new file mode 100644 index 0000000..5ce8123 --- /dev/null +++ b/week5/community-contributions/rag_chat_example/utils.py @@ -0,0 +1,267 @@ +from chromadb import PersistentClient +from dotenv import load_dotenv +from enum import Enum + +import plotly.graph_objects as go +from langchain.document_loaders import DirectoryLoader, TextLoader +from langchain.text_splitter import CharacterTextSplitter +from langchain.schema import Document +from langchain_openai import OpenAIEmbeddings, ChatOpenAI +from langchain_chroma import Chroma +from langchain.memory import ConversationBufferMemory +from langchain.chains import ConversationalRetrievalChain +import numpy as np +import os +from pathlib import Path +from sklearn.manifold import TSNE +from typing import Any, List, Tuple, Generator + +cur_path = Path(__file__) +env_path = cur_path.parent.parent.parent.parent / '.env' +assert env_path.exists(), f"Please add an .env to the root project path" + +load_dotenv(dotenv_path=env_path) + + +class Rag(Enum): + + GPT_MODEL = "gpt-4o-mini" + HUG_MODEL = "sentence-transformers/all-MiniLM-L6-v2" + EMBED_MODEL = OpenAIEmbeddings() + DB_NAME = "vector_db" + + +def add_metadata(doc: Document, doc_type: str) -> Document: + """ + Add metadata to a Document object. + + :param doc: The Document object to add metadata to. + :type doc: Document + :param doc_type: The type of document to be added as metadata. + :type doc_type: str + :return: The Document object with added metadata. + :rtype: Document + """ + doc.metadata["doc_type"] = doc_type + return doc + + +def get_chunks(folders: Generator[Path, None, None], file_ext='.txt') -> List[Document]: + """ + Load documents from specified folders, add metadata, and split them into chunks. + + :param folders: List of folder paths containing documents. + :type folders: List[str] + :param file_ext: + The file extension to get from a local knowledge base (e.g. '.txt') + :type file_ext: str + :return: List of document chunks. + :rtype: List[Document] + """ + text_loader_kwargs = {'encoding': 'utf-8'} + documents = [] + for folder in folders: + doc_type = os.path.basename(folder) + loader = DirectoryLoader( + folder, glob=f"**/*{file_ext}", loader_cls=TextLoader, loader_kwargs=text_loader_kwargs + ) + folder_docs = loader.load() + documents.extend([add_metadata(doc, doc_type) for doc in folder_docs]) + + text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=200) + chunks = text_splitter.split_documents(documents) + + return chunks + + +def create_vector_db(db_name: str, chunks: List[Document], embeddings: Any) -> Any: + """ + Create a vector database from document chunks. + + :param db_name: Name of the database to create. + :type db_name: str + :param chunks: List of document chunks. + :type chunks: List[Document] + :param embeddings: Embedding function to use. + :type embeddings: Any + :return: Created vector store. + :rtype: Any + """ + # Delete if already exists + if os.path.exists(db_name): + Chroma(persist_directory=db_name, embedding_function=embeddings).delete_collection() + + # Create vectorstore + vectorstore = Chroma.from_documents(documents=chunks, embedding=embeddings, persist_directory=db_name) + + return vectorstore + + +def get_local_vector_db(path: str) -> Any: + """ + Get a local vector database. + + :param path: Path to the local vector database. + :type path: str + :return: Persistent client for the vector database. + :rtype: Any + """ + return PersistentClient(path=path) + + +def get_vector_db_info(vector_store: Any) -> None: + """ + Print information about the vector database. + + :param vector_store: Vector store to get information from. + :type vector_store: Any + """ + collection = vector_store._collection + count = collection.count() + + sample_embedding = collection.get(limit=1, include=["embeddings"])["embeddings"][0] + dimensions = len(sample_embedding) + + print(f"There are {count:,} vectors with {dimensions:,} dimensions in the vector store") + + +def get_plot_data(collection: Any) -> Tuple[np.ndarray, List[str], List[str], List[str]]: + """ + Get plot data from a collection. + + :param collection: Collection to get data from. + :type collection: Any + :return: Tuple containing vectors, colors, document types, and documents. + :rtype: Tuple[np.ndarray, List[str], List[str], List[str]] + """ + result = collection.get(include=['embeddings', 'documents', 'metadatas']) + vectors = np.array(result['embeddings']) + documents = result['documents'] + metadatas = result['metadatas'] + doc_types = [metadata['doc_type'] for metadata in metadatas] + colors = [['blue', 'green', 'red', 'orange'][['products', 'employees', 'contracts', 'company'].index(t)] for t in + doc_types] + + return vectors, colors, doc_types, documents + + +def get_2d_plot(collection: Any) -> go.Figure: + """ + Generate a 2D plot of the vector store. + + :param collection: Collection to generate plot from. + :type collection: Any + :return: 2D scatter plot figure. + :rtype: go.Figure + """ + vectors, colors, doc_types, documents = get_plot_data(collection) + tsne = TSNE(n_components=2, random_state=42) + reduced_vectors = tsne.fit_transform(vectors) + + fig = go.Figure(data=[go.Scatter( + x=reduced_vectors[:, 0], + y=reduced_vectors[:, 1], + mode='markers', + marker=dict(size=5, color=colors, opacity=0.8), + text=[f"Type: {t}
Text: {d[:100]}..." for t, d in zip(doc_types, documents)], + hoverinfo='text' + )]) + + fig.update_layout( + title='2D Chroma Vector Store Visualization', + scene=dict(xaxis_title='x', yaxis_title='y'), + width=800, + height=600, + margin=dict(r=20, b=10, l=10, t=40) + ) + + return fig + + +def get_3d_plot(collection: Any) -> go.Figure: + """ + Generate a 3D plot of the vector store. + + :param collection: Collection to generate plot from. + :type collection: Any + :return: 3D scatter plot figure. + :rtype: go.Figure + """ + vectors, colors, doc_types, documents = get_plot_data(collection) + tsne = TSNE(n_components=3, random_state=42) + reduced_vectors = tsne.fit_transform(vectors) + + fig = go.Figure(data=[go.Scatter3d( + x=reduced_vectors[:, 0], + y=reduced_vectors[:, 1], + z=reduced_vectors[:, 2], + mode='markers', + marker=dict(size=5, color=colors, opacity=0.8), + text=[f"Type: {t}
Text: {d[:100]}..." for t, d in zip(doc_types, documents)], + hoverinfo='text' + )]) + + fig.update_layout( + title='3D Chroma Vector Store Visualization', + scene=dict(xaxis_title='x', yaxis_title='y', zaxis_title='z'), + width=900, + height=700, + margin=dict(r=20, b=10, l=10, t=40) + ) + + return fig + + +def get_conversation_chain(vectorstore: Any) -> ConversationalRetrievalChain: + """ + Create a conversation chain using the vector store. + + :param vectorstore: Vector store to use in the conversation chain. + :type vectorstore: Any + :return: Conversational retrieval chain. + :rtype: ConversationalRetrievalChain + """ + llm = ChatOpenAI(temperature=0.7, model_name=Rag.GPT_MODEL.value) + + memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True, output_key='answer') + + retriever = vectorstore.as_retriever(search_kwargs={"k": 25}) + + conversation_chain = ConversationalRetrievalChain.from_llm( + llm=llm, + retriever=retriever, + memory=memory, + return_source_documents=True, + ) + + return conversation_chain + + +def get_lang_doc(document_text, doc_id, metadata=None, encoding='utf-8'): + + """ + Build a langchain Document that can be used to create a chroma database + + :type document_text: str + :param document_text: + The text to add to a document object + :type doc_id: str + :param doc_id: + The document id to include. + :type metadata: dict + :param metadata: + A dictionary of metadata to associate to the document object. This will help filter an item from a + vector database. + :type encoding: string + :param encoding: + The type of encoding to use for loading the text. + + """ + return Document( + page_content=document_text, + id=doc_id, + metadata=metadata, + encoding=encoding, + ) + +