import gradio as gr import fitz # PyMuPDF for reading PDFs import numpy as np from bokeh.plotting import figure, output_file, save from bokeh.models import HoverTool, ColumnDataSource import umap import pandas as pd from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances from sentence_transformers import SentenceTransformer import tempfile import logging # Set up logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') # Initialize the model globally model = SentenceTransformer('all-MiniLM-L6-v2') logging.info("Model loaded successfully.") def process_pdf(pdf_path): logging.info(f"Processing PDF: {pdf_path}") # Open the PDF doc = fitz.open(pdf_path) texts = [page.get_text() for page in doc] print("PDF processed successfully.") return " ".join(texts) def create_embeddings(text): print("Creating embeddings.") sentences = text.split(". ") # A simple split; consider a more robust sentence splitter embeddings = model.encode(sentences) print("Embeddings created successfully.") return embeddings, sentences def generate_plot(query, pdf_file): logging.info("Generating plot.") # Generate embeddings for the query query_embedding = model.encode([query])[0] # Process the PDF and create embeddings text = process_pdf(pdf_file.name) embeddings, sentences = create_embeddings(text) logging.info("Data prepared for UMAP.") # Prepare the data for UMAP and visualization all_embeddings = np.vstack([embeddings, query_embedding]) all_sentences = sentences + [query] # UMAP transformation umap_transform = umap.UMAP(n_neighbors=15, min_dist=0.0, n_components=2, random_state=42) umap_embeddings = umap_transform.fit_transform(all_embeddings) logging.info("UMAP transformation completed.") # Find the closest sentences to the query distances = cosine_similarity([query_embedding], embeddings)[0] closest_indices = distances.argsort()[-5:][::-1] # Adjust the number as needed # Prepare data for plotting data = { 'x': umap_embeddings[:-1, 0], # Exclude the query point itself 'y': umap_embeddings[:-1, 1], # Exclude the query point itself 'content': all_sentences[:-1], # Exclude the query sentence itself 'color': ['red' if i in closest_indices else 'blue' for i in range(len(sentences))], } source = ColumnDataSource(data) # Create the Bokeh plot p = figure(title="UMAP Projection of Sentences", width=700, height=700) p.scatter('x', 'y', color='color', source=source) hover = HoverTool(tooltips=[("Content", "@content")]) p.add_tools(hover) logging.info("Plot created successfully.") # Save the plot to an HTML file temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".html") output_file(temp_file.name) save(p) logging.info("Plot saved to file.") output_file("plot.html") return p.figure def gradio_interface(pdf_file, query): logging.info("Gradio interface called.") plot_path = generate_plot(query, pdf_file) with open(plot_path, "r") as f: html_content = f.read() logging.info("Returning HTML content.") return html_content iface = gr.Interface( fn=gradio_interface, inputs=[gr.File(label="Upload PDF"), gr.Textbox(label="Query")], outputs=gr.HTML(label="Visualization"), title="PDF Content Visualizer", description="Upload a PDF and enter a query to visualize the content." ) if __name__ == "__main__": iface.launch()