CoolFace
Apppublic

MuhammadAdnanMalik/PDF_to_Word_File_Converter

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
app.py176 linesDownload Raw Back to root
1import io2import os3import tempfile4import fitz  # PyMuPDF5import pdfplumber6from docx import Document7from docx.shared import Pt, Inches8from PIL import Image9import gradio as gr10 11# Utility: clean filename12def _clean_filename(name: str) -> str:13    return "".join(c for c in name if c.isalnum() or c in (' ', '.', '_', '-')).rstrip()14 15 16def extract_with_pymupdf(pdf_bytes: bytes):17    doc = fitz.open(stream=pdf_bytes, filetype="pdf")18    pages_out = []19    for page in doc:20        page_dict = {"spans": [], "images": []}21        blocks = page.get_text("dict").get("blocks", [])22        for b in blocks:23            if b.get("type") == 0:24                for line in b.get("lines", []):25                    for span in line.get("spans", []):26                        page_dict["spans"].append({27                            "text": span.get("text", ""),28                            "font": span.get("font", ""),29                            "size": span.get("size", 11),30                            "bbox": span.get("bbox", None),31                        })32        try:33            for imginfo in page.get_images(full=True):34                xref = imginfo[0]35                base_image = doc.extract_image(xref)36                img_bytes = base_image["image"]37                ext = base_image.get("ext", "png")38                page_dict["images"].append({"image_bytes": img_bytes, "bbox": None, "ext": ext})39        except Exception:40            pass41        pages_out.append(page_dict)42    doc.close()43    return pages_out44 45 46def extract_tables_with_pdfplumber(pdf_bytes: bytes):47    tables_by_page = {}48    with pdfplumber.open(io.BytesIO(pdf_bytes)) as pdf:49        for i, page in enumerate(pdf.pages):50            try:51                table = page.extract_table()52                if table:53                    tables_by_page[i] = table54            except Exception:55                continue56    return tables_by_page57 58 59def pdf_to_docx(pdf_bytes: bytes, original_filename: str = "converted.pdf"):60    pages = extract_with_pymupdf(pdf_bytes)61    tables = extract_tables_with_pdfplumber(pdf_bytes)62 63    doc = Document()64 65    for p_idx, page in enumerate(pages):66        if p_idx > 0:67            doc.add_page_break()68 69        if p_idx in tables:70            tbl_data = tables[p_idx]71            rows = len(tbl_data)72            cols = max(len(r) for r in tbl_data)73            table = doc.add_table(rows=rows, cols=cols)74            table.style = "Table Grid"75            for r_i, row in enumerate(tbl_data):76                for c_i, cell in enumerate(row):77                    table.rows[r_i].cells[c_i].text = cell if cell is not None else ""78 79        para = None80        for span in page.get("spans", []):81            txt = span.get("text", "")82            if not txt:83                continue84            if para is None:85                para = doc.add_paragraph()86            run = para.add_run(txt)87            try:88                if span.get("font"):89                    run.font.name = span.get("font")90                if span.get("size"):91                    run.font.size = Pt(float(span.get("size")))92            except Exception:93                pass94 95        for img in page.get("images", []):96            try:97                image_bytes = img.get("image_bytes")98                ext = img.get("ext", "png")99                with tempfile.NamedTemporaryFile(delete=False, suffix=f".{ext}") as tf:100                    tf.write(image_bytes)101                    tmpname = tf.name102                try:103                    doc.add_picture(tmpname, width=Inches(6))104                except Exception:105                    doc.add_picture(tmpname)106                finally:107                    try:108                        os.unlink(tmpname)109                    except Exception:110                        pass111            except Exception:112                continue113 114    out_stream = io.BytesIO()115    safe_name = _clean_filename(os.path.splitext(original_filename)[0])116    out_filename = f"{safe_name}.docx"117    doc.save(out_stream)118    out_stream.seek(0)119    return out_filename, out_stream120 121 122def process_pdf(uploaded_file_path):123    if uploaded_file_path is None:124        return None125    # ✅ Open the file path instead of using .read()126    with open(uploaded_file_path, "rb") as f:127        file_bytes = f.read()128    base_name = os.path.basename(uploaded_file_path)129    out_name, out_stream = pdf_to_docx(file_bytes, original_filename=base_name)130    return (out_name, out_stream.getvalue())131 132 133with gr.Blocks(title="PDF → Word Converter") as demo:134    with gr.Row():135        gr.Markdown("# PDF → Word Converter\nUpload a PDF and get an editable .docx file.")136    with gr.Tabs():137        with gr.TabItem("Converter"):138            with gr.Column():139                pdf_in = gr.File(label="Upload PDF", file_count="single", file_types=[".pdf"]) 140                convert_btn = gr.Button("Convert to Word")141                output_file = gr.File(label="Download .docx")142                status = gr.Textbox(label="Status", interactive=False)143 144            def on_convert(f):145                if f is None:146                    return None, "No file uploaded"147                try:148                    name, data = process_pdf(f)149                    tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".docx")150                    tmp.write(data)151                    tmp.flush()152                    tmp.close()153                    return tmp.name, "Conversion successful"154                except Exception as e:155                    return None, f"Conversion failed: {e}"156 157            convert_btn.click(on_convert, inputs=[pdf_in], outputs=[output_file, status])158 159        with gr.TabItem("News — Announcement"):160            try:161                with open("news1.md", "r", encoding="utf-8") as f:162                    news_md = f.read()163            except Exception:164                news_md = "No news file (news1.md) found."165            gr.Markdown(news_md)166 167        with gr.TabItem("News — Release Notes"):168            try:169                with open("news2.md", "r", encoding="utf-8") as f:170                    news_md2 = f.read()171            except Exception:172                news_md2 = "No news file (news2.md) found."173            gr.Markdown(news_md2)174 175    demo.launch()176