microhum commited on
Commit
d1d1d6a
·
1 Parent(s): 7635282
Files changed (10) hide show
  1. .gitignore +4 -0
  2. Dockerfile +19 -0
  3. app.py +46 -0
  4. main.py +47 -0
  5. poetry.lock +0 -0
  6. pyproject.toml +22 -0
  7. rag.py +86 -0
  8. requirements.txt +11 -0
  9. retriever.py +23 -0
  10. storePDF.py +58 -0
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ venv
2
+ __pycache__
3
+ files
4
+ .env
Dockerfile ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ COPY ./pyproject.toml /code/pyproject.toml
4
+ RUN pip install --no-cache-dir --upgrade .
5
+
6
+ # Set home to the user's home directory
7
+ RUN useradd -m -u 1000 user
8
+ USER user
9
+ ENV HOME=/home/user \
10
+ PATH=/home/user/.local/bin:$PATH
11
+
12
+ WORKDIR $HOME/app
13
+
14
+ COPY --chown=user . $HOME/app
15
+
16
+ EXPOSE 8000
17
+ EXPOSE 7860
18
+
19
+ CMD ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port 8000 & python3 app.py"]
app.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_community.document_loaders import PyPDFLoader
2
+ from langchain_core.messages import AIMessage, HumanMessage
3
+ from pydantic import BaseModel
4
+ import time
5
+ import gradio as gr
6
+ import requests
7
+ from typing import Generator
8
+
9
+ chat_history = []
10
+
11
+ def generate_response(chat_input: str, bot_message: str) -> Generator[str, str, str] | str:
12
+ url = "http://127.0.0.1:8000/generatechat/"
13
+ payload = {
14
+ 'question': chat_input,
15
+ }
16
+ headers = {
17
+ 'Content-Type': 'application/json'
18
+ }
19
+
20
+ response = requests.post(url, json=payload, headers=headers)
21
+ if response.status_code == 200:
22
+ data = response.json()
23
+ answer = data['response']['answer']
24
+ print("Success:", response.json())
25
+
26
+ # Get a typewriting animation response
27
+ partial_response = ""
28
+ for char in answer:
29
+ partial_response += char
30
+ yield partial_response
31
+ time.sleep(0.005)
32
+ else:
33
+ print("Error:", response.status_code, response.text)
34
+ return f"Error: {response.status_code}, {response.text}"
35
+
36
+ with gr.Blocks() as demo:
37
+ with gr.Column():
38
+
39
+ chatbot = gr.ChatInterface(
40
+ fn=generate_response,
41
+ title="AskmeAboutRAG Chat",
42
+ description="RAG model for asking about RAG",
43
+ )
44
+
45
+ if __name__ == "__main__":
46
+ demo.launch()
main.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.messages import AIMessage, HumanMessage
2
+ from fastapi import FastAPI
3
+ from langchain_pinecone.vectorstores import Pinecone
4
+ from pydantic import BaseModel
5
+ from rag import Rag
6
+ from retriever import AskMeAboutRagRetriever
7
+ from langchain_huggingface import HuggingFaceEmbeddings
8
+ from dotenv import load_dotenv
9
+ import os
10
+
11
+ load_dotenv()
12
+
13
+ api_key=os.getenv('PINECONE_KEY')
14
+ index_name="askmeaboutrag"
15
+
16
+ vectorstore = Pinecone(pinecone_api_key=api_key, index_name=index_name, embedding=HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2"))
17
+ retriever = AskMeAboutRagRetriever(vectorstore)
18
+ rag_llm = Rag(vectorstore, retriever);
19
+
20
+ rag_llm.createRagChain()
21
+
22
+ chat_history = []
23
+
24
+ class ChatInput(BaseModel):
25
+ question: str
26
+
27
+ app = FastAPI()
28
+
29
+ @app.get("/")
30
+ async def root():
31
+ return {"message": "Hello World"}
32
+
33
+ @app.post("/generatechat/")
34
+ async def generateResponse(chat_input: ChatInput):
35
+ ai_msg = rag_llm.generateResponse(chat_input.question, chat_history)
36
+ chat_history.extend(
37
+ [
38
+ HumanMessage(content=chat_input.question),
39
+ AIMessage(content=ai_msg["answer"]),
40
+ ]
41
+ )
42
+ return {"response": ai_msg}
43
+
44
+ if __name__ == "__main__":
45
+ import uvicorn
46
+ uvicorn.run(app, host="127.0.0.1", port=8000)
47
+ print("Server is running")
poetry.lock ADDED
The diff for this file is too large to render. See raw diff
 
pyproject.toml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [tool.poetry]
2
+ name = "askmeaboutrag"
3
+ version = "0.1.0"
4
+ description = "RAG model for asking about RAG"
5
+ authors = ["microhum, Beamlnwza, SupeemAFK, GGital"]
6
+ readme = "README.md"
7
+
8
+ [tool.poetry.dependencies]
9
+ python = "^3.11"
10
+ langchain="0.2.14"
11
+ langchain_community="0.2.12"
12
+ langchain_groq= "*"
13
+ langchain_huggingface = "*"
14
+ langchain_openai= "*"
15
+ langchain-pinecone= "*"
16
+ pypdf= "*"
17
+ fastapi= "*"
18
+ gradio = "^4.44.0"
19
+
20
+ [build-system]
21
+ requires = ["poetry-core"]
22
+ build-backend = "poetry.core.masonry.api"
rag.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.chains import create_retrieval_chain
2
+ from langchain.chains.combine_documents import create_stuff_documents_chain
3
+ from langchain_core.prompts import ChatPromptTemplate
4
+ from langchain_core.prompts import MessagesPlaceholder
5
+ from langchain.chains import create_history_aware_retriever
6
+ from langchain_pinecone.vectorstores import Pinecone
7
+ from uuid import uuid4
8
+ from langchain_groq import ChatGroq
9
+ from langchain.schema.retriever import BaseRetriever
10
+ from dotenv import load_dotenv
11
+ import os
12
+
13
+ load_dotenv()
14
+
15
+ class Rag:
16
+ def __init__(self, vectorstore: Pinecone, retriever: BaseRetriever):
17
+ self.model = ChatGroq(
18
+ model="llama-3.1-70b-versatile",
19
+ temperature=0,
20
+ max_tokens=None,
21
+ timeout=None,
22
+ max_retries=2,
23
+ api_key=os.getenv('GROQ_API_KEY')
24
+ )
25
+ self.system_prompt = (
26
+ """
27
+ You are "Ask me about RAG", a knowledgeable librarian specializing in RAG research papers. A user has requested assistance with research paper recommendations.
28
+
29
+ We have retrieved {num_docs} research paper(s) related to the user's query. These papers are listed below:
30
+
31
+ {context}
32
+
33
+ Please provide detailed information for EACH research paper retrieved, including:
34
+ 1. The title of the research paper.
35
+ 2. A concise summary of its content, highlighting key findings or topics covered.
36
+ 3. Relevant details for locating or referencing the paper (e.g., a link, DOI, university, journal name, or organization).
37
+
38
+ Format your response as a numbered list, preserving the order in which the papers were retrieved.
39
+ """
40
+ )
41
+ self.contextualize_q_system_prompt = (
42
+ "Given a chat history and the latest user question "
43
+ "which might reference context in the chat history, "
44
+ "formulate a standalone question which can be understood "
45
+ "without the chat history. Do NOT answer the question, "
46
+ "just reformulate it if needed and otherwise return it as is."
47
+ )
48
+
49
+ self.contextualize_q_prompt = ChatPromptTemplate.from_messages(
50
+ [
51
+ ("system", self.contextualize_q_system_prompt),
52
+ MessagesPlaceholder("chat_history"),
53
+ ("human", "{input}"),
54
+ ]
55
+ )
56
+ self.qa_prompt = ChatPromptTemplate.from_messages(
57
+ [
58
+ ("system", self.system_prompt),
59
+ MessagesPlaceholder("chat_history"),
60
+ ("human", "{input}"),
61
+ ]
62
+ )
63
+
64
+ self.vectorstore = vectorstore
65
+ self.retriever = retriever
66
+
67
+ def storeDocumentsInVectorstore(self, documents):
68
+ uuids = [str(uuid4()) for _ in range(len(documents))]
69
+ self.vectorstore.add_documents(documents=documents, ids=uuids)
70
+
71
+ def createRagChain(self):
72
+ self.question_answer_chain = create_stuff_documents_chain(self.model, self.qa_prompt)
73
+ self.history_aware_retriever = create_history_aware_retriever(self.model, self.retriever, self.contextualize_q_prompt)
74
+ self.rag_chain = create_retrieval_chain(self.history_aware_retriever, self.question_answer_chain)
75
+
76
+ def generateResponse(self, question, chat_history):
77
+ retrieved_docs = self.vectorstore.as_retriever().get_relevant_documents(question)
78
+ num_docs = len(retrieved_docs)
79
+
80
+ ai_msg = self.rag_chain.invoke({
81
+ "num_docs": num_docs,
82
+ "input": question,
83
+ "chat_history": chat_history
84
+ })
85
+ return ai_msg
86
+
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ langchain==0.2.14
2
+ langchain_community==0.2.12
3
+ langchain_ollama==0.1.1
4
+ langchain_groq
5
+ langchain_huggingface
6
+ langchain_openai
7
+ langchain_pinecone
8
+ pypdf
9
+ chromadb
10
+ ollama
11
+ fastapi
retriever.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.schema.retriever import BaseRetriever
2
+ from langchain_core.callbacks import CallbackManagerForRetrieverRun
3
+ from langchain_pinecone.vectorstores import Pinecone
4
+ from langchain.schema import Document
5
+ from pydantic import PrivateAttr
6
+
7
+ class AskMeAboutRagRetriever(BaseRetriever):
8
+ vectorstore: Pinecone = PrivateAttr()
9
+
10
+ def __init__(self, vectorstore: Pinecone, **data):
11
+ super().__init__(**data)
12
+ self.vectorstore = vectorstore
13
+
14
+ def _get_relevant_documents(self, query: str, *, run_manager: CallbackManagerForRetrieverRun):
15
+ retrieved_docs = self.vectorstore.as_retriever().get_relevant_documents(query)
16
+ docs = [
17
+ Document(
18
+ page_content= str(i+1) + ".)" + "Title = " + "(" + doc.metadata.get('title') + ")" + " " + "Content = " + "(" + doc.page_content + ")",
19
+ metadata={"title": doc.metadata.get('title')}
20
+ )
21
+ for i, doc in enumerate(retrieved_docs)
22
+ ]
23
+ return docs
storePDF.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import fitz
2
+ import os
3
+ from sentence_transformers import SentenceTransformer
4
+ from pinecone import Pinecone
5
+ from dotenv import load_dotenv
6
+ import os
7
+
8
+ load_dotenv()
9
+
10
+ pc = Pinecone(api_key=os.getenv('PINECONE_KEY'))
11
+ index_name = "askmeaboutrag"
12
+ index = pc.Index(index_name)
13
+
14
+ model = SentenceTransformer('all-MiniLM-L6-v2')
15
+
16
+ def extract_pages_from_pdf(pdf_path):
17
+ doc = fitz.open(pdf_path)
18
+ pages = []
19
+ for page_num in range(len(doc)):
20
+ page = doc.load_page(page_num)
21
+ text = page.get_text("text")
22
+ pages.append(text)
23
+ return pages
24
+
25
+ def store_document_in_pinecone(document_id, pages, title, model):
26
+ for page_number, page_text in enumerate(pages):
27
+ embedding = model.encode(page_text)
28
+ index.upsert(
29
+ vectors=[
30
+ {
31
+ "id": f'{document_id}_page_{page_number}',
32
+ "values": embedding,
33
+ "metadata": {
34
+ "document_id": document_id,
35
+ "page_number": page_number,
36
+ "text": page_text,
37
+ "title": title,
38
+ }
39
+ }
40
+ ],
41
+ )
42
+ print(f"Stored {len(pages)} pages for document: {document_id}")
43
+
44
+ def process_pdfs_in_folder(folder_path):
45
+ for i, filename in enumerate(os.listdir(folder_path)):
46
+ if filename.endswith('.pdf'):
47
+ pdf_path = os.path.join(folder_path, filename)
48
+ document_id = str(i+1)
49
+ print(f"Processing {filename} with document_id: {document_id}")
50
+
51
+ pages = extract_pages_from_pdf(pdf_path)
52
+ file_name_without_extension = os.path.splitext(filename)[0]
53
+
54
+ store_document_in_pinecone(document_id, pages, file_name_without_extension, model)
55
+ print("Stored Completed")
56
+
57
+ folder_path = 'files'
58
+ process_pdfs_in_folder(folder_path)