Spaces:
Sleeping
Sleeping
| # Gradio App | |
| import numpy as np | |
| from transformers import pipeline, AutoTokenizer, AutoModelForQuestionAnswering | |
| from sentence_transformers import SentenceTransformer | |
| import gradio as gr | |
| from PyPDF2 import PdfReader | |
| # Document Reading | |
| def read_document(file_path): | |
| """ | |
| Reads PDF or TXT files and returns plain text. | |
| """ | |
| if file_path.endswith(".pdf"): | |
| reader = PdfReader(file_path) | |
| text = "" | |
| for page in reader.pages: | |
| text += page.extract_text() + " " | |
| return text | |
| elif file_path.endswith(".txt"): | |
| with open(file_path, "r", encoding="utf-8") as f: | |
| return f.read() | |
| else: | |
| return None | |
| # Chunking | |
| def chunk_text(text, chunk_size=500): | |
| """ | |
| Splits the text into chunks of `chunk_size` words. | |
| Transformers have input limits, so chunking is necessary. | |
| """ | |
| words = text.split() | |
| chunks = [" ".join(words[i:i+chunk_size]) for i in range(0, len(words), chunk_size)] | |
| return chunks | |
| # Embeddings for retrieval | |
| embed_model = SentenceTransformer('all-MiniLM-L6-v2') | |
| # Pre-trained QA model for extractive answers | |
| qa_model_name = "distilbert-base-uncased-distilled-squad" | |
| qa_tokenizer = AutoTokenizer.from_pretrained(qa_model_name) | |
| qa_model = AutoModelForQuestionAnswering.from_pretrained(qa_model_name) | |
| qa_pipeline_model = pipeline("question-answering", model=qa_model, tokenizer=qa_tokenizer) | |
| # QA Function | |
| def answer_question(file, question, top_k=3): | |
| """ | |
| Takes a document file and question string, | |
| returns the best answer from the document. | |
| """ | |
| if file is None: | |
| return "Please upload a document." | |
| # Step 1: Read & chunk document | |
| text = read_document(file.name) | |
| chunks = chunk_text(text, chunk_size=500) | |
| # Step 2: Embed chunks | |
| chunk_embeddings = embed_model.encode(chunks) | |
| # Step 3: Embed question | |
| question_embedding = embed_model.encode([question])[0] | |
| # Step 4: Compute cosine similarity to find top-k relevant chunks | |
| similarities = np.dot(chunk_embeddings, question_embedding) / ( | |
| np.linalg.norm(chunk_embeddings, axis=1) * np.linalg.norm(question_embedding) | |
| ) | |
| top_idx = similarities.argsort()[-top_k:][::-1] | |
| top_chunks = [chunks[i] for i in top_idx] | |
| # Step 5: Run extractive QA on top-k chunks | |
| best_answer = {"score": 0, "answer": "Answer not found."} | |
| for chunk in top_chunks: | |
| result = qa_pipeline_model(question=question, context=chunk) | |
| if result['score'] > best_answer['score']: | |
| best_answer = result | |
| return best_answer['answer'] | |
| iface = gr.Interface( | |
| fn=answer_question, | |
| inputs=[ | |
| gr.File(label="Upload Document (.pdf or .txt)"), | |
| gr.Textbox(label="Enter your question"), | |
| gr.Slider(1, 5, value=3, step=1, label="Top-k chunks to consider") | |
| ], | |
| outputs=gr.Textbox(label="Answer"), | |
| title="Document Question Answering (Mini-RAG)", | |
| description="Upload a document and ask questions. The system retrieves relevant chunks and extracts the answer." | |
| ) | |
| iface.launch() |