|
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 |
|
|
|
|
|
if __name__ == "__main__": |
|
demo = create_interface() |
|
demo.launch( |
|
server_name="0.0.0.0", |
|
server_port=7860, |
|
share=False |
|
) |