File size: 4,086 Bytes
220a370
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import MessagesPlaceholder
from langchain.chains import create_history_aware_retriever
from langchain_pinecone import PineconeVectorStore
from pinecone import Pinecone
from uuid import uuid4
import os
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI

class Rag:
    def __init__(self):
        self.embedding = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
        self.model = ChatOpenAI(
            base_url='https://api.opentyphoon.ai/v1',
            model='typhoon-v1.5-instruct',
            api_key="sk-clKR9DG6C5K02OeHUBU927gbzXmTCydV9PjFaTBXfRVAJLKC",
        )
        self.system_prompt = (
           """
            You are a helpful librarian named ThaiCodex. A user has requested book recommendations. 
            We have retrieved {num_docs} document(s) based on the user's request, listed below:

            {context}

            Please list ALL and ONLY the books that were found above in the order they were retrieved. 
            For each book, provide:
            1. The Title.
            2. A brief Content.
            3. A reference to locate the book (e.g., a link, university, organization, or other relevant details).

            Format your response as a numbered list, matching the order in which the documents were retrieved.

            Results:
            """
        )
        self.contextualize_q_system_prompt = (
            "Given a chat history and the latest user question "
            "which might 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."
        )

        self.contextualize_q_prompt = ChatPromptTemplate.from_messages(
            [
                ("system", self.contextualize_q_system_prompt),
                MessagesPlaceholder("chat_history"),
                ("human", "{input}"),
            ]
        )
        self.qa_prompt = ChatPromptTemplate.from_messages(
            [
                ("system", self.system_prompt),
                MessagesPlaceholder("chat_history"),
                ("human", "{input}"),
            ]
        )

        if not os.getenv("PINECONE_API_KEY"):
            os.environ["PINECONE_API_KEY"] = "ed681339-2270-4f85-b416-a372e857827b"
            pinecone_api_key = os.environ.get("PINECONE_API_KEY")
            pc = Pinecone(api_key=pinecone_api_key)

        index_name = "thaicodex" 
        index = pc.Index(index_name)
        self.vectorstore = PineconeVectorStore(index=index, embedding=self.embedding)

    def storeDocumentsInVectorstore(self, documents):
        uuids = [str(uuid4()) for _ in range(len(documents))]
        self.vectorstore.add_documents(documents=documents, ids=uuids)
    
    def createRagChain(self):
        self.question_answer_chain = create_stuff_documents_chain(self.model, self.qa_prompt)
        self.history_aware_retriever = create_history_aware_retriever(self.model, self.vectorstore.as_retriever(), self.contextualize_q_prompt)
        self.rag_chain = create_retrieval_chain(self.history_aware_retriever, self.question_answer_chain)

    def generateResponse(self, question, chat_history):
        retrieved_docs = self.vectorstore.as_retriever().get_relevant_documents(question)
        num_docs = len(retrieved_docs)

        docs = "\n\n".join([
            f"{i+1}. Title: {doc.metadata.get('source')}\nContent: {doc.page_content}"
            for i, doc in enumerate(retrieved_docs)
        ])
        print(num_docs)
        print(docs)
        ai_msg = self.rag_chain.invoke({
            "context": docs,
            "num_docs": num_docs,
            "input": question,
            "chat_history": chat_history
        })
        return ai_msg