Spaces:
Sleeping
Sleeping
init
Browse files- .gitignore +4 -0
- Dockerfile +19 -0
- app.py +46 -0
- main.py +47 -0
- poetry.lock +0 -0
- pyproject.toml +22 -0
- rag.py +86 -0
- requirements.txt +11 -0
- retriever.py +23 -0
- 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)
|