File size: 3,358 Bytes
d0896fa
 
 
 
5d796ae
d0896fa
 
 
d5275a1
5d796ae
d0896fa
d5275a1
d0896fa
02e3818
5d796ae
d0896fa
02e3818
 
 
d5275a1
02e3818
 
 
 
 
 
 
 
 
 
 
d0896fa
 
 
 
 
 
 
d5275a1
d0896fa
d5275a1
cc2eb6d
 
 
 
 
 
 
d5275a1
cc2eb6d
 
1cf02bf
 
cc2eb6d
1cf02bf
 
cc2eb6d
 
d5275a1
cc2eb6d
 
02e3818
cc2eb6d
1cf02bf
cc2eb6d
 
 
d5275a1
5d796ae
d0896fa
 
5d796ae
d0896fa
 
 
 
d5275a1
 
02e3818
 
 
 
 
d0896fa
 
 
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
from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from langchain.memory import ConversationBufferMemory
from langchain_groq import ChatGroq
from langchain.chains import ConversationalRetrievalChain
from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
from config import VECTOR_DIR, EMBED_MODEL, GROQ_API_KEY, GROQ_MODEL

# ---- Memory for our rag system----
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

#we are going to reset memory if new pdf uplaod 
def reset_memory():
    """Clear previous conversation memory (use after ingesting a new PDF)"""
    memory.clear()

def normalize_question(question: str) -> str:
    """
    Ensure the question starts with 'What' if not already starting
    with Who/When/Where/Why/How/What/tell me about/summarize.
    """
    question = question.strip()
    if question == "":
        return "What?"
    
    first_word = question.split()[0].lower()
    wh_words = ["what", "who", "when", "where", "why", "how","tell me about"]
    if first_word not in wh_words:
        question = "What " + question[0].lower() + question[1:] if len(question) > 0 else "What?"
    return question

def build_chain():
    embeddings = HuggingFaceEmbeddings(model_name=EMBED_MODEL)
    vectordb = FAISS.load_local(VECTOR_DIR, embeddings, allow_dangerous_deserialization=True)
    retriever = vectordb.as_retriever(search_kwargs={"k": 3})

    llm = ChatGroq(model=GROQ_MODEL, api_key=GROQ_API_KEY, temperature=0.1)

    # ---- System + Human Prompt with diverse prompt engineering----
    chat_prompt = ChatPromptTemplate.from_messages([
    #this is a system message
    SystemMessagePromptTemplate.from_template(
        "You are a highly knowledgeable financial expert assistant. "
        "Use the context provided to answer the user question accurately. "
        "Always provide the answer in clear, concise sentences. "
        "Cite the reference (page number or section title) from the PDF where the information was found. "
        "If the answer is not present in the context, say 'The information is not available in the provided document.'"
    ),
    #this is a human message
    HumanMessagePromptTemplate.from_template(
        """Context:
{context}

User Question:
{question}

Instructions:
- Answer the question clearly and concisely.
- Always start the answer naturally (What, Who, When, Where, Why, How,tell me about ,summarize) depending on the question.
- Include the reference where the information is found in the format: Reference: page:X or section name.
- If the information is not in the context, state clearly that it is not available.

Answer:
"""
    )
])

# this fuction make our orginal chain 
    chain = ConversationalRetrievalChain.from_llm(
        llm=llm,
        retriever=retriever,
        memory=memory,
        combine_docs_chain_kwargs={"prompt": chat_prompt}
    )
    return chain

# this method responsible for question answering 

def answer(user_question: str) -> str:
    """
    Normalize the user's question and ask the RAG chain.
    """
    question = normalize_question(user_question)
    chain = build_chain()
    result = chain.invoke({"question": question})
    return result.get("answer") or result.get("result") or "No answer."