File size: 6,076 Bytes
fe1fc2e
467c73a
3c4de7d
bd26a11
 
 
 
 
8356c3c
bd26a11
 
 
467c73a
fe1fc2e
644332a
8356c3c
dfb65c1
2390875
fe1fc2e
8356c3c
ccb7696
fe1fc2e
 
 
 
 
 
2390875
 
 
 
 
8356c3c
3c4de7d
 
 
 
 
 
 
 
8356c3c
3c4de7d
2c3a2a1
3c4de7d
fe1fc2e
3c4de7d
dfb65c1
 
fe1fc2e
3c4de7d
 
 
 
 
 
 
 
 
fd0bd52
3c4de7d
1eac1eb
 
 
 
 
fe1fc2e
3c4de7d
fe1fc2e
8356c3c
1eac1eb
8356c3c
 
 
 
 
 
 
 
 
fe1fc2e
3c4de7d
 
 
 
fe1fc2e
8356c3c
fe1fc2e
3c4de7d
fe1fc2e
3c4de7d
 
 
 
 
 
 
fe1fc2e
3c4de7d
fe1fc2e
3c4de7d
 
fe1fc2e
5bd324a
 
 
 
 
 
 
 
 
 
4e6d28b
 
c923605
 
 
1eac1eb
 
05127d7
 
 
 
 
 
 
 
 
 
c923605
05127d7
1eac1eb
 
 
61ebf90
3fbaf5c
 
1eac1eb
 
 
237d231
1eac1eb
fe1fc2e
 
 
 
 
 
4e6d28b
237d231
fe1fc2e
237d231
4e6d28b
237d231
 
fe1fc2e
4e6d28b
fe1fc2e
8356c3c
 
 
fe1fc2e
4e6d28b
237d231
fe1fc2e
 
96078d7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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

script_dir = os.path.dirname(os.path.abspath(__file__))
data_path = os.path.join(script_dir, "data/")
model_path = os.path.join(script_dir, 'qwen2-0_5b-instruct-q4_0.gguf')
store = {}

model_name = "sentence-transformers/all-mpnet-base-v2"
model_kwargs = {'device': 'cpu'}
encode_kwargs = {'normalize_embeddings': True}

hf = HuggingFaceEmbeddings(
    model_name=model_name,
    model_kwargs=model_kwargs,
    encode_kwargs=encode_kwargs
)

def get_vectorstore(text_chunks):
    model_name = "sentence-transformers/all-mpnet-base-v2"
    model_kwargs = {'device': 'cpu'}
    encode_kwargs = {'normalize_embeddings': True}
    hf = HuggingFaceEmbeddings(
        model_name=model_name,
        model_kwargs=model_kwargs,
        encode_kwargs=encode_kwargs
    )

    vectorstore = Chroma.from_documents(documents=text_chunks, embedding=hf, persist_directory="docs/chroma/")
    return vectorstore

def get_pdf_text(pdf_docs):
    document_loader = DirectoryLoader(pdf_docs)
    return document_loader.load()

def get_text_chunks(text):
    text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
        separator="\n",
        chunk_size=1000,
        chunk_overlap=200,
        length_function=len
    )
    chunks = text_splitter.split_text(text)
    return chunks

def create_conversational_rag_chain(vectorstore):
    
    script_dir = os.path.dirname(os.path.abspath(__file__))
    model_path = os.path.join(script_dir, 'qwen2-0_5b-instruct-q4_0.gguf')
    
    retriever = vectorstore.as_retriever(search_type='mmr', search_kwargs={"k": 7})

    callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])

    llm = llamacpp.LlamaCpp(
        model_path=os.path.join(model_path),
        n_gpu_layers=1,
        temperature=0.1,
        top_p=0.9,
        n_ctx=22000,
        max_tokens=200,
        repeat_penalty=1.7,
        callback_manager=callback_manager,
        verbose=False,
    )

    contextualize_q_system_prompt = """Given a context, chat history and the latest user question
    which maybe reference context in the chat history, 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."""

    ha_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_system_prompt)

    qa_system_prompt = """You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Be as informative as possible, be polite and formal.\n{context}"""

    qa_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", qa_system_prompt),
            MessagesPlaceholder("chat_history"),
            ("human", "{input}"),
        ]
    )

    question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)

    rag_chain = create_retrieval_chain(ha_retriever, question_answer_chain)
    msgs = StreamlitChatMessageHistory(key="special_app_key")

    conversation_chain = RunnableWithMessageHistory(
        rag_chain,
        lambda session_id: msgs,
        input_messages_key="input",
        history_messages_key="chat_history",
        output_messages_key="answer",
    )
    return conversation_chain

def main():
    """Main function for the Streamlit app."""
    # Initialize chat history if not already present in session state

    documents = []
    
    script_dir = os.path.dirname(os.path.abspath(__file__))
    data_path = os.path.join(script_dir, "data/")
    for filename in os.listdir(data_path):

    if filename.endswith('.txt'):

        file_path = os.path.join(data_path, filename)

        documents = TextLoader(file_path).load()

        documents.extend(documents)
    
    
    docs = split_docs(documents, 350, 40)

    
    
    
    
    

    vectorstore = get_vectorstore(docs)
    
    msgs = st.session_state.get("chat_history", StreamlitChatMessageHistory(key="special_app_key"))
    chain_with_history = create_conversational_rag_chain(vectorstore)

    st.title("Conversational RAG Chatbot")

    if prompt := st.chat_input():
        st.chat_message("human").write(prompt)

        # Prepare the input dictionary with the correct keys
        input_dict = {"input": prompt, "chat_history": msgs.messages}
        config = {"configurable": {"session_id": "any"}}

        # Process user input and handle response
        response = chain_with_history.invoke(input_dict, config)
        st.chat_message("ai").write(response["answer"])

        # Display retrieved documents (if any and present in response)
        if "docs" in response and response["documents"]:
            for index, doc in enumerate(response["documents"]):
                with st.expander(f"Document {index + 1}"):
                    st.write(doc)

    # Update chat history in session state
    st.session_state["chat_history"] = msgs

if __name__ == "__main__":
    main()