import os from fpdf import FPDF from PyPDF2 import PdfMerger from PIL import Image import gradio as gr #import aspose.words as aw import pypandoc def docx_to_pdf(docx_file, pdf_file): try: pypandoc.convert_file( docx_file, 'pdf', outputfile=pdf_file, extra_args=['--pdf-engine=pdflatex'] ) except OSError: # Download pandoc programmatically if it's not found print("Pandoc not found. Downloading pandoc...") pypandoc.download_pandoc() pypandoc.convert_file( docx_file, 'pdf', outputfile=pdf_file, extra_args=['--pdf-engine=pdflatex'] ) # Function to add a single text input as a new page in an FPDF object def add_text_as_page(pdf, text): pdf.add_page() pdf.set_auto_page_break(auto=True, margin=15) pdf.set_font("Arial", size=12) pdf.multi_cell(0, 10, text) # Function to convert an image to a standalone PDF def image_to_pdf(image_file): img = Image.open(image_file) pdf_path = image_file + ".pdf" img.convert('RGB').save(pdf_path) return pdf_path # Function to merge multiple PDFs def merge_pdfs(pdfs): merger = PdfMerger() for pdf in pdfs: merger.append(pdf) output_path = "merged_output.pdf" merger.write(output_path) merger.close() return output_path # Convert DOCX to PDF #def docx_to_pdf(docx_file, pdf_file): # doc = aw.Document(docx_file) # doc.save(pdf_file) # Main function to process uploaded files and manual text inputs def process_files_and_text(files, manual_texts, file_order): pdfs = [] manual_text_pdf = "manual_texts.pdf" pdf = FPDF() # Process uploaded files according to file_order for file_name in file_order: file = next(f for f in files if f.name == file_name) file_name, file_extension = os.path.splitext(file.name) if file_extension.lower() == ".pdf": pdfs.append(file.name) elif file_extension.lower() == ".txt": text = file.read().decode("utf-8") add_text_as_page(pdf, text) elif file_extension.lower() == ".docx": docx_to_pdf(file.name, file_name + ".pdf") #pdf_file = file_name + ".pdf" #docx_to_pdf(file.name, pdf_file) pdfs.append(file_name + ".pdf") elif file_extension.lower() in [".png", ".jpg", ".jpeg"]: pdf_output = image_to_pdf(file.name) pdfs.append(pdf_output) # Add manual text inputs, with each input becoming a new page for text in manual_texts: if text.strip(): # Add only non-empty text add_text_as_page(pdf, text) # Save manual text inputs to PDF if any pages were added if len(pdf.pages) > 0: pdf.output(manual_text_pdf) pdfs.append(manual_text_pdf) # Merge all PDFs into one merged_pdf = merge_pdfs(pdfs) return merged_pdf # Function to move items up or down in the list def reorder_files(file_list, direction, index): if direction == "up" and index > 0: file_list[index], file_list[index - 1] = file_list[index - 1], file_list[index] elif direction == "down" and index < len(file_list) - 1: file_list[index], file_list[index + 1] = file_list[index + 1], file_list[index] return file_list # Gradio interface function def file_merger(files, texts, file_order): merged_pdf = process_files_and_text(files, texts, file_order) return merged_pdf # Define Gradio interface with gr.Blocks() as iface: gr.Markdown("### File Merger: Merge PDF, TXT, DOCX, Image files, and manual text inputs into a single PDF.") with gr.Row(): file_input = gr.File(file_count="multiple", label="Upload Files") manual_text_inputs = gr.Textbox( lines=5, placeholder="Enter text here...", label="Manual Text Inputs", elem_id="manual_text_inputs", interactive=True ) file_list_state = gr.State([]) file_display = gr.Textbox( label="Uploaded Files (Reorder Below)", interactive=False, lines=10 ) file_index = gr.Number(label="File Index to Move (Starting from 0)", value=0, interactive=True) with gr.Row(): move_up_button = gr.Button("Move Up") move_down_button = gr.Button("Move Down") add_more_button = gr.Button("Add More Text") merge_button = gr.Button("Merge Files and Text") output = gr.File(label="Download Merged PDF") # Maintain a dynamic list for manual inputs manual_texts_state = gr.State(value=[]) def add_text_to_state(current_text, state_texts): state_texts.append(current_text) return "", state_texts # Clear the input box and update the state def update_file_list(files): file_names = [file.name for file in files] return file_names, "\n".join(file_names) def handle_reorder(file_list, direction, index): if 0 <= index < len(file_list): reordered_list = reorder_files(file_list, direction, index) return reordered_list, "\n".join(reordered_list) return file_list, "\n".join(file_list) # No change if index is out of range # Add functionality to add more text add_more_button.click(add_text_to_state, inputs=[manual_text_inputs, manual_texts_state], outputs=[manual_text_inputs, manual_texts_state]) # Update file list when files are uploaded file_input.change(update_file_list, inputs=[file_input], outputs=[file_list_state, file_display]) # Move files up or down move_up_button.click(handle_reorder, inputs=[file_list_state, gr.Text("up"), file_index], outputs=[file_list_state, file_display]) move_down_button.click(handle_reorder, inputs=[file_list_state, gr.Text("down"), file_index], outputs=[file_list_state, file_display]) # Merge files and text merge_button.click(file_merger, inputs=[file_input, manual_texts_state, file_list_state], outputs=output) iface.launch(share=True)