import os import uuid import io import shutil import fitz # PyMuPDF import gradio as gr from pptx import Presentation from pptx.util import Inches from docx import Document from docx.shared import Cm from PIL import Image # ------------------------- # Configuration # ------------------------- UPLOAD_DIR = "uploads" os.makedirs(UPLOAD_DIR, exist_ok=True) MAX_FILE_SIZE_MB = 500 # ------------------------- # Core Conversion Logic # ------------------------- def convert_pdf(file_path, target_format): if file_path is None: raise gr.Error("Please upload a PDF file.") if not file_path.lower().endswith(".pdf"): raise gr.Error("Only PDF files are supported.") unique_id = str(uuid.uuid4()) pdf_path = os.path.join(UPLOAD_DIR, f"{unique_id}.pdf") # ✅ FIX: copy file instead of file.read() shutil.copy(file_path, pdf_path) doc = fitz.open(pdf_path) if len(doc) == 0: doc.close() os.remove(pdf_path) raise gr.Error("The uploaded PDF is empty.") # ---------- PDF → PPT ---------- if target_format == "PowerPoint (.pptx)": output_path = os.path.join(UPLOAD_DIR, f"{unique_id}.pptx") prs = Presentation() prs.slide_width = Inches(13.333) prs.slide_height = Inches(7.5) for page in doc: pix = page.get_pixmap(matrix=fitz.Matrix(1.5, 1.5), alpha=False) img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples) img_stream = io.BytesIO() img.save(img_stream, format="JPEG", quality=80) img_stream.seek(0) slide = prs.slides.add_slide(prs.slide_layouts[6]) slide.shapes.add_picture( img_stream, 0, 0, width=prs.slide_width, height=prs.slide_height ) img_stream.close() prs.save(output_path) # ---------- PDF → Word ---------- else: output_path = os.path.join(UPLOAD_DIR, f"{unique_id}.docx") word_doc = Document() for section in word_doc.sections: section.top_margin = Cm(0.5) section.bottom_margin = Cm(0.5) section.left_margin = Cm(0.5) section.right_margin = Cm(0.5) for i, page in enumerate(doc): pix = page.get_pixmap(matrix=fitz.Matrix(1.5, 1.5), alpha=False) img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples) img_stream = io.BytesIO() img.save(img_stream, format="JPEG", quality=80) img_stream.seek(0) word_doc.add_picture(img_stream, width=Cm(20)) if i < len(doc) - 1: word_doc.add_page_break() img_stream.close() word_doc.save(output_path) doc.close() os.remove(pdf_path) return output_path # ------------------------- # Utility: Clear Files # ------------------------- def clear_files(): for f in os.listdir(UPLOAD_DIR): try: os.remove(os.path.join(UPLOAD_DIR, f)) except: pass return None # ------------------------- # Gradio UI # ------------------------- with gr.Blocks(title="PDF Converter | Developer: Najaf Ali Sharqi") as demo: gr.Markdown(""" # 📄 PDF Conversion Tool **Developer:** Najaf Ali Sharqi Convert PDF files generated by NotebookLM into **editable PowerPoint or Word documents** without modifying original content, layout, or images. """) with gr.Row(): pdf_input = gr.File( label="Upload PDF File", file_types=[".pdf"] ) format_choice = gr.Radio( choices=["PowerPoint (.pptx)", "Word Document (.docx)"], value="PowerPoint (.pptx)", label="Select Output Format" ) with gr.Row(): convert_btn = gr.Button("Convert") clear_btn = gr.Button("Clear Uploaded Files") output_file = gr.File(label="Download Converted File") convert_btn.click( fn=convert_pdf, inputs=[pdf_input, format_choice], outputs=output_file ) clear_btn.click( fn=clear_files, outputs=output_file ) gr.Markdown(""" --- ⚠️ **Important Notes** - UI instructions are provided in English only - The tool does **not** add, remove, or modify content - Output files preserve original visuals exactly - Designed for Hugging Face deployment using Gradio """) # ------------------------- # Launch (HF Compatible) # ------------------------- demo.launch( server_name="0.0.0.0", server_port=7860, ssr_mode=False )