Syed Junaid Iqbal commited on
Commit
5887a43
β€’
1 Parent(s): 1534aac

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +291 -0
app.py ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+
3
+ import streamlit as st
4
+ from dotenv import load_dotenv
5
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
6
+ from langchain.vectorstores import FAISS
7
+ from langchain.embeddings import FastEmbedEmbeddings # General embeddings from HuggingFace models.
8
+ from langchain.memory import ConversationBufferMemory
9
+ from langchain.callbacks.manager import CallbackManager
10
+ from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
11
+ from htmlTemplates import css, bot_template, user_template
12
+ from langchain.llms import LlamaCpp # For loading transformer models.
13
+ from langchain.document_loaders import PyPDFLoader, TextLoader, CSVLoader
14
+ from langchain.chains import RetrievalQA
15
+ from langchain.prompts import PromptTemplate
16
+ from langchain import hub
17
+ import os
18
+ import glob
19
+ import shutil
20
+
21
+ os.environ['FAISS_NO_AVX2'] = '1'
22
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
23
+
24
+
25
+ def load_document_text():
26
+ """
27
+ input : path to the document
28
+ output: list of loaded document
29
+ """
30
+
31
+ documents = []
32
+
33
+ for dox in os.listdir(path= "./documents/"):
34
+ dir = os.path.join("./documents/", dox)
35
+
36
+ if dox.endswith(".pdf"):
37
+ documents.extend( PyPDFLoader(dir).load() )
38
+
39
+ elif dox.endswith(".txt"):
40
+ documents.extend( TextLoader(dir).load() )
41
+
42
+ elif dox.endswith(".csv"):
43
+ documents.extend( CSVLoader(dir).load() )
44
+
45
+ return documents
46
+
47
+ def get_text_chunks(documents):
48
+ """
49
+ For the compute purpose we will split the document into multiple smaller chunks.
50
+
51
+ IMPORTANT : If the chunks too small we will miss the context and if its too large we will have longer compute time
52
+ """
53
+ text_splitter = RecursiveCharacterTextSplitter(
54
+ chunk_size=1024,
55
+ chunk_overlap=100,
56
+ )
57
+
58
+ st.session_state.text_chunks = text_splitter.split_documents(documents)
59
+
60
+
61
+ def get_vectorstore():
62
+ """
63
+ given the chunks, we will embed them into vector stores
64
+ """
65
+
66
+ if len(glob.glob("./vectordb/*.faiss")) == 0:
67
+ st.session_state.vectorstore = FAISS.from_documents(documents= st.session_state.text_chunks,
68
+ embedding= st.session_state.embeddings)
69
+ # save the file
70
+ st.session_state.vectorstore.save_local("./vectordb")
71
+ else:
72
+ st.session_state.vectorstore = FAISS.load_local("./vectordb/",
73
+ st.session_state.embeddings)
74
+
75
+
76
+ def get_conversation_chain():
77
+ """
78
+ This is a langchain model where we will be binding the runner to infer data from LLM
79
+ """
80
+ model_path = st.session_state.model
81
+ callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])
82
+
83
+ llm = LlamaCpp(model_path= model_path,
84
+ n_ctx=4000,
85
+ max_tokens= 4000,
86
+ fp = 50,
87
+ n_batch = 512,
88
+ callback_manager = callback_manager,
89
+ verbose=True)
90
+
91
+ memory = ConversationBufferMemory(
92
+ memory_key='chat_history', return_messages=False)
93
+
94
+
95
+ prompt_template = """You are a personal HR Bot assistant for answering any questions about Companies policies
96
+ You are given a question and a set of documents.
97
+ If the user's question requires you to provide specific information from the documents, give your answer based only on the examples provided below. DON'T generate an answer that is NOT written in the provided examples.
98
+ If you don't find the answer to the user's question with the examples provided to you below, answer that you didn't find the answer in the documentation and propose him to rephrase his query with more details.
99
+ Use bullet points if you have to make a list, only if necessary.
100
+
101
+ QUESTION: {question}
102
+
103
+ DOCUMENTS:
104
+ =========
105
+ {context}
106
+ =========
107
+ Finish by proposing your help for anything else.
108
+ """
109
+
110
+ rag_prompt_custom = PromptTemplate.from_template(prompt_template)
111
+
112
+ prompt = hub.pull("rlm/rag-prompt")
113
+
114
+ conversation_chain = RetrievalQA.from_chain_type(
115
+ llm,
116
+ retriever= st.session_state.vectorstore.as_retriever(),
117
+ chain_type_kwargs={"prompt": prompt},
118
+ )
119
+ conversation_chain.callback_manager = callback_manager
120
+ conversation_chain.memory = ConversationBufferMemory()
121
+
122
+ return conversation_chain
123
+
124
+
125
+ def handle_userinput():
126
+
127
+ clear = False
128
+
129
+ # Add clear chat button
130
+ if st.button("Clear Chat history"):
131
+ clear = True
132
+ st.session_state.messages = []
133
+
134
+ if "messages" not in st.session_state:
135
+ st.session_state.messages = [{"role": "assistant", "content": "How can I help you?"}]
136
+
137
+ for msg in st.session_state.messages:
138
+ st.chat_message(msg["role"]).write(msg["content"])
139
+
140
+ if prompt := st.chat_input():
141
+ st.session_state.messages.append({"role": "user", "content": prompt})
142
+ st.chat_message("user").write(prompt)
143
+ if clear:
144
+ st.session_state.conversation.clean()
145
+
146
+ msg = st.session_state.conversation.run(prompt)
147
+ print(msg)
148
+ st.session_state.messages.append({"role": "assistant", "content": msg})
149
+ st.chat_message("assistant").write(msg)
150
+
151
+
152
+
153
+ # Function to apply rounded edges using CSS
154
+ def add_rounded_edges(image_path="./randstad_featuredimage.png", radius=30):
155
+ st.markdown(
156
+ f'<style>.rounded-img{{border-radius: {radius}px; overflow: hidden;}}</style>',
157
+ unsafe_allow_html=True,)
158
+ st.image(image_path, use_column_width=True, output_format='auto')
159
+
160
+
161
+ # Delete our vector DB
162
+ def delete_db(directory_path = './vectordb/'):
163
+
164
+ # Check if the directory exists
165
+ if os.path.exists(directory_path) and len(os.listdir(directory_path)) > 0:
166
+ # Iterate over all files in the directory and remove them
167
+ for filename in os.listdir(directory_path):
168
+ file_path = os.path.join(directory_path, filename)
169
+ try:
170
+ if os.path.isfile(file_path) or os.path.islink(file_path):
171
+ os.unlink(file_path)
172
+ elif os.path.isdir(file_path):
173
+ shutil.rmtree(file_path)
174
+ except Exception as e:
175
+ print(f"Error deleting {file_path}: {e}")
176
+ else:
177
+ print(f"The directory {directory_path} does not exist.")
178
+
179
+
180
+
181
+ def save_uploaded_file(uploaded_file):
182
+ save_directory = "./documents/"
183
+ file_path = os.path.join(save_directory, uploaded_file.name)
184
+ with open(file_path, "wb") as f:
185
+ f.write(uploaded_file.getvalue())
186
+ return file_path
187
+
188
+
189
+ def load_dependencies():
190
+ # append documents to a list
191
+ doc_list = load_document_text()
192
+
193
+ # get the text chunks
194
+ get_text_chunks(doc_list)
195
+
196
+ # create vector store
197
+ get_vectorstore()
198
+
199
+ # create conversation chain
200
+ st.session_state.conversation = get_conversation_chain()
201
+
202
+
203
+ def main():
204
+ load_dotenv()
205
+ st.set_page_config(page_title="Chat with multiple Files",
206
+ page_icon=":books:")
207
+ st.write(css, unsafe_allow_html=True)
208
+
209
+
210
+ if "conversation" not in st.session_state:
211
+ st.session_state.conversation = None
212
+ if "chat_history" not in st.session_state:
213
+ st.session_state.chat_history = None
214
+
215
+ st.title("πŸ’¬ Randstad HR Chatbot")
216
+ st.subheader("πŸš€ A HR powered by Generative AI")
217
+
218
+ # default model
219
+ st.session_state.model = "./models/mistral-7b-instruct-v0.2.Q5_K_M.gguf"
220
+
221
+
222
+ # Embedding Model
223
+ st.session_state.embeddings = FastEmbedEmbeddings( model_name= "BAAI/bge-small-en-v1.5",
224
+ cache_dir="./embedding_model/")
225
+
226
+ with st.sidebar:
227
+
228
+ # calling a
229
+ add_rounded_edges()
230
+
231
+ st.subheader("Select Your Embedding Model Model")
232
+ st.session_state.model = st.selectbox( 'Models', tuple( glob.glob('./models/*.gguf') ) )
233
+
234
+
235
+ st.subheader("Your documents")
236
+
237
+ # Space to Upload a Document
238
+ docs = st.file_uploader(
239
+ "Upload File (pdf,text,csv...) and click 'Process'", accept_multiple_files=True)
240
+
241
+ # Define a process button
242
+ if st.button("Process"):
243
+
244
+ # delete the old embeddings
245
+ delete_db()
246
+
247
+ # then Embedd new documents
248
+ with st.spinner("Processing"):
249
+
250
+
251
+ # iterate over updated files and save them to the local directory (i.e. "Documents") using a helper function
252
+ for file in docs:
253
+ save_uploaded_file(file)
254
+
255
+ """
256
+ using the helper function below lets load our dependencies
257
+ Step 1 : Load the documents
258
+ Step 2 : Break them into Chunks
259
+ Step 3 : Create Embeddings and save them to Vector DB
260
+ Step 4 : Get our conversation chain
261
+ """
262
+ load_dependencies()
263
+
264
+ # Load our model
265
+ if len(glob.glob("./vectordb/*.faiss")) == 0:
266
+ load_dependencies()
267
+ get_vectorstore()
268
+ else:
269
+ get_vectorstore()
270
+ st.session_state.conversation = get_conversation_chain()
271
+
272
+ handle_userinput()
273
+
274
+ # # load dependencies -> chaunks of documents -> Embeddings -> Inference
275
+ # load_dependencies()
276
+
277
+
278
+
279
+ if __name__ == '__main__':
280
+
281
+ command = 'CMAKE_ARGS="-DLLAMA_CUBLAS=on" FORCE_CMAKE=1 pip install llama-cpp-python --no-cache-dir'
282
+
283
+ # Run the command using subprocess
284
+ try:
285
+ subprocess.run(command, shell=True, check=True)
286
+ print("Command executed successfully.")
287
+ except subprocess.CalledProcessError as e:
288
+ print(f"Error: {e}")
289
+
290
+ # Run the apps
291
+ main()