Spaces:
Sleeping
Sleeping
Upload 2 files
Browse filesnew files commint
- app.py +169 -0
- requirements.txt +10 -0
app.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import PyPDF2
|
| 3 |
+
import os
|
| 4 |
+
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
| 5 |
+
from sentence_transformers import SentenceTransformer
|
| 6 |
+
from langchain.vectorstores import Chroma
|
| 7 |
+
from langchain_community.embeddings import SentenceTransformerEmbeddings
|
| 8 |
+
from langchain_groq import ChatGroq
|
| 9 |
+
from langchain.chains import RetrievalQA
|
| 10 |
+
from langchain.prompts import PromptTemplate
|
| 11 |
+
|
| 12 |
+
# Initialize global variables for RAG components
|
| 13 |
+
rag_chain = None
|
| 14 |
+
vector_store = None
|
| 15 |
+
llm = None
|
| 16 |
+
embedding_model = None
|
| 17 |
+
embedding_function = None
|
| 18 |
+
|
| 19 |
+
# Set your Groq API key here - Read from environment variable
|
| 20 |
+
# os.environ["GROQ_API_KEY"] = "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" # Removed hardcoded key
|
| 21 |
+
groq_api_key = os.environ.get("GROQ_API_KEY")
|
| 22 |
+
|
| 23 |
+
def build_rag_from_pdf(pdf_path):
|
| 24 |
+
"""Builds the RAG chain from an uploaded PDF."""
|
| 25 |
+
global rag_chain, vector_store, llm, embedding_model, embedding_function
|
| 26 |
+
|
| 27 |
+
if not groq_api_key:
|
| 28 |
+
error_message = "Groq API key not set. Please set the GROQ_API_KEY environment variable."
|
| 29 |
+
print(error_message)
|
| 30 |
+
return False, error_message
|
| 31 |
+
|
| 32 |
+
pdf_text = ""
|
| 33 |
+
try:
|
| 34 |
+
with open(pdf_path, 'rb') as file:
|
| 35 |
+
reader = PyPDF2.PdfReader(file)
|
| 36 |
+
for page in reader.pages:
|
| 37 |
+
pdf_text += page.extract_text()
|
| 38 |
+
print("PDF text extracted successfully.")
|
| 39 |
+
except FileNotFoundError:
|
| 40 |
+
error_message = f"Error: The file '{pdf_path}' was not found."
|
| 41 |
+
print(error_message)
|
| 42 |
+
return False, error_message
|
| 43 |
+
except Exception as e:
|
| 44 |
+
error_message = f"An error occurred during PDF extraction: {e}"
|
| 45 |
+
print(error_message)
|
| 46 |
+
return False, error_message
|
| 47 |
+
|
| 48 |
+
if not pdf_text:
|
| 49 |
+
error_message = "Extracted text is empty."
|
| 50 |
+
print(error_message)
|
| 51 |
+
return False, error_message
|
| 52 |
+
|
| 53 |
+
# Split text into chunks
|
| 54 |
+
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
|
| 55 |
+
text_chunks = text_splitter.split_text(pdf_text)
|
| 56 |
+
print(f"Split PDF text into {len(text_chunks)} chunks.")
|
| 57 |
+
|
| 58 |
+
if not text_chunks:
|
| 59 |
+
error_message = "No text chunks created."
|
| 60 |
+
print(error_message)
|
| 61 |
+
return False, error_message
|
| 62 |
+
|
| 63 |
+
# Create embeddings
|
| 64 |
+
try:
|
| 65 |
+
embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
|
| 66 |
+
embeddings = embedding_model.encode(text_chunks)
|
| 67 |
+
print(f"Generated embeddings for {len(text_chunks)} text chunks.")
|
| 68 |
+
except Exception as e:
|
| 69 |
+
error_message = f"An error occurred during embedding generation: {e}"
|
| 70 |
+
print(error_message)
|
| 71 |
+
return False, error_message
|
| 72 |
+
|
| 73 |
+
# Set up vector store
|
| 74 |
+
try:
|
| 75 |
+
embedding_function = SentenceTransformerEmbeddings(model_name='all-MiniLM-L6-v2')
|
| 76 |
+
vector_store = Chroma.from_texts(texts=text_chunks, embedding=embedding_function)
|
| 77 |
+
print("Chroma vector store created successfully.")
|
| 78 |
+
except Exception as e:
|
| 79 |
+
error_message = f"An error occurred during vector store creation: {e}"
|
| 80 |
+
print(error_message)
|
| 81 |
+
return False, error_message
|
| 82 |
+
|
| 83 |
+
# Initialize LLM
|
| 84 |
+
try:
|
| 85 |
+
llm = ChatGroq(model_name="openai/gpt-oss-20b", groq_api_key=groq_api_key) # Pass API key
|
| 86 |
+
print("Groq language model set up successfully.")
|
| 87 |
+
except Exception as e:
|
| 88 |
+
error_message = f"An error occurred during LLM setup: {e}"
|
| 89 |
+
print(error_message)
|
| 90 |
+
return False, error_message
|
| 91 |
+
|
| 92 |
+
# Build RAG chain
|
| 93 |
+
try:
|
| 94 |
+
template = """Use the following pieces of context to answer queries about the provided document efficiently. If you don't know the answer, just say that you don't know, don't try to make up an answer.
|
| 95 |
+
|
| 96 |
+
{context}
|
| 97 |
+
|
| 98 |
+
Question: {question}
|
| 99 |
+
Helpful Answer:"""
|
| 100 |
+
QA_CHAIN_PROMPT = PromptTemplate.from_template(template)
|
| 101 |
+
|
| 102 |
+
rag_chain = RetrievalQA.from_chain_type(
|
| 103 |
+
llm=llm,
|
| 104 |
+
chain_type="stuff",
|
| 105 |
+
retriever=vector_store.as_retriever(),
|
| 106 |
+
chain_type_kwargs={"prompt": QA_CHAIN_PROMPT}
|
| 107 |
+
)
|
| 108 |
+
print("RAG chain built successfully.")
|
| 109 |
+
return True, "Document processed. You can now ask questions."
|
| 110 |
+
except Exception as e:
|
| 111 |
+
error_message = f"An error occurred while building the RAG chain: {e}"
|
| 112 |
+
print(error_message)
|
| 113 |
+
rag_chain = None
|
| 114 |
+
return False, error_message
|
| 115 |
+
|
| 116 |
+
def chat_with_rag(message, history):
|
| 117 |
+
"""Handles chat interactions using the RAG chain."""
|
| 118 |
+
global rag_chain
|
| 119 |
+
print(f"chat_with_rag received history type: {type(history)}, content: {history}") # Debug print
|
| 120 |
+
if rag_chain is not None:
|
| 121 |
+
try:
|
| 122 |
+
response = rag_chain.invoke(message)
|
| 123 |
+
# Append message and response in the 'messages' format
|
| 124 |
+
history.append({"role": "user", "content": message})
|
| 125 |
+
history.append({"role": "assistant", "content": response['result']})
|
| 126 |
+
print(f"chat_with_rag returning history type: {type(history)}, content: {history}") # Debug print
|
| 127 |
+
return history
|
| 128 |
+
except Exception as e:
|
| 129 |
+
error_message = f"An error occurred while querying the RAG chain: {e}"
|
| 130 |
+
history.append({"role": "user", "content": message})
|
| 131 |
+
history.append({"role": "assistant", "content": error_message})
|
| 132 |
+
print(f"chat_with_rag returning history with error type: {type(history)}, content: {history}") # Debug print
|
| 133 |
+
return history
|
| 134 |
+
else:
|
| 135 |
+
error_message = "Please upload a document to start the chat."
|
| 136 |
+
history.append({"role": "user", "content": message})
|
| 137 |
+
history.append({"role": "assistant", "content": error_message})
|
| 138 |
+
print(f"chat_with_rag returning history with no RAG chain type: {type(history)}, content: {history}") # Debug print
|
| 139 |
+
return history
|
| 140 |
+
|
| 141 |
+
def process_file(file):
|
| 142 |
+
"""Processes the uploaded file and builds the RAG chain."""
|
| 143 |
+
if file is None:
|
| 144 |
+
print("process_file received None file.") # Debug print
|
| 145 |
+
return "Please upload a file.", None
|
| 146 |
+
print(f"Processing file: {file.name}") # Debug print
|
| 147 |
+
success, message = build_rag_from_pdf(file.name)
|
| 148 |
+
if success:
|
| 149 |
+
print("File processing successful, returning message and None for history.") # Debug print
|
| 150 |
+
# Return None for chatbot history to clear it on successful upload
|
| 151 |
+
return message, None
|
| 152 |
+
else:
|
| 153 |
+
print(f"File processing failed, returning message and empty list for history. Message: {message}") # Debug print
|
| 154 |
+
return message, []
|
| 155 |
+
|
| 156 |
+
# Define the Gradio interface
|
| 157 |
+
with gr.Blocks() as demo:
|
| 158 |
+
gr.Markdown("## RAG Chatbot with Document Upload")
|
| 159 |
+
file_upload = gr.File(label="Upload your document (PDF)")
|
| 160 |
+
output_message = gr.Textbox(label="Status")
|
| 161 |
+
chatbot = gr.Chatbot(type='messages') # Explicitly set type to 'messages'
|
| 162 |
+
msg = gr.Textbox(label="Your Question")
|
| 163 |
+
clear = gr.ClearButton([msg, chatbot])
|
| 164 |
+
|
| 165 |
+
file_upload.upload(process_file, inputs=[file_upload], outputs=[output_message, chatbot])
|
| 166 |
+
msg.submit(chat_with_rag, inputs=[msg, chatbot], outputs=[chatbot])
|
| 167 |
+
|
| 168 |
+
if __name__ == "__main__":
|
| 169 |
+
demo.launch(share=True)
|
requirements.txt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
langchain
|
| 2 |
+
pypdf2
|
| 3 |
+
groq
|
| 4 |
+
chromadb
|
| 5 |
+
langchain-groq
|
| 6 |
+
langchain-community
|
| 7 |
+
langchain-text-splitters
|
| 8 |
+
langchain-core
|
| 9 |
+
sentence-transformers
|
| 10 |
+
gradio
|