import os import sys import tempfile import gradio as gr # Add backend directory to sys.path so internal imports work seamlessly sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'backend'))) from backend.pdf_processor import convert_pdf_to_images from backend.services.export_service import ExportService def process_pdf(pdf_file, mineru_api_base, mineru_token, baidu_api_key, baidu_secret_key, max_workers, progress=gr.Progress()): if not pdf_file: return None, "Error: No file uploaded." if not mineru_token: # Fallback to HF Secrets using exact screenshot names or defaults mineru_token = os.environ.get("MinerU_Token", os.environ.get("MINERU_TOKEN", "")) if not mineru_token: return None, "Error: MinerU Token is required." if not baidu_api_key: baidu_api_key = os.environ.get("Baidu_API_Key", os.environ.get("BAIDU_API_KEY", "")) if not baidu_secret_key: baidu_secret_key = os.environ.get("Baidu_Secret_Key", os.environ.get("BAIDU_SECRET_KEY", "")) if not mineru_api_base: mineru_api_base = os.environ.get("MinerU_API_Base", os.environ.get("MINERU_API_BASE", "https://asemxin2000-mineru.hf.space")) # Set up environment variables that the backend relies on os.environ['MINERU_TOKEN'] = mineru_token os.environ['MINERU_API_BASE'] = mineru_api_base os.environ['BAIDU_API_KEY'] = baidu_api_key os.environ['BAIDU_SECRET_KEY'] = baidu_secret_key # We'll use a local temp upload folder upload_dir = tempfile.mkdtemp() os.environ['UPLOAD_FOLDER'] = upload_dir try: progress(0, desc="Converting PDF to images...") # 1. Convert PDF to high-res images image_paths = convert_pdf_to_images(pdf_file.name, output_dir=upload_dir, dpi=300) if not image_paths: return None, "Error: Failed to extract images from PDF." progress(0.1, desc=f"Extracted {len(image_paths)} pages.") # Progress callback adapter def progress_adapter(step: str, message: str, percent: int): # Gradio progress takes float [0, 1] # Since pdf to image took 10%, we map the remaining 90% (percent / 100 * 0.9 + 0.1) mapped_progress = (percent / 100.0) * 0.9 + 0.1 progress(mapped_progress, desc=f"[{step}] {message}") # 2. Run the main PPTX conversion pipeline exactly as designed in banana-slides # Defaulting export strategies to hybrid which combines MinerU and Baidu OCR pptx_bytes, warnings = ExportService.create_editable_pptx_with_recursive_analysis( image_paths=image_paths, output_file=None, # Return bytes slide_width_pixels=1920, slide_height_pixels=1080, max_depth=1, # Depth 1 is generally enough for presentations max_workers=int(max_workers), progress_callback=progress_adapter, export_extractor_method='hybrid' if baidu_api_key else 'mineru', export_inpaint_method='baidu' if baidu_api_key else 'generative', # generative requires AI model, let's just stick to baidu if we have it fail_fast=False # tolerate warnings ) if not pptx_bytes: return None, "Error: PPTX generation returned empty bytes." # Save to a temporary file output_pptx_path = os.path.join(upload_dir, "output_presentation.pptx") with open(output_pptx_path, "wb") as f: f.write(pptx_bytes) warning_msg = f"Done! {len(warnings.to_summary())} warnings encountered." if warnings.has_warnings() else "Done successfully!" return output_pptx_path, warning_msg except Exception as e: import traceback traceback.print_exc() return None, f"An error occurred: {str(e)}" # Define the Gradio Interface with gr.Blocks(title="PDF to Editable PPTX") as demo: gr.Markdown("# 🍌📄 PDF to Editable PPTX Converter") gr.Markdown("Convert your PDF slides into high-fidelity editable PowerPoint files using OpenXLab MinerU and Baidu OCR APIs.") with gr.Row(): with gr.Column(scale=1): pdf_input = gr.File(label="Upload PDF", file_types=[".pdf"]) max_workers = gr.Slider(minimum=1, maximum=16, value=2, step=1, label="Max Workers (Parallel Processing)") with gr.Accordion("API Keys (Optional if set in Space Secrets)", open=False): mineru_api_base = gr.Textbox(label="MinerU API Base", value=os.environ.get("MinerU_API_Base", os.environ.get("MINERU_API_BASE", "https://asemxin2000-mineru.hf.space")), placeholder="https://asemxin2000-mineru.hf.space", info="MinerU 服务地址(HF Space 或 mineru.net)") mineru_token = gr.Textbox(label="MinerU Token", type="password", value=os.environ.get("MinerU_Token", os.environ.get("MINERU_TOKEN", ""))) baidu_api_key = gr.Textbox(label="Baidu API Key", type="password", value=os.environ.get("Baidu_API_Key", os.environ.get("BAIDU_API_KEY", ""))) baidu_secret = gr.Textbox(label="Baidu Secret Key", type="password", value=os.environ.get("Baidu_Secret_Key", os.environ.get("BAIDU_SECRET_KEY", ""))) convert_btn = gr.Button("Convert to PPTX", variant="primary") with gr.Column(scale=1): status_box = gr.Textbox(label="Status", interactive=False) pptx_output = gr.File(label="Download PPTX") convert_btn.click( fn=process_pdf, inputs=[pdf_input, mineru_api_base, mineru_token, baidu_api_key, baidu_secret, max_workers], outputs=[pptx_output, status_box] ) if __name__ == "__main__": demo.launch()