import atexit
import base64
import io
import json
import os
import tempfile
import uuid
import zipfile
from pathlib import Path
import gradio as gr
import requests
from PIL import Image
# API Configuration
API_URL = "https://cf38vaydqdl2l4p2.aistudio-hub.baidu.com/layout-parsing"
TOKEN = os.getenv("API_TOKEN")
LOGO_PATH = Path(__file__).parent / "pp-structurev3.png"
with open(LOGO_PATH, "rb") as image_file:
LOGO_BASE64 = (
f"data:image/png;base64,{base64.b64encode(image_file.read()).decode('utf-8')}"
)
TEMP_DIR = tempfile.TemporaryDirectory()
atexit.register(TEMP_DIR.cleanup)
CSS = """
:root {
--sand-color: #FAF9F6;
--white: #ffffff;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--text-color: #F3F4F7;
--black:#000000;
--link-hover: #2b6cb0;
--content-width: 1200px;
}
body {
display: flex;
justify-content: center;
background-color: var(--sand-color);
color: var(--text-color);
font-family: Arial, sans-serif;
}
.gradio-container {
max-width: var(--content-width) !important;
width: 100% !important;
margin: 20px auto;
padding: 20px;
background-color: var(--white);
}
#component-0,
#tabs,
#settings {
background-color: var(--white) !important;
padding: 15px;
}
.upload-section {
width: 100%;
margin: 0 auto 30px;
padding: 20px;
background-color: var(--sand-color) !important;
border-radius: 8px;
box-shadow: var(--shadow);
}
.center-content {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
margin-bottom: 20px;
}
.header {
margin-bottom: 30px;
width: 100%;
}
.logo-container {
width: 100%;
margin-bottom: 20px;
}
.logo-img {
width: 100%;
max-width: var(--content-width);
margin: 0 auto;
display: block;
}
.nav-bar {
display: flex;
justify-content: center;
background-color: var(--white);
padding: 15px 0;
box-shadow: var(--shadow);
margin-bottom: 20px;
}
.nav-links {
display: flex;
gap: 30px;
width: 100%;
justify-content: center;
}
.nav-link {
color: var(--black);
text-decoration: none;
font-weight: bold;
font-size: 24px;
transition: color 0.2s;
}
.nav-link:hover {
color: var(--link-hover);
text-decoration: none;
}
button {
background-color: var(--text-color) !important;
color: var(--black) !important;
border: none !important;
border-radius: 4px;
padding: 8px 16px;
}
button:hover {
opacity: 0.8 !important;
}
.file-download {
margin-top: 15px !important;
}
.loader {
border: 5px solid #f3f3f3;
border-top: 5px solid #3498db;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
margin: 20px auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loader-container {
text-align: center;
margin: 20px 0;
}
"""
MAX_NUM_PAGES = 10
def url_to_bytes(url, *, timeout=10):
resp = requests.get(url, timeout=timeout)
resp.raise_for_status()
return resp.content
def bytes_to_image(image_bytes):
return Image.open(io.BytesIO(image_bytes))
def embed_images_into_markdown_text(markdown_text, markdown_images):
for img_path, img_url in markdown_images.items():
# HACK
markdown_text = markdown_text.replace(
f'')
# Navigation bar
with gr.Row(elem_classes=["nav-bar"]):
gr.HTML(
"""
Processing, please wait...
""" ) # Results display section with gr.Column(): gr.Markdown("### Results") layout_ordering_images = [] markdown_display_list = [] for i in range(MAX_NUM_PAGES): with gr.Row(): layout_ordering_images.append( gr.Image( label=f"Layout Ordering Image {i}", show_label=True, visible=False, ) ) markdown_display_list.append( gr.Markdown( visible=False, container=True, show_copy_button=True, latex_delimiters=[ {"left": "$$", "right": "$$", "display": True}, {"left": "$", "right": "$", "display": False}, ], ) ) # Download section with gr.Column(elem_classes=["download-section"]): gr.Markdown("### Result Export") download_all_btn = gr.Button("Download Full Results (ZIP)", variant="primary") download_file = gr.File(visible=False, label="Download File") # Interaction logic def toggle_spinner(): return gr.update(visible=True) def hide_spinner(): return gr.update(visible=False) def update_display(results): ret_img = [] ret_cont = [] cnt = 0 for img, cont in zip( results["layout_ordering_images"], results["markdown_content_list"] ): ret_img.append(gr.update(value=bytes_to_image(img), visible=True)) ret_cont.append(gr.update(value=cont, visible=True)) cnt += 1 for _ in range(cnt, MAX_NUM_PAGES): ret_img.append(gr.update(visible=False)) ret_cont.append(gr.update(visible=False)) return ret_img + ret_cont process_btn.click(toggle_spinner, outputs=[loading_spinner]).then( process_file, inputs=[file_input], outputs=[results_state] ).then(hide_spinner, outputs=[loading_spinner]).then( update_display, inputs=[results_state], outputs=layout_ordering_images + markdown_display_list, ) download_all_btn.click( export_full_results, inputs=[results_state], outputs=[download_file] ).success(lambda: gr.update(visible=True), outputs=[download_file]) if __name__ == "__main__": demo.launch( server_name="0.0.0.0", server_port=7860, share=True, favicon_path=LOGO_PATH, )