| import gradio as gr |
| import tempfile |
| import os |
| import json |
| import shutil |
| from pathlib import Path |
| import base64 |
| import logging |
| from main import generate_paper_poster |
|
|
|
|
| logging.basicConfig(level=logging.INFO) |
| logger = logging.getLogger(__name__) |
|
|
|
|
| def process_paper_to_poster( |
| pdf_file, |
| model_choice, |
| figure_service_url, |
| openai_api_key, |
| openai_base_url |
| ): |
| """ |
| 处理上传的PDF文件并生成海报 - 支持实时状态更新 |
| """ |
| if pdf_file is None: |
| yield None, None, None, "❌ Please upload a PDF file first!" |
| return |
| |
| if not openai_api_key.strip(): |
| yield None, None, None, "❌ Please enter your OpenAI API Key!" |
| return |
| |
| if not figure_service_url.strip(): |
| yield None, None, None, "❌ Please enter the figure detection service URL!" |
| return |
| |
| try: |
| |
| yield None, None, None, "🚀 Starting poster generation process..." |
| |
| |
| yield None, None, None, "⚙️ Configuring OpenAI API settings..." |
| os.environ['OPENAI_API_KEY'] = openai_api_key.strip() |
| if openai_base_url.strip(): |
| os.environ['OPENAI_BASE_URL'] = openai_base_url.strip() |
| |
| |
| yield None, None, None, "📁 Creating temporary workspace..." |
| temp_dir = tempfile.mkdtemp() |
| |
| |
| yield None, None, None, "📄 Processing uploaded PDF file..." |
| pdf_path = os.path.join(temp_dir, "paper.pdf") |
| shutil.copy(pdf_file.name, pdf_path) |
| |
| |
| yield None, None, None, "🔍 Extracting content from PDF and detecting figures..." |
| |
| |
| poster, html = generate_paper_poster( |
| url=figure_service_url, |
| pdf=pdf_path, |
| vendor="openai", |
| model=model_choice, |
| text_prompt="", |
| figures_prompt="", |
| output="" |
| ) |
| |
| |
| if poster is None and html is None: |
| yield None, None, None, "❌ Failed to generate poster! The paper processing returned no results. Please check:\n- PDF file format and content\n- Figure detection service availability\n- API key validity\n- Model configuration\n- Network connectivity" |
| return |
| |
| |
| yield None, None, None, "🖼️ Image processing completed! Generating JSON structure..." |
| |
| |
| json_content = json.dumps(poster.model_dump(), indent=2, ensure_ascii=False) |
| |
| |
| yield None, None, None, "📋 JSON file generated successfully! Creating HTML poster..." |
| |
| |
| json_file = tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False, encoding='utf-8') |
| html_file = tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8') |
| |
| |
| json_file.write(json_content) |
| json_file.close() |
| |
| html_file.write(html) |
| html_file.close() |
| |
| |
| yield None, None, None, "🧹 Cleaning up temporary files..." |
| shutil.rmtree(temp_dir) |
| |
| |
| yield ( |
| [json_file.name, html_file.name], |
| json_content, |
| html, |
| "✅ Poster generated successfully! 🎉\n📥 Files are ready for download\n🎨 HTML preview is displayed below\n💡 Download the HTML file for best viewing experience" |
| ) |
| |
| except Exception as e: |
| error_msg = f"❌ Error occurred during processing: {str(e)}" |
| yield None, None, None, error_msg |
|
|
|
|
| |
| def create_interface(): |
| |
| |
| js_func = """ |
| function refresh() { |
| const url = new URL(window.location); |
| |
| if (url.searchParams.get('__theme') !== 'light') { |
| url.searchParams.set('__theme', 'light'); |
| window.location.href = url.href; |
| } |
| } |
| """ |
| |
| with gr.Blocks( |
| title="P2P: Paper-to-Poster Generator", |
| theme=gr.themes.Default(), |
| js=js_func, |
| css=""" |
| .title { |
| text-align: center; |
| margin-bottom: 1rem; |
| } |
| .preview-container { |
| min-height: 1000px; |
| max-height: 1500px; |
| overflow-y: auto; |
| border: 1px solid #e0e0e0; |
| border-radius: 8px; |
| padding: 15px; |
| background-color: #fafafa; |
| } |
| .preview-container iframe { |
| width: 100% !important; |
| min-height: 1000px !important; |
| } |
| .config-section { |
| margin-bottom: 2rem; |
| } |
| .status-updating { |
| color: #2563eb; |
| font-weight: 500; |
| } |
| """ |
| ) as demo: |
| |
| gr.HTML(""" |
| <div class="title"> |
| <h1>🎓 P2P: Paper-to-Poster Generator</h1> |
| <p>Automatically convert academic papers into professional conference posters ✨</p> |
| <p><a href="https://arxiv.org/abs/2505.17104" target="_blank">📄 View Research Paper</a></p> |
| </div> |
| """) |
| |
| |
| with gr.Row(elem_classes=["config-section"]): |
| with gr.Column(scale=1): |
| gr.Markdown("### 📥 Input Configuration") |
| |
| |
| pdf_input = gr.File( |
| label="Upload PDF Paper File", |
| file_types=[".pdf"], |
| file_count="single" |
| ) |
| |
| |
| gr.Markdown("#### 🔑 OpenAI API Configuration") |
| openai_api_key = gr.Textbox( |
| label="OpenAI API Key", |
| placeholder="sk-...", |
| type="password", |
| info="Enter your OpenAI API key" |
| ) |
| |
| openai_base_url = gr.Textbox( |
| label="OpenAI Base URL (Optional)", |
| placeholder="https://api.openai.com/v1", |
| value="https://api.openai.com/v1", |
| info="Modify this URL if using proxy or other OpenAI-compatible services" |
| ) |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### ⚙️ Model Configuration") |
| |
| |
| model_choice = gr.Textbox( |
| label="AI Model Name", |
| value="gpt-4o-mini", |
| placeholder="e.g., gpt-4o-mini, gpt-4o, gpt-3.5-turbo, claude-3-sonnet", |
| info="Enter the AI model name you want to use" |
| ) |
| |
| |
| figure_url = gr.Textbox( |
| label="Figure Detection Service URL", |
| placeholder="Enter the URL of figure detection service", |
| info="Used to extract images and tables from PDF" |
| ) |
| |
| |
| generate_btn = gr.Button( |
| "🚀 Generate Poster", |
| variant="primary", |
| size="lg" |
| ) |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### 📤 Results & Downloads") |
| |
| |
| status_msg = gr.Textbox( |
| label="Status Information", |
| interactive=False, |
| lines=4, |
| show_copy_button=True |
| ) |
| |
| |
| output_files = gr.File( |
| label="📥 Download Generated Files (JSON & HTML)", |
| file_count="multiple", |
| interactive=False, |
| show_label=True |
| ) |
| |
| |
| with gr.Accordion("📋 JSON Structure", open=False): |
| json_preview = gr.Code( |
| label="", |
| language="json", |
| lines=10, |
| show_label=False |
| ) |
| |
| |
| gr.Markdown("### 🎨 HTML Poster Preview") |
| |
| gr.Markdown("**💡 Recommended: Download the HTML file from above and open it in your browser for optimal viewing experience**") |
| |
| |
| html_preview = gr.HTML( |
| label="", |
| show_label=False, |
| elem_classes=["preview-container"] |
| ) |
| |
| |
| gr.Markdown(""" |
| ### 📖 Usage Instructions |
| |
| 1. **Upload PDF File**: Select the academic paper PDF you want to convert |
| 2. **Configure OpenAI API**: Enter your API Key and Base URL (if needed) |
| 3. **Select Model**: Enter model name manually, such as gpt-4o-mini, gpt-4o, claude-3-sonnet, etc. |
| 4. **Set Figure Service**: Enter the URL of the figure detection service |
| 5. **Generate Poster**: Click the generate button and wait for processing |
| 6. **Download Results**: Download the generated JSON and HTML files from the download section |
| 7. **Full Preview**: Download the HTML file and open it in your browser for the best viewing experience |
| |
| ⚠️ **Important Notes**: |
| - Generated Poster is recommended to be viewed in fullscreen mode or download the HTML file to view in browser |
| - Requires a valid OpenAI API key with sufficient balance |
| - Figure detection service URL is required for extracting images from PDFs |
| - Processing time depends on paper length and complexity (usually 3-6 minutes) |
| - Ensure the model name is correct and supported by your API |
| - Download the HTML file and open it in your browser for the best viewing experience |
| |
| 💡 **Tips**: |
| - Recommended to use gpt-4o-mini model for cost-effective testing |
| - Recommended to use Claude model for better performance |
| - Modify Base URL if using domestic proxy services |
| - Supports any OpenAI-compatible model names |
| - Can use Claude, Gemini and other models (requires corresponding API configuration) |
| - The HTML preview below shows how your poster will look with maximum width for better viewing |
| - Download the HTML file from the "Download Generated Files" section for standalone viewing |
| """) |
| |
| |
| generate_btn.click( |
| fn=process_paper_to_poster, |
| inputs=[ |
| pdf_input, |
| model_choice, |
| figure_url, |
| openai_api_key, |
| openai_base_url |
| ], |
| outputs=[ |
| output_files, |
| json_preview, |
| html_preview, |
| status_msg |
| ] |
| ) |
| |
| return demo |
| pass |
|
|
|
|
| if __name__ == "__main__": |
| demo = create_interface() |
| demo.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| share=False |
| ) |