muhyousf's picture
Update app.py
80ff9dd verified
Raw
History Blame Contribute Delete
10.5 kB
import gradio as gr
import numpy as np
from sentence_transformers import SentenceTransformer
import faiss
import os
import PyPDF2
import docx
import pandas as pd
class PureRAGBot:
def __init__(self):
# Embedding model for document search
self.embedder = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
self.documents = []
self.index = None
self.is_ready = False
def load_file_content(self, file):
"""Load content from various file types"""
try:
if file is None:
return "Please select a file first."
file_path = file.name
file_extension = os.path.splitext(file_path)[1].lower()
if file_extension == '.txt':
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
chunks = self.split_text_into_chunks(content)
elif file_extension == '.csv':
df = pd.read_csv(file_path)
chunks = self.dataframe_to_chunks(df)
elif file_extension == '.pdf':
chunks = self.pdf_to_chunks(file_path)
elif file_extension in ['.docx', '.doc']:
chunks = self.docx_to_chunks(file_path)
else:
return "Unsupported file format. Please upload TXT, CSV, PDF, or DOCX files."
# Create FAISS index
if chunks:
embeddings = self.embedder.encode(chunks)
self.index = faiss.IndexFlatIP(embeddings.shape[1])
self.index.add(embeddings.astype('float32'))
self.documents = chunks
self.is_ready = True
return f"βœ… Document successfully loaded! {len(chunks)} content sections indexed. You can now ask questions about this document."
else:
return "❌ No readable content found in the file."
except Exception as e:
return f"❌ Error processing file: {str(e)}"
def split_text_into_chunks(self, text, chunk_size=300):
"""Split text into manageable chunks"""
sentences = text.split('.')
chunks = []
current_chunk = ""
for sentence in sentences:
sentence = sentence.strip()
if not sentence:
continue
if len(current_chunk) + len(sentence) < chunk_size:
current_chunk += sentence + '. '
else:
if current_chunk:
chunks.append(current_chunk.strip())
current_chunk = sentence + '. '
if current_chunk:
chunks.append(current_chunk.strip())
return chunks if chunks else [text[:500]]
def dataframe_to_chunks(self, df):
"""Convert DataFrame to text chunks"""
chunks = []
for idx, row in df.iterrows():
row_text = " | ".join([str(cell) for cell in row if pd.notna(cell)])
if len(row_text) > 500:
row_text = row_text[:500] + "..."
chunks.append(f"Row {idx+1}: {row_text}")
return chunks
def pdf_to_chunks(self, file_path):
"""Extract text from PDF"""
try:
with open(file_path, 'rb') as file:
reader = PyPDF2.PdfReader(file)
text = ""
for page in reader.pages:
text += page.extract_text() + "\n"
return self.split_text_into_chunks(text)
except Exception as e:
return [f"Error reading PDF: {str(e)}"]
def docx_to_chunks(self, file_path):
"""Extract text from DOCX"""
try:
doc = docx.Document(file_path)
text = ""
for paragraph in doc.paragraphs:
if paragraph.text.strip():
text += paragraph.text + "\n"
return self.split_text_into_chunks(text)
except Exception as e:
return [f"Error reading DOCX: {str(e)}"]
def search_documents(self, query, k=3):
"""Search for relevant documents"""
if not self.is_ready:
return []
try:
query_embedding = self.embedder.encode([query])
distances, indices = self.index.search(query_embedding.astype('float32'), k)
results = []
for i, idx in enumerate(indices[0]):
if idx < len(self.documents):
results.append({
'content': self.documents[idx],
'score': float(distances[0][i])
})
return results
except Exception as e:
print(f"Search error: {e}")
return []
def generate_rag_response(self, query):
"""Generate response purely from document content"""
if not self.is_ready:
return "❌ Please upload a document file first to ask questions about its content."
# Search for relevant content
results = self.search_documents(query)
if not results:
return f"❌ I couldn't find any information about '{query}' in the uploaded document. Please try rephrasing your question or ask about different content from the document."
# Filter relevant results
relevant_results = [r for r in results if r['score'] > 0.3]
if not relevant_results:
return f"❌ The document contains some text, but nothing specifically relevant to '{query}'. Please ask about content that might be in the document."
# Build response from document content
response = "πŸ“š **Based on your document:**\n\n"
for i, result in enumerate(relevant_results[:3]): # Show top 3 results
response += f"**β€’ Section {i+1}:** {result['content']}\n\n"
# Add suggestions
response += "πŸ’‘ **Tip:** You can ask about:\n- Key topics in the document\n- Specific information you're looking for\n- Summaries of sections\n- Explanations of concepts mentioned"
return response
def create_interface():
bot = PureRAGBot()
with gr.Blocks(theme=gr.themes.Soft(), title="Document RAG Assistant") as demo:
gr.Markdown("""
# πŸ“š Document RAG Assistant
**Pure Document-Based Question Answering**
- **πŸ” Semantic Search**: Find relevant content in your documents
- **πŸ“– Content-Based Answers**: All answers come directly from your uploaded files
- **🎯 Precision**: Only answers based on document content
**Note**: This bot only answers questions based on your uploaded documents.
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### πŸ“ Upload Document")
file_input = gr.File(
label="Upload your document",
file_types=[".txt", ".csv", ".pdf", ".docx", ".doc"],
type="filepath"
)
upload_btn = gr.Button("Process Document", variant="primary")
status = gr.Textbox(
label="Status",
value="Please upload a document to begin...",
interactive=False
)
gr.Markdown("""
### ℹ️ How It Works
1. Upload any document (TXT, PDF, CSV, DOCX)
2. Ask questions about the content
3. Get answers directly from the document
4. No general knowledge - only document content
""")
with gr.Column(scale=2):
gr.Markdown("### πŸ’¬ Ask About Your Document")
chatbot = gr.Chatbot(
height=400,
label="Document Q&A",
show_copy_button=True,
placeholder="Ask questions about your uploaded document content..."
)
with gr.Row():
question_input = gr.Textbox(
label="Your question about the document",
placeholder="What would you like to know about this document?",
scale=4
)
send_btn = gr.Button("Search Document", variant="primary", scale=1)
clear_btn = gr.Button("Clear Conversation", variant="secondary")
# gr.Markdown("""
# ### πŸ’‘ Example Questions:
# **After uploading a document, try:**
# - "What is the main topic of this document?"
# - "Summarize the key points"
# - "What are the main findings?"
# - "Explain the methodology used"
# - "What solutions are proposed?"
# - "List the key recommendations"
# - "What data is presented in this report?"
# """)
def process_file(file):
return bot.load_file_content(file)
def respond(message, chat_history):
if not message.strip():
return "", chat_history
response = bot.generate_rag_response(message)
chat_history.append((message, response))
return "", chat_history
def clear_chat():
return []
# Event handlers
upload_btn.click(
process_file,
inputs=[file_input],
outputs=[status]
)
question_input.submit(
respond,
inputs=[question_input, chatbot],
outputs=[question_input, chatbot]
)
send_btn.click(
respond,
inputs=[question_input, chatbot],
outputs=[question_input, chatbot]
)
clear_btn.click(
clear_chat,
outputs=[chatbot]
)
return demo
# Launch the application
if __name__ == "__main__":
demo = create_interface()
demo.launch(
share=True,
server_name="0.0.0.0",
show_error=True
)