ArturG9's picture
Update app.py
4bf5fc4 verified
raw
history blame
7.04 kB
import os
import streamlit as st
from dotenv import load_dotenv
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.llms import llamacpp
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.callbacks import CallbackManager, StreamingStdOutCallbackHandler
from langchain.chains import create_history_aware_retriever, create_retrieval_chain, ConversationalRetrievalChain
from langchain.document_loaders import TextLoader
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_community.chat_message_histories.streamlit import StreamlitChatMessageHistory
from langchain.prompts import PromptTemplate
from langchain.vectorstores import Chroma
from utills import load_txt_documents, split_docs, load_uploaded_documents, retriever_from_chroma
from langchain.text_splitter import TokenTextSplitter, RecursiveCharacterTextSplitter
from langchain_community.document_loaders.directory import DirectoryLoader
from HTML_templates import css, bot_template, user_template
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
lang_api_key = os.getenv("lang_api_key")
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.langchain.plus"
os.environ["LANGCHAIN_API_KEY"] = lang_api_key
os.environ["LANGCHAIN_PROJECT"] = "Chat with multiple PDFs"
def create_retriever_from_chroma(vectorstore_path="docs/chroma/", search_type='mmr', k=7, chunk_size=250, chunk_overlap=20):
data_path = "data"
model_name = "Alibaba-NLP/gte-base-en-v1.5"
model_kwargs = {'device': 'cpu',
"trust_remote_code" : 'True'}
encode_kwargs = {'normalize_embeddings': True}
embeddings = HuggingFaceEmbeddings(
model_name=model_name,
model_kwargs=model_kwargs,
encode_kwargs=encode_kwargs
)
llm = llamacpp.LlamaCpp(
model_path='qwen2-0_5b-instruct-q4_0.gguf',
n_gpu_layers=0,
temperature=0.0,
top_p=0.9,
n_ctx=22000,
n_batch=2000,
max_tokens=200,
repeat_penalty=1.7,
last_n_tokens_size = 1500,
# callback_manager=callback_manager,
verbose=False,
)
# Check if vectorstore exists
if os.path.exists(vectorstore_path) and os.listdir(vectorstore_path):
# Load the existing vectorstore
vectorstore = Chroma(persist_directory=vectorstore_path,embedding_function=embeddings)
else:
# Load documents from the specified data path
documents = []
for filename in os.listdir(data_path):
if filename.endswith('.txt'):
file_path = os.path.join(data_path, filename)
loaded_docs = TextLoader(file_path).load()
documents.extend(loaded_docs)
# Split documents into chunks
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
split_docs = text_splitter.split_documents(documents)
# Ensure the directory for storing vectorstore exists
if not os.path.exists(vectorstore_path):
os.makedirs(vectorstore_path)
# Create the vectorstore
vectorstore = Chroma.from_documents(
documents=split_docs, embedding=embeddings, persist_directory=vectorstore_path
)
retriever=vectorstore.as_retriever(search_type='mmr', search_kwargs={"k": 7})
contextualize_q_system_prompt = """If the question is not clear, given a chat history and the latest user question
which maybe reference context, formulate a standalone question,
which can be understood without the chat history. Do NOT answer the question,
just reformulate it if needed and otherwise return it as is."""
contextualize_q_prompt = ChatPromptTemplate.from_messages(
[
("system", contextualize_q_system_prompt),
MessagesPlaceholder("chat_history"),
("human", "{question}"),
]
)
ha_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)
return ha_retriever
def main():
st.set_page_config(page_title="Chat with multiple PDFs",
page_icon=":books:")
st.write(css, unsafe_allow_html=True)
st.header("Chat with multiple PDFs :books:")
st.markdown("Hi, I am Qwen, chat mmodel, based on respublic of Lithuania law document. Write you question and press enter to start chat.")
retriever = create_retriever_from_chroma(vectorstore_path="docs/chroma/", search_type='mmr', k=9, chunk_size=250, chunk_overlap=20)
user_question = st.text_input("Ask a question about your documents:")
if "messages" not in st.session_state:
st.session_state["messages"] = [
{"role": "assistant", "content": "Hi, I'm a chatbot who is based on lithuanian law documents. How can I help you?"}
]
for msg in st.session_state.messages:
st.chat_message(msg["role"]).write(msg["content"])
if user_question:
handle_userinput(user_question,retriever)
def handle_userinput(user_question,retriever):
st.session_state.messages.append({"role": "user", "content": user_question})
st.chat_message("user").write(user_question)
docs = retriever.invoke({"question": user_question, "chat_history": st.session_state.messages})
with st.sidebar:
st.subheader("Your documents")
with st.spinner("Processing"):
for doc in docs:
st.write(f"Document: {doc}")
doc_txt = [doc.page_content for doc in docs]
rag_chain = create_conversational_rag_chain(retriever)
response = rag_chain.invoke({"context": doc_txt, "question": user_question})
st.session_state.messages.append({"role": "assistant", "content": response})
st.chat_message("assistant").write(response)
def create_conversational_rag_chain(retriever):
model_path = ('qwen2-0_5b-instruct-q4_0.gguf')
callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])
llm = llamacpp.LlamaCpp(
model_path = "qwen2-0_5b-instruct-q4_0.gguf",
n_gpu_layers=0,
temperature=0.4,
top_p=0.9,
n_ctx=22000,
n_batch=2000,
max_tokens=200,
repeat_penalty=1.7,
last_n_tokens_size = 200,
# callback_manager=callback_manager,
verbose=False,
)
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
rag_chain = prompt | llm | StrOutputParser()
return rag_chain
if __name__ == "__main__":
main()