chsubhasis commited on
Commit
a21db6e
·
1 Parent(s): 92421ad

app and requirements files added

Browse files
Files changed (2) hide show
  1. app.py +213 -0
  2. requirements.txt +0 -0
app.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from getpass import getpass
3
+ import csv
4
+ from langchain_core.documents import Document
5
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
6
+ #from langchain.schema import Document
7
+ from langchain_huggingface import HuggingFaceEmbeddings
8
+ import torch
9
+ from langchain_huggingface import HuggingFaceEndpoint
10
+ from langchain_community.cache import InMemoryCache
11
+ from langchain.globals import set_llm_cache
12
+ from langchain_chroma import Chroma
13
+ from langchain.chains import RetrievalQA
14
+ import numpy as np
15
+ import gradio
16
+ import sqlite3
17
+
18
+ hfapi_key = getpass("Enter you HuggingFace access token:")
19
+ os.environ["HF_TOKEN"] = hfapi_key
20
+ os.environ["HUGGINGFACEHUB_API_TOKEN"] = hfapi_key
21
+
22
+ set_llm_cache(InMemoryCache())
23
+
24
+ persist_directory = 'docs/chroma/'
25
+
26
+ ####################################
27
+ def load_file_as_JSON():
28
+ print("$$$$$ ENTER INTO load_file_as_JSON $$$$$")
29
+ rows = []
30
+ with open("mini-llama-articles.csv", mode="r", encoding="utf-8") as file:
31
+ csv_reader = csv.reader(file)
32
+ for idx, row in enumerate(csv_reader):
33
+ if idx == 0:
34
+ continue
35
+ # Skip header row
36
+ rows.append(row)
37
+
38
+ print("@@@@@@ EXIT FROM load_file_as_JSON @@@@@")
39
+ return rows
40
+ ####################################
41
+ def get_documents():
42
+ print("$$$$$ ENTER INTO get_documents $$$$$")
43
+ documents = [
44
+ Document(
45
+ page_content=row[1], metadata={"title": row[0], "url": row[2], "source_name": row[3]}
46
+ )
47
+ for row in load_file_as_JSON()
48
+ ]
49
+ print("documents lenght is ", len(documents))
50
+ print("first entry from documents ", documents[0])
51
+ print("document metadata ", documents[0].metadata)
52
+ print("@@@@@@ EXIT FROM get_documents @@@@@")
53
+ return documents
54
+ ####################################
55
+ def getDocSplitter():
56
+ print("$$$$$ ENTER INTO getDocSplitter $$$$$")
57
+ text_splitter = RecursiveCharacterTextSplitter(
58
+ chunk_size = 512,
59
+ chunk_overlap = 128
60
+ )
61
+ splits = text_splitter.split_documents(get_documents())
62
+ print("Split length ", len(splits))
63
+ print("Page content ", splits[0].page_content)
64
+ print("@@@@@@ EXIT FROM getDocSplitter @@@@@")
65
+ return splits
66
+ ####################################
67
+ def getEmbeddings():
68
+ print("$$$$$ ENTER INTO getEmbeddings $$$$$")
69
+ modelPath="mixedbread-ai/mxbai-embed-large-v1"
70
+ device = "cuda" if torch.cuda.is_available() else "cpu"
71
+
72
+ # Create a dictionary with model configuration options, specifying to use the CPU for computations
73
+ model_kwargs = {'device': device} # cuda/cpu
74
+
75
+ # Create a dictionary with encoding options, specifically setting 'normalize_embeddings' to False
76
+ encode_kwargs = {'normalize_embeddings': False}
77
+
78
+ embedding = HuggingFaceEmbeddings(
79
+ model_name=modelPath, # Provide the pre-trained model's path
80
+ model_kwargs=model_kwargs, # Pass the model configuration options
81
+ encode_kwargs=encode_kwargs # Pass the encoding options
82
+ )
83
+
84
+ print("Embedding ", embedding)
85
+ print("@@@@@@ EXIT FROM getEmbeddings @@@@@")
86
+ return embedding
87
+ ####################################
88
+ def getLLM():
89
+ print("$$$$$ ENTER INTO getLLM $$$$$")
90
+ llm = HuggingFaceEndpoint(
91
+ repo_id="HuggingFaceH4/zephyr-7b-beta",
92
+ #repo_id="chsubhasis/ai-tutor-towardsai",
93
+ task="text-generation",
94
+ max_new_tokens = 512,
95
+ top_k = 10,
96
+ temperature = 0.1,
97
+ repetition_penalty = 1.03,
98
+ )
99
+ print("llm ", llm)
100
+ print("Who is the CEO of Apple? ", llm.invoke("Who is the CEO of Apple?")) #test
101
+ print("@@@@@@ EXIT FROM getLLM @@@@@")
102
+ return llm
103
+ ####################################
104
+ def is_chroma_db_present(directory: str):
105
+ """
106
+ Check if the directory exists and contains any files.
107
+ """
108
+ return os.path.exists(directory) and len(os.listdir(directory)) > 0
109
+ ####################################
110
+ def getRetiriver():
111
+ print("$$$$$ ENTER INTO getRetiriver $$$$$")
112
+ if is_chroma_db_present(persist_directory):
113
+ print(f"Chroma vector DB found in '{persist_directory}' and will be loaded.")
114
+ # Load vector store from the local directory
115
+ #vectordb = Chroma(persist_directory=persist_directory)
116
+ vectordb = Chroma(
117
+ persist_directory=persist_directory,
118
+ embedding_function=getEmbeddings(),
119
+ collection_name="ai_tutor")
120
+ else:
121
+ vectordb = Chroma.from_documents(
122
+ collection_name="ai_tutor",
123
+ documents=getDocSplitter(), # splits we created earlier
124
+ embedding=getEmbeddings(),
125
+ persist_directory=persist_directory, # save the directory
126
+ )
127
+ print("vectordb collection count ", vectordb._collection.count())
128
+
129
+ docs = vectordb.search("What is Artificial Intelligence", search_type="mmr", k=5)
130
+ for i in range(len(docs)):
131
+ print(docs[i].page_content)
132
+
133
+ metadata_filter = {
134
+ "result": "llama" # ChromaDB will perform a substring search
135
+ }
136
+
137
+ retriever = vectordb.as_retriever(search_type="mmr", search_kwargs={"k": 3, "fetch_k":5, "filter": metadata_filter})
138
+ print("retriever ", retriever)
139
+ print("@@@@@@ EXIT FROM getRetiriver @@@@@")
140
+ return retriever
141
+ ####################################
142
+ def get_rag_response(query):
143
+ print("$$$$$ ENTER INTO get_rag_response $$$$$")
144
+ qa_chain = RetrievalQA.from_chain_type(
145
+ llm=getLLM(),
146
+ chain_type="stuff",
147
+ retriever=getRetiriver(),
148
+ return_source_documents=True
149
+ )
150
+
151
+ #RAG Evaluation
152
+ # Sample dataset of questions and expected answers
153
+ dataset = [
154
+ {"question": "Who is the CEO of Meta?", "expected_answer": "Mark Zuckerberg"},
155
+ {"question": "Who is the CEO of Apple?", "expected_answer": "Tiiiiiim Coooooook"},
156
+ ]
157
+
158
+ hit_rate, mrr = evaluate_rag(qa_chain, dataset)
159
+ print(f"Hit Rate: {hit_rate:.2f}, Mean Reciprocal Rank (MRR): {mrr:.2f}")
160
+
161
+ result = qa_chain({"query": query})
162
+ print("Result ",result)
163
+ print("@@@@@@ EXIT FROM get_rag_response @@@@@")
164
+ return result["result"]
165
+ ####################################
166
+ def evaluate_rag(qa, dataset):
167
+ print("$$$$$ ENTER INTO evaluate_rag $$$$$")
168
+ hits = 0
169
+ reciprocal_ranks = []
170
+
171
+ for entry in dataset:
172
+ question = entry["question"]
173
+ expected_answer = entry["expected_answer"]
174
+
175
+ # Get the answer from the RAG system
176
+ response = qa({"query": question})
177
+ answer = response["result"]
178
+
179
+ # Check if the answer matches the expected answer
180
+ if expected_answer.lower() in answer.lower():
181
+ hits += 1
182
+ reciprocal_ranks.append(1) # Hit at rank 1
183
+ else:
184
+ reciprocal_ranks.append(0)
185
+
186
+ # Calculate Hit Rate and MRR
187
+ hit_rate = hits / len(dataset)
188
+ mrr = np.mean(reciprocal_ranks)
189
+
190
+ print("@@@@@@ EXIT FROM evaluate_rag @@@@@")
191
+ return hit_rate, mrr
192
+ ####################################
193
+ def launch_ui():
194
+ print("$$$$$ ENTER INTO launch_ui $$$$$")
195
+ # Input from user
196
+ in_question = gradio.Textbox(lines=10, placeholder=None, value="query", label='Enter your query')
197
+
198
+ # Output prediction
199
+ out_response = gradio.Textbox(type="text", label='RAG Response')
200
+
201
+ # Gradio interface to generate UI
202
+ iface = gradio.Interface(fn = get_rag_response,
203
+ inputs = [in_question],
204
+ outputs = [out_response],
205
+ title = "RAG Response",
206
+ description = "Write the query and get the response from the RAG system",
207
+ allow_flagging = 'never')
208
+
209
+ iface.launch(share = True)
210
+
211
+ ####################################
212
+ if __name__ == "__main__":
213
+ launch_ui()
requirements.txt ADDED
Binary file (308 Bytes). View file