Spaces:
Sleeping
Sleeping
chsubhasis
commited on
Commit
·
a21db6e
1
Parent(s):
92421ad
app and requirements files added
Browse files- app.py +213 -0
- 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
|
|