Spaces:
Runtime error
Runtime error
captain-awesome
commited on
Commit
•
f7172b2
1
Parent(s):
5cc9f1b
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,294 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from langchain.chains import ConversationalRetrievalChain
|
2 |
+
from langchain.chains.question_answering import load_qa_chain
|
3 |
+
from langchain.memory import ConversationBufferMemory
|
4 |
+
from langchain.llms import HuggingFacePipeline
|
5 |
+
from langchain import PromptTemplate
|
6 |
+
from langchain.embeddings import HuggingFaceEmbeddings
|
7 |
+
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
8 |
+
from langchain.vectorstores import Chroma
|
9 |
+
from langchain.document_loaders import (
|
10 |
+
CSVLoader,
|
11 |
+
DirectoryLoader,
|
12 |
+
GitLoader,
|
13 |
+
NotebookLoader,
|
14 |
+
OnlinePDFLoader,
|
15 |
+
PythonLoader,
|
16 |
+
TextLoader,
|
17 |
+
UnstructuredFileLoader,
|
18 |
+
UnstructuredHTMLLoader,
|
19 |
+
UnstructuredPDFLoader,
|
20 |
+
UnstructuredWordDocumentLoader,
|
21 |
+
WebBaseLoader,
|
22 |
+
)
|
23 |
+
from transformers import (
|
24 |
+
AutoModelForCausalLM,
|
25 |
+
AutoTokenizer,
|
26 |
+
StoppingCriteria,
|
27 |
+
StoppingCriteriaList,
|
28 |
+
pipeline,
|
29 |
+
GenerationConfig,
|
30 |
+
TextStreamer,
|
31 |
+
pipeline
|
32 |
+
)
|
33 |
+
from langchain.llms import HuggingFaceHub
|
34 |
+
import torch
|
35 |
+
from transformers import BitsAndBytesConfig
|
36 |
+
import os
|
37 |
+
from langchain.llms import CTransformers
|
38 |
+
import streamlit as st
|
39 |
+
|
40 |
+
def load_model():
|
41 |
+
# model_path=HuggingFaceHub(repo_id="vilsonrodrigues/falcon-7b-instruct-sharded")
|
42 |
+
|
43 |
+
# if not os.path.exists(model_path):
|
44 |
+
# raise FileNotFoundError(f"No model file found at {model_path}")
|
45 |
+
|
46 |
+
# quantization_config = BitsAndBytesConfig(
|
47 |
+
# load_in_4bit=True,
|
48 |
+
# bnb_4bit_compute_dtype=torch.float16,
|
49 |
+
# bnb_4bit_quant_type="nf4",
|
50 |
+
# bnb_4bit_use_double_quant=True,
|
51 |
+
# )
|
52 |
+
|
53 |
+
# model_4bit = AutoModelForCausalLM.from_pretrained(
|
54 |
+
# model_path,
|
55 |
+
# device_map="auto",
|
56 |
+
# quantization_config=quantization_config,
|
57 |
+
# )
|
58 |
+
|
59 |
+
# tokenizer = AutoTokenizer.from_pretrained(model_path)
|
60 |
+
|
61 |
+
# pipeline = pipeline(
|
62 |
+
# "text-generation",
|
63 |
+
# model=model_4bit,
|
64 |
+
# tokenizer=tokenizer,
|
65 |
+
# use_cache=True,
|
66 |
+
# device_map="auto",
|
67 |
+
# max_length=700,
|
68 |
+
# do_sample=True,
|
69 |
+
# top_k=5,
|
70 |
+
# num_return_sequences=1,
|
71 |
+
# eos_token_id=tokenizer.eos_token_id,
|
72 |
+
# pad_token_id=tokenizer.eos_token_id,
|
73 |
+
# )
|
74 |
+
|
75 |
+
# llm = HuggingFacePipeline(pipeline=pipeline)
|
76 |
+
# llm = CTransformers(
|
77 |
+
# model=HuggingFaceHub(repo_id="TheBloke/Llama-2-7B-Chat-GGML", model_kwargs={"temperature":0.5, "max_length":512})
|
78 |
+
# # model_type=model_type,
|
79 |
+
# # max_new_tokens=max_new_tokens, # type: ignore
|
80 |
+
# # temperature=temperature, # type: ignore
|
81 |
+
# )
|
82 |
+
llm = CTransformers(
|
83 |
+
model="TheBloke/Llama-2-7B-Chat-GGML"
|
84 |
+
# model_type=model_type,
|
85 |
+
# max_new_tokens=max_new_tokens, # type: ignore
|
86 |
+
# temperature=temperature, # type: ignore
|
87 |
+
)
|
88 |
+
return llm
|
89 |
+
|
90 |
+
|
91 |
+
def create_vector_database():
|
92 |
+
# DB_DIR: str = os.path.join(ABS_PATH, "db")
|
93 |
+
"""
|
94 |
+
Creates a vector database using document loaders and embeddings.
|
95 |
+
|
96 |
+
This function loads data from PDF, markdown and text files in the 'data/' directory,
|
97 |
+
splits the loaded documents into chunks, transforms them into embeddings using HuggingFace,
|
98 |
+
and finally persists the embeddings into a Chroma vector database.
|
99 |
+
|
100 |
+
"""
|
101 |
+
# Initialize loaders for different file types
|
102 |
+
pdf_loader = DirectoryLoader("data/", glob="**/*.pdf", loader_cls=PyPDFLoader)
|
103 |
+
markdown_loader = DirectoryLoader("data/", glob="**/*.md", loader_cls=UnstructuredMarkdownLoader)
|
104 |
+
text_loader = DirectoryLoader("data/", glob="**/*.txt", loader_cls=TextLoader)
|
105 |
+
csv_loader = DirectoryLoader("data/", glob="**/*.csv", loader_cls=CSVLoader)
|
106 |
+
python_loader = DirectoryLoader("data/", glob="**/*.py", loader_cls=PythonLoader)
|
107 |
+
epub_loader = DirectoryLoader("data/", glob="**/*.epub", loader_cls=UnstructuredEPubLoader)
|
108 |
+
html_loader = DirectoryLoader("data/", glob="**/*.html", loader_cls=UnstructuredHTMLLoader)
|
109 |
+
ppt_loader = DirectoryLoader("data/", glob="**/*.ppt", loader_cls=UnstructuredPowerPointLoader)
|
110 |
+
pptx_loader = DirectoryLoader("data/", glob="**/*.pptx", loader_cls=UnstructuredPowerPointLoader)
|
111 |
+
doc_loader = DirectoryLoader("data/", glob="**/*.doc", loader_cls=UnstructuredWordDocumentLoader)
|
112 |
+
docx_loader = DirectoryLoader("data/", glob="**/*.docx", loader_cls=UnstructuredWordDocumentLoader)
|
113 |
+
odt_loader = DirectoryLoader("data/", glob="**/*.odt", loader_cls=UnstructuredODTLoader)
|
114 |
+
notebook_loader = DirectoryLoader("data/", glob="**/*.ipynb", loader_cls=NotebookLoader)
|
115 |
+
|
116 |
+
|
117 |
+
all_loaders = [pdf_loader, markdown_loader, text_loader, csv_loader, python_loader, epub_loader, html_loader, ppt_loader, pptx_loader, doc_loader, docx_loader, odt_loader, notebook_loader]
|
118 |
+
|
119 |
+
# Load documents from all loaders
|
120 |
+
loaded_documents = []
|
121 |
+
for loader in all_loaders:
|
122 |
+
loaded_documents.extend(loader.load())
|
123 |
+
|
124 |
+
# Split loaded documents into chunks
|
125 |
+
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=40)
|
126 |
+
chunked_documents = text_splitter.split_documents(loaded_documents)
|
127 |
+
|
128 |
+
# Initialize HuggingFace embeddings
|
129 |
+
embeddings = HuggingFaceEmbeddings(
|
130 |
+
model_name="sentence-transformers/all-MiniLM-L6-v2"
|
131 |
+
)
|
132 |
+
|
133 |
+
# Create and persist a Chroma vector database from the chunked documents
|
134 |
+
db = Chroma.from_documents(
|
135 |
+
documents=chunked_documents,
|
136 |
+
embedding=embeddings,
|
137 |
+
# persist_directory=DB_DIR,
|
138 |
+
)
|
139 |
+
db.persist()
|
140 |
+
return db
|
141 |
+
|
142 |
+
def set_custom_prompt_condense():
|
143 |
+
_template = """Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, in its original language.
|
144 |
+
|
145 |
+
Chat History:
|
146 |
+
{chat_history}
|
147 |
+
Follow Up Input: {question}
|
148 |
+
Standalone question:"""
|
149 |
+
CONDENSE_QUESTION_PROMPT = PromptTemplate.from_template(_template)
|
150 |
+
return CONDENSE_QUESTION_PROMPT
|
151 |
+
|
152 |
+
def set_custom_prompt():
|
153 |
+
"""
|
154 |
+
Prompt template for retrieval for each vectorstore
|
155 |
+
"""
|
156 |
+
|
157 |
+
|
158 |
+
prompt_template = """<Instructions>
|
159 |
+
Important:
|
160 |
+
Answer with the facts listed in the list of sources below. If there isn't enough information below, say you don't know.
|
161 |
+
If asking a clarifying question to the user would help, ask the question.
|
162 |
+
ALWAYS return a "SOURCES" part in your answer, except for small-talk conversations.
|
163 |
+
|
164 |
+
Question: {question}
|
165 |
+
|
166 |
+
{context}
|
167 |
+
|
168 |
+
|
169 |
+
Question: {question}
|
170 |
+
Helpful Answer:
|
171 |
+
|
172 |
+
---------------------------
|
173 |
+
---------------------------
|
174 |
+
Sources:
|
175 |
+
"""
|
176 |
+
|
177 |
+
prompt = PromptTemplate(template=prompt_template, input_variables=["context", "question"])
|
178 |
+
return prompt
|
179 |
+
|
180 |
+
def create_chain(llm, prompt, CONDENSE_QUESTION_PROMPT, db):
|
181 |
+
"""
|
182 |
+
Creates a Retrieval Question-Answering (QA) chain using a given language model, prompt, and database.
|
183 |
+
|
184 |
+
This function initializes a ConversationalRetrievalChain object with a specific chain type and configurations,
|
185 |
+
and returns this chain. The retriever is set up to return the top 3 results (k=3).
|
186 |
+
|
187 |
+
Args:
|
188 |
+
llm (any): The language model to be used in the RetrievalQA.
|
189 |
+
prompt (str): The prompt to be used in the chain type.
|
190 |
+
db (any): The database to be used as the
|
191 |
+
retriever.
|
192 |
+
|
193 |
+
Returns:
|
194 |
+
ConversationalRetrievalChain: The initialized conversational chain.
|
195 |
+
"""
|
196 |
+
memory = ConversationTokenBufferMemory(llm=llm, memory_key="chat_history", return_messages=True, input_key='question', max_token_limit=1000)
|
197 |
+
chain = ConversationalRetrievalChain.from_llm(
|
198 |
+
llm=llm,
|
199 |
+
chain_type="stuff",
|
200 |
+
retriever=db.as_retriever(search_kwargs={"k": 3}),
|
201 |
+
return_source_documents=True,
|
202 |
+
combine_docs_chain_kwargs={"prompt": prompt},
|
203 |
+
condense_question_prompt=CONDENSE_QUESTION_PROMPT,
|
204 |
+
memory=memory,
|
205 |
+
)
|
206 |
+
return chain
|
207 |
+
|
208 |
+
def create_retrieval_qa_bot():
|
209 |
+
if not os.path.exists(persist_dir):
|
210 |
+
raise FileNotFoundError(f"No directory found at {persist_dir}")
|
211 |
+
|
212 |
+
try:
|
213 |
+
llm = load_model() # Assuming this function exists and works as expected
|
214 |
+
except Exception as e:
|
215 |
+
raise Exception(f"Failed to load model: {str(e)}")
|
216 |
+
|
217 |
+
try:
|
218 |
+
prompt = set_custom_prompt() # Assuming this function exists and works as expected
|
219 |
+
except Exception as e:
|
220 |
+
raise Exception(f"Failed to get prompt: {str(e)}")
|
221 |
+
|
222 |
+
try:
|
223 |
+
CONDENSE_QUESTION_PROMPT = set_custom_prompt_condense() # Assuming this function exists and works as expected
|
224 |
+
except Exception as e:
|
225 |
+
raise Exception(f"Failed to get condense prompt: {str(e)}")
|
226 |
+
|
227 |
+
try:
|
228 |
+
db = create_vector_database() # Assuming this function exists and works as expected
|
229 |
+
except Exception as e:
|
230 |
+
raise Exception(f"Failed to get database: {str(e)}")
|
231 |
+
|
232 |
+
try:
|
233 |
+
qa = create_chain(
|
234 |
+
llm=llm, prompt=prompt,CONDENSE_QUESTION_PROMPT=CONDENSE_QUESTION_PROMPT, db=db
|
235 |
+
) # Assuming this function exists and works as expected
|
236 |
+
except Exception as e:
|
237 |
+
raise Exception(f"Failed to create retrieval QA chain: {str(e)}")
|
238 |
+
|
239 |
+
return qa
|
240 |
+
|
241 |
+
def retrieve_bot_answer(query):
|
242 |
+
"""
|
243 |
+
Retrieves the answer to a given query using a QA bot.
|
244 |
+
|
245 |
+
This function creates an instance of a QA bot, passes the query to it,
|
246 |
+
and returns the bot's response.
|
247 |
+
|
248 |
+
Args:
|
249 |
+
query (str): The question to be answered by the QA bot.
|
250 |
+
|
251 |
+
Returns:
|
252 |
+
dict: The QA bot's response, typically a dictionary with response details.
|
253 |
+
"""
|
254 |
+
qa_bot_instance = create_retrieval_qa_bot()
|
255 |
+
bot_response = qa_bot_instance({"query": query})
|
256 |
+
return bot_response
|
257 |
+
|
258 |
+
|
259 |
+
# from your_module import load_model, set_custom_prompt, set_custom_prompt_condense, create_vector_database, retrieve_bot_answer
|
260 |
+
|
261 |
+
def main():
|
262 |
+
st.title("Docuverse")
|
263 |
+
|
264 |
+
# Upload files
|
265 |
+
uploaded_files = st.file_uploader("Upload your documents", type=["pdf", "md", "txt", "csv", "py", "epub", "html", "ppt", "pptx", "doc", "docx", "odt", "ipynb"], accept_multiple_files=True)
|
266 |
+
|
267 |
+
if uploaded_files:
|
268 |
+
# Process uploaded files
|
269 |
+
for uploaded_file in uploaded_files:
|
270 |
+
st.write(f"Uploaded: {uploaded_file.name}")
|
271 |
+
|
272 |
+
st.write("Chat with the Document:")
|
273 |
+
query = st.text_input("Ask a question:")
|
274 |
+
|
275 |
+
if st.button("Get Answer"):
|
276 |
+
if query:
|
277 |
+
# Load model, set prompts, create vector database, and retrieve answer
|
278 |
+
try:
|
279 |
+
llm = load_model()
|
280 |
+
prompt = set_custom_prompt()
|
281 |
+
CONDENSE_QUESTION_PROMPT = set_custom_prompt_condense()
|
282 |
+
db = create_vector_database()
|
283 |
+
response = retrieve_bot_answer(query)
|
284 |
+
|
285 |
+
# Display bot response
|
286 |
+
st.write("Bot Response:")
|
287 |
+
st.write(response)
|
288 |
+
except Exception as e:
|
289 |
+
st.error(f"An error occurred: {str(e)}")
|
290 |
+
else:
|
291 |
+
st.warning("Please enter a question.")
|
292 |
+
|
293 |
+
if __name__ == "__main__":
|
294 |
+
main()
|