update
Browse files- app.py +33 -4
- posterbuilder/convert.py +9 -8
app.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import subprocess, shutil, os, zipfile, datetime, sys, time, uuid, stat, re
|
| 3 |
from pathlib import Path
|
|
|
|
|
|
|
| 4 |
|
| 5 |
# =====================
|
| 6 |
# Version guard
|
|
@@ -260,6 +262,23 @@ def _apply_left_logo(OUTPUT_DIR: Path, logo_files, logs):
|
|
| 260 |
logs.append(f"⚠️ Failed to modify poster_output.tex: {e}")
|
| 261 |
return False
|
| 262 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 263 |
|
| 264 |
# =====================
|
| 265 |
# Gradio pipeline function (ISOLATED)
|
|
@@ -347,7 +366,6 @@ def run_pipeline(arxiv_url, pdf_file, openai_key, logo_files, meeting_logo_file,
|
|
| 347 |
|
| 348 |
logs.append("\n======= REAL-TIME LOG =======")
|
| 349 |
logs.append(f"cwd = runs/{WORK_DIR.name}")
|
| 350 |
-
logs.append(f"cmd = {' '.join(cmd)}")
|
| 351 |
_write_logs(LOG_PATH, logs)
|
| 352 |
yield "\n".join(logs), None
|
| 353 |
|
|
@@ -469,13 +487,22 @@ def run_pipeline(arxiv_url, pdf_file, openai_key, logo_files, meeting_logo_file,
|
|
| 469 |
except Exception as e:
|
| 470 |
logs.append(f"❌ Failed to create zip: {e}")
|
| 471 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
end_time = datetime.datetime.now()
|
| 473 |
dur = (end_time - start_time).seconds
|
| 474 |
logs.append(f"🏁 Completed at {_now_str()} (Duration: {dur}s)")
|
| 475 |
logs.append(f"🆔 run_id = {WORK_DIR.name}")
|
| 476 |
|
| 477 |
_write_logs(LOG_PATH, logs)
|
| 478 |
-
yield "\n".join(logs), (str(ZIP_PATH) if ZIP_PATH.exists() else None)
|
| 479 |
|
| 480 |
# =====================
|
| 481 |
# Gradio UI
|
|
@@ -491,7 +518,7 @@ iface = gr.Interface(
|
|
| 491 |
file_count="multiple",
|
| 492 |
file_types=["image"],
|
| 493 |
),
|
| 494 |
-
gr.File(label="🧩 Optional: Conference Logo (
|
| 495 |
gr.ColorPicker(
|
| 496 |
label="🎨 Theme Color (optional)",
|
| 497 |
value="#5E2E91" # default purple (94,46,145)
|
|
@@ -499,8 +526,10 @@ iface = gr.Interface(
|
|
| 499 |
],
|
| 500 |
outputs=[
|
| 501 |
gr.Textbox(label="🧾 Logs (8~10 minutes)", lines=30, max_lines=50),
|
| 502 |
-
gr.File(label="📦 Download Results (.zip)")
|
|
|
|
| 503 |
],
|
|
|
|
| 504 |
title="🎓 Paper2Poster",
|
| 505 |
description="""
|
| 506 |
[paper](https://arxiv.org/abs/2505.21497) | [GitHub](https://github.com/Paper2Poster/Paper2Poster) | [project page](https://paper2poster.github.io/)
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import subprocess, shutil, os, zipfile, datetime, sys, time, uuid, stat, re
|
| 3 |
from pathlib import Path
|
| 4 |
+
import base64
|
| 5 |
+
|
| 6 |
|
| 7 |
# =====================
|
| 8 |
# Version guard
|
|
|
|
| 262 |
logs.append(f"⚠️ Failed to modify poster_output.tex: {e}")
|
| 263 |
return False
|
| 264 |
|
| 265 |
+
def render_overleaf_button(overleaf_b64):
|
| 266 |
+
if not overleaf_b64:
|
| 267 |
+
return ""
|
| 268 |
+
|
| 269 |
+
html = f"""
|
| 270 |
+
<form action="https://www.overleaf.com/docs" method="post" target="_blank">
|
| 271 |
+
<input type="hidden" name="snip_uri" value="data:application/zip;base64,{overleaf_b64}">
|
| 272 |
+
<input type="hidden" name="engine" value="xelatex">
|
| 273 |
+
<button style="
|
| 274 |
+
background:#4CAF50;color:white;padding:8px 14px;
|
| 275 |
+
border:none;border-radius:6px;cursor:pointer; margin-top:8px;
|
| 276 |
+
">
|
| 277 |
+
🚀 Open in Overleaf
|
| 278 |
+
</button>
|
| 279 |
+
</form>
|
| 280 |
+
"""
|
| 281 |
+
return html
|
| 282 |
|
| 283 |
# =====================
|
| 284 |
# Gradio pipeline function (ISOLATED)
|
|
|
|
| 366 |
|
| 367 |
logs.append("\n======= REAL-TIME LOG =======")
|
| 368 |
logs.append(f"cwd = runs/{WORK_DIR.name}")
|
|
|
|
| 369 |
_write_logs(LOG_PATH, logs)
|
| 370 |
yield "\n".join(logs), None
|
| 371 |
|
|
|
|
| 487 |
except Exception as e:
|
| 488 |
logs.append(f"❌ Failed to create zip: {e}")
|
| 489 |
|
| 490 |
+
# ====== Prepare Overleaf base64 payload (optional) ======
|
| 491 |
+
overleaf_zip_b64 = ""
|
| 492 |
+
try:
|
| 493 |
+
with open(ZIP_PATH, "rb") as f:
|
| 494 |
+
overleaf_zip_b64 = base64.b64encode(f.read()).decode("utf-8")
|
| 495 |
+
logs.append("🔗 Prepared Overleaf base64 payload")
|
| 496 |
+
except Exception as e:
|
| 497 |
+
logs.append(f"⚠️ Failed Overleaf payload: {e}")
|
| 498 |
+
|
| 499 |
end_time = datetime.datetime.now()
|
| 500 |
dur = (end_time - start_time).seconds
|
| 501 |
logs.append(f"🏁 Completed at {_now_str()} (Duration: {dur}s)")
|
| 502 |
logs.append(f"🆔 run_id = {WORK_DIR.name}")
|
| 503 |
|
| 504 |
_write_logs(LOG_PATH, logs)
|
| 505 |
+
yield "\n".join(logs), (str(ZIP_PATH) if ZIP_PATH.exists() else None), overleaf_zip_b64
|
| 506 |
|
| 507 |
# =====================
|
| 508 |
# Gradio UI
|
|
|
|
| 518 |
file_count="multiple",
|
| 519 |
file_types=["image"],
|
| 520 |
),
|
| 521 |
+
gr.File(label="🧩 Optional: Conference Logo (NIPS official logo by defalt)", file_count="single", file_types=["image"]),
|
| 522 |
gr.ColorPicker(
|
| 523 |
label="🎨 Theme Color (optional)",
|
| 524 |
value="#5E2E91" # default purple (94,46,145)
|
|
|
|
| 526 |
],
|
| 527 |
outputs=[
|
| 528 |
gr.Textbox(label="🧾 Logs (8~10 minutes)", lines=30, max_lines=50),
|
| 529 |
+
gr.File(label="📦 Download Results (.zip)"),
|
| 530 |
+
gr.HTML(label="Open in Overleaf")
|
| 531 |
],
|
| 532 |
+
|
| 533 |
title="🎓 Paper2Poster",
|
| 534 |
description="""
|
| 535 |
[paper](https://arxiv.org/abs/2505.21497) | [GitHub](https://github.com/Paper2Poster/Paper2Poster) | [project page](https://paper2poster.github.io/)
|
posterbuilder/convert.py
CHANGED
|
@@ -88,26 +88,27 @@ def escape_text(s: str) -> str:
|
|
| 88 |
if not s:
|
| 89 |
return ""
|
| 90 |
|
| 91 |
-
#
|
| 92 |
math_blocks = []
|
| 93 |
-
|
| 94 |
def store_math(m):
|
| 95 |
math_blocks.append(m.group(0))
|
| 96 |
-
|
| 97 |
-
return f"\0{len(math_blocks)-1}\0" # 不会出现在普通文本里
|
| 98 |
|
| 99 |
-
|
|
|
|
| 100 |
|
| 101 |
-
#
|
| 102 |
rep = {
|
| 103 |
"&": r"\&", "%": r"\%", "$": r"\$", "#": r"\#",
|
| 104 |
"_": r"\_", "{": r"\{", "}": r"\}",
|
| 105 |
-
"~": r"
|
|
|
|
| 106 |
}
|
|
|
|
| 107 |
for k, v in rep.items():
|
| 108 |
s = s.replace(k, v)
|
| 109 |
|
| 110 |
-
#
|
| 111 |
for i, block in enumerate(math_blocks):
|
| 112 |
s = s.replace(f"\0{i}\0", block)
|
| 113 |
|
|
|
|
| 88 |
if not s:
|
| 89 |
return ""
|
| 90 |
|
| 91 |
+
# --- 1) 捕获 math: $...$ 或 \( ... \) ----
|
| 92 |
math_blocks = []
|
|
|
|
| 93 |
def store_math(m):
|
| 94 |
math_blocks.append(m.group(0))
|
| 95 |
+
return f"\0{len(math_blocks)-1}\0"
|
|
|
|
| 96 |
|
| 97 |
+
# 识别 $...$ 和 \( ... \)
|
| 98 |
+
s = re.sub(r"\${1,2}.*?\${1,2}|\\\(.+?\\\)", store_math, s)
|
| 99 |
|
| 100 |
+
# --- 2) 转义文本字符(不碰 math) ----
|
| 101 |
rep = {
|
| 102 |
"&": r"\&", "%": r"\%", "$": r"\$", "#": r"\#",
|
| 103 |
"_": r"\_", "{": r"\{", "}": r"\}",
|
| 104 |
+
"~": r"~{}", # 保持 LaTeX 不换行空格
|
| 105 |
+
"^": r"\^{}",
|
| 106 |
}
|
| 107 |
+
|
| 108 |
for k, v in rep.items():
|
| 109 |
s = s.replace(k, v)
|
| 110 |
|
| 111 |
+
# --- 3) 恢复 math ----
|
| 112 |
for i, block in enumerate(math_blocks):
|
| 113 |
s = s.replace(f"\0{i}\0", block)
|
| 114 |
|