Spaces:
Sleeping
Sleeping
| 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 | |
| ) |