Spaces:
Running
Running
Upload 59 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +5 -0
- config.yaml +12 -0
- main.py +250 -0
- mineru_outputs/readme.txt.txt +1 -0
- papers/readme.txt +1 -0
- poster_template/expore_our_work_in_detail.jpg +3 -0
- poster_template/poster_template.html +324 -0
- ppt_template/Contents.html +68 -0
- ppt_template/T10_4Img_2×2Grid.html +97 -0
- ppt_template/T11_3Img_TopTextBottom.html +99 -0
- ppt_template/T12_3Img_BottomTextTop.html +102 -0
- ppt_template/T13_3Img.html +95 -0
- ppt_template/T14_ImageRight_1Formula.html +99 -0
- ppt_template/T15_ImageLeft_1Formula.html +95 -0
- ppt_template/T16_1Img_2Formula_TopTextBottom.html +93 -0
- ppt_template/T17_2Img_1Formula_TopTextBottom.html +102 -0
- ppt_template/T18_2Formula_TopTextBottom.html +86 -0
- ppt_template/T19_2Text.html +75 -0
- ppt_template/T1_TextOnly.html +72 -0
- ppt_template/T20_FormulaTop.html +81 -0
- ppt_template/T21_3Img_col.html +95 -0
- ppt_template/T2_ImageRight.html +91 -0
- ppt_template/T3_ImageLeft.html +89 -0
- ppt_template/T4_ImageTop.html +81 -0
- ppt_template/T5_TwoImages.html +81 -0
- ppt_template/T6_TwoImages2.html +94 -0
- ppt_template/T7_2×2_TopImage.html +101 -0
- ppt_template/T8_2×2_BottomImage.html +99 -0
- ppt_template/T9_2×2_AltTextImg.html +99 -0
- ppt_template/Title Slide.html +98 -0
- ppt_template/format.txt +34 -0
- ppt_template/images/2.png +3 -0
- ppt_template/images/3.png +0 -0
- ppt_template/images/4.png +3 -0
- ppt_template/images/5_1.png +0 -0
- ppt_template/images/5_2.png +0 -0
- ppt_template/images/5_3.png +0 -0
- ppt_template/images/7.png +3 -0
- ppt_template/images/t_2.png +3 -0
- pr_template.md +31 -0
- prompt.json +46 -0
- src/DAG2poster.py +871 -0
- src/DAG2ppt.py +773 -0
- src/DAG2pr.py +995 -0
- src/__init__.py +34 -0
- src/__pycache__/DAG2poster.cpython-310.pyc +0 -0
- src/__pycache__/DAG2ppt.cpython-310.pyc +0 -0
- src/__pycache__/DAG2pr.cpython-310.pyc +0 -0
- src/__pycache__/__init__.cpython-310.pyc +0 -0
- src/__pycache__/__init__.cpython-312.pyc +0 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
poster_template/expore_our_work_in_detail.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
ppt_template/images/2.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
ppt_template/images/4.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
ppt_template/images/7.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
ppt_template/images/t_2.png filter=lfs diff=lfs merge=lfs -text
|
config.yaml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 项目基础设置
|
| 2 |
+
path:
|
| 3 |
+
root_folder: "./mineru_outputs"
|
| 4 |
+
|
| 5 |
+
# 模型相关设置
|
| 6 |
+
model_settings:
|
| 7 |
+
generation_model: "gemini-3-pro-preview"
|
| 8 |
+
|
| 9 |
+
# 敏感信息(建议通过环境变量读取,或仅在本地调试时填写)
|
| 10 |
+
api_keys:
|
| 11 |
+
gemini_api_key: ""
|
| 12 |
+
openai_api_key: ""
|
main.py
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import os
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
from src import *
|
| 6 |
+
|
| 7 |
+
import yaml
|
| 8 |
+
import os
|
| 9 |
+
|
| 10 |
+
# ============= 读取配置 ===============
|
| 11 |
+
def load_config(config_path="config.yaml"):
|
| 12 |
+
with open(config_path, "r", encoding="utf-8") as f:
|
| 13 |
+
config = yaml.safe_load(f)
|
| 14 |
+
return config
|
| 15 |
+
|
| 16 |
+
# ========== 读取 prompt 模板 ==========
|
| 17 |
+
def load_prompt(prompt_path="prompt.json", prompt_name="poster_prompt"):
|
| 18 |
+
with open(prompt_path, "r", encoding="utf-8") as f:
|
| 19 |
+
data = json.load(f)
|
| 20 |
+
return data.get(prompt_name, "")
|
| 21 |
+
|
| 22 |
+
# 应用配置
|
| 23 |
+
config = load_config()
|
| 24 |
+
|
| 25 |
+
model_name = config['model_settings']['generation_model']
|
| 26 |
+
|
| 27 |
+
# ========== 主流程 ==========
|
| 28 |
+
def main():
|
| 29 |
+
# 输入总文件夹路径(包含多个论文子文件夹)
|
| 30 |
+
root_folder = config['path']['root_folder'] # ⚠️ 修改为你的实际路径
|
| 31 |
+
prompt_path = "prompt.json"
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
print("📘 Loading prompts...")
|
| 35 |
+
# dag prompt:
|
| 36 |
+
section_split_prompt = load_prompt(prompt_path, prompt_name="section_split_prompt")
|
| 37 |
+
clean_prompt = load_prompt(prompt_path, prompt_name="clean_prompt")
|
| 38 |
+
initialize_dag_prompt = load_prompt(prompt_path, prompt_name="initialize_dag_prompt")
|
| 39 |
+
visual_dag_prompt = load_prompt(prompt_path, prompt_name="visual_dag_prompt")
|
| 40 |
+
section_dag_generation_prompt = load_prompt(prompt_path, prompt_name="section_dag_generation_prompt")
|
| 41 |
+
|
| 42 |
+
# ppt prompt:
|
| 43 |
+
outline_initialize_prompt = load_prompt(prompt_path, prompt_name="outline_initialize_prompt")
|
| 44 |
+
generate_complete_outline_prompt = load_prompt(prompt_path, prompt_name="generate_complete_outline_prompt")
|
| 45 |
+
arrange_template_prompt= load_prompt(prompt_path, prompt_name="arrange_template_prompt")
|
| 46 |
+
commenter_prompt= load_prompt(prompt_path, prompt_name="commenter_prompt")
|
| 47 |
+
reviser_prompt= load_prompt(prompt_path, prompt_name="reviser_prompt")
|
| 48 |
+
|
| 49 |
+
# poster prompt:
|
| 50 |
+
poster_outline_prompt= load_prompt(prompt_path, prompt_name="poster_outline_prompt")
|
| 51 |
+
poster_refinement_prompt= load_prompt(prompt_path, prompt_name="poster_refinement_prompt")
|
| 52 |
+
modified_poster_logic_prompt=load_prompt(prompt_path, prompt_name="modified_poster_logic_prompt")
|
| 53 |
+
|
| 54 |
+
# pr prompt:
|
| 55 |
+
extract_basic_information_prompt = load_prompt("prompt.json", "extract_basic_information_prompt")
|
| 56 |
+
generate_pr_prompt = load_prompt(prompt_path, prompt_name="generate_pr_prompt")
|
| 57 |
+
add_title_and_hashtag_prompt = load_prompt(prompt_path, prompt_name="add_title_and_hashtag_prompt")
|
| 58 |
+
pr_refinement_prompt = load_prompt(prompt_path, prompt_name="pr_refinement_prompt")
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
# === 遍历每个子文件夹 ===
|
| 64 |
+
for subdir in os.listdir(root_folder):
|
| 65 |
+
subdir_path = os.path.join(root_folder, subdir)
|
| 66 |
+
auto_path = os.path.join(subdir_path, "auto") # ✅ 进入 auto 子文件夹
|
| 67 |
+
|
| 68 |
+
if not os.path.isdir(auto_path):
|
| 69 |
+
print(f"⚠️ No 'auto' folder found in {subdir_path}, skipping...")
|
| 70 |
+
continue # 只处理存在 auto 文件夹的目录
|
| 71 |
+
|
| 72 |
+
# ✅ 如果 success.txt 已存在,跳过该目录
|
| 73 |
+
success_flag = os.path.join(auto_path, "success.txt")
|
| 74 |
+
if os.path.isfile(success_flag):
|
| 75 |
+
print(f"✅ success.txt exists in {auto_path}, skipping...")
|
| 76 |
+
continue
|
| 77 |
+
|
| 78 |
+
print(f"\n🚀 Processing paper folder: {auto_path}")
|
| 79 |
+
|
| 80 |
+
# === 根据子文件夹名精确匹配文件 ===
|
| 81 |
+
target_pdf = f"{subdir}_origin.pdf"
|
| 82 |
+
target_md = f"{subdir}.md"
|
| 83 |
+
|
| 84 |
+
pdf_path = os.path.join(auto_path, target_pdf)
|
| 85 |
+
md_path = os.path.join(auto_path, target_md)
|
| 86 |
+
|
| 87 |
+
# === 检查文件是否存在 ===
|
| 88 |
+
if not os.path.exists(pdf_path):
|
| 89 |
+
print(f"⚠️ Missing expected PDF: {target_pdf} in {auto_path}, skipping...")
|
| 90 |
+
continue
|
| 91 |
+
if not os.path.exists(md_path):
|
| 92 |
+
print(f"⚠️ Missing expected Markdown: {target_md} in {auto_path}, skipping...")
|
| 93 |
+
continue
|
| 94 |
+
|
| 95 |
+
print(f"📄 Matched files:\n PDF: {target_pdf}\n MD: {target_md}")
|
| 96 |
+
|
| 97 |
+
# === 输出文件路径 ===
|
| 98 |
+
output_html = os.path.join(auto_path, "poster.html")
|
| 99 |
+
graph_json_path = os.path.join(auto_path, "graph.json")
|
| 100 |
+
|
| 101 |
+
# === 清理 markdown === 去除无意义的段落,如relative work,reference,appendix等等
|
| 102 |
+
print("🧹 Cleaning markdown before splitting...")
|
| 103 |
+
cleaned_md_path = clean_paper(md_path, clean_prompt, model="gemini-3-pro-preview", config=config)
|
| 104 |
+
|
| 105 |
+
# === 利用gpt将论文分段 ===
|
| 106 |
+
paths = split_paper(cleaned_md_path, section_split_prompt, model="gemini-3-pro-preview" ,config=config)
|
| 107 |
+
|
| 108 |
+
# === 利用gpt初始化dag ===
|
| 109 |
+
dag = initialize_dag(markdown_path=cleaned_md_path,initialize_dag_prompt=initialize_dag_prompt,model="gemini-3-pro-preview", config=config)
|
| 110 |
+
dag_path = os.path.join(auto_path, "dag.json")
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
# === 生成visual_dag ===
|
| 114 |
+
visual_dag_path=os.path.join(auto_path, "visual_dag.json")
|
| 115 |
+
extract_and_generate_visual_dag(markdown_path=cleaned_md_path,prompt_for_gpt=visual_dag_prompt,output_json_path=visual_dag_path,model="gemini-3-pro-preview", config=config)
|
| 116 |
+
add_resolution_to_visual_dag(auto_path, visual_dag_path)
|
| 117 |
+
|
| 118 |
+
# === 生成section_dag ===
|
| 119 |
+
section_split_output_path=os.path.join(subdir_path, "section_split_output")
|
| 120 |
+
build_section_dags(folder_path=section_split_output_path,base_prompt=section_dag_generation_prompt,model="gemini-3-pro-preview", config=config)
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
# === 向dag.json添加section_dag ===
|
| 124 |
+
section_dag_path=os.path.join(subdir_path, "section_dag")
|
| 125 |
+
merged_path = add_section_dag(section_dag_folder=section_dag_path,main_dag_path=dag_path,output_path=None)
|
| 126 |
+
|
| 127 |
+
# === 向dag.json添加visual_dag ===
|
| 128 |
+
add_visual_dag(dag_path=dag_path,visual_dag_path=visual_dag_path)
|
| 129 |
+
|
| 130 |
+
# === 完善dag中每一个结点的visual_node ===
|
| 131 |
+
refine_visual_node(dag_path)
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
# ============================= PPT部分 ================================
|
| 137 |
+
|
| 138 |
+
# === 按照算法选出结点,以便后续生成outline ===
|
| 139 |
+
selected_node_path=os.path.join(auto_path, "selected_node.json")
|
| 140 |
+
generate_selected_nodes(dag_json_path=dag_path, max_len=15,output_path=selected_node_path)
|
| 141 |
+
|
| 142 |
+
# === 初始化ouline ===
|
| 143 |
+
outline_path= os.path.join(auto_path, "outline.json")
|
| 144 |
+
outline = outline_initialize(dag_json_path=dag_path,outline_initialize_prompt=outline_initialize_prompt,model=model_name, config=config)
|
| 145 |
+
|
| 146 |
+
# === 生成完整ouline ===
|
| 147 |
+
outline_data=generate_complete_outline(selected_node_path,outline_path,generate_complete_outline_prompt,model=model_name, config=config)
|
| 148 |
+
|
| 149 |
+
# === 配模板 ===
|
| 150 |
+
arrange_template(outline_path,arrange_template_prompt,model=model_name, config=config)
|
| 151 |
+
|
| 152 |
+
# === 生成最终的PPT ===
|
| 153 |
+
ppt_template_path="./ppt_template"
|
| 154 |
+
generate_ppt_prompt = {"role":"system","content":"You are given (1) a slide node (JSON) and (2) an HTML slide template. Your task: revise the HTML template to produce the final slide HTML using the node content. Node fields: text (slide textual content), figure (list of images to display, each has name, caption, resolution), formula (list of formula images to display, each has name, caption, resolution), template (template filename). IMPORTANT RULES: 1) Only modify places in the HTML that are marked by comments like <!-- You need to revise the following parts. X: ... -->. 2) For 'Subjects' sections: replace the placeholder title with ONE concise summary sentence for this slide. 3) For 'Image' sections (<img ...>): replace src with the relative path extracted from node.figure/formula[i].name; the node image name may be markdown like '', use only 'images/abc.jpg'. 4) For 'Text' sections: replace the placeholder text with the node.text content, formatted cleanly in HTML; keep it readable and you may use <p>, <ul><li>, <br/> appropriately. 5) If the template expects more images/text blocks than provided by the node, leave the missing positions unchanged and do not invent content. 6) If the node provides more images than the template has slots, fill slots in order and ignore the rest. 7) Preserve all other HTML, CSS, and structure exactly. OUTPUT FORMAT: Return ONLY the revised HTML as plain text. Do NOT wrap it in markdown fences. Do NOT add explanations."}
|
| 155 |
+
generate_ppt(outline_path,ppt_template_path,generate_ppt_prompt,model=model_name, config=config)
|
| 156 |
+
|
| 157 |
+
# === Refiner ===
|
| 158 |
+
refinement_ppt(input_index=auto_path, prompts=[commenter_prompt, reviser_prompt], model=model_name, max_iterations=3, config=config)
|
| 159 |
+
|
| 160 |
+
# ============================= Poster部分 ================================
|
| 161 |
+
|
| 162 |
+
poster_outline_path = os.path.join(auto_path, "poster_outline.txt")
|
| 163 |
+
|
| 164 |
+
print(f"📝 Generating poster outline at: {poster_outline_path}")
|
| 165 |
+
generate_poster_outline_txt(dag_path=dag_path,poster_outline_path=poster_outline_path,poster_outline_prompt=poster_outline_prompt,model=model_name, config=config)
|
| 166 |
+
print (f"✅ Poster outline generated.")
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
poster_path=os.path.join(auto_path, "poster.html")
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
subdir_name = Path(subdir_path).name
|
| 173 |
+
poster_outline_path_modified = os.path.join(auto_path, "poster_outline_modified.txt")
|
| 174 |
+
print(f"📝 Modifying poster outline for paper: {subdir_name}")
|
| 175 |
+
modify_poster_outline(poster_outline_path=poster_outline_path,poster_paper_name=subdir_name,modified_poster_outline_path=poster_outline_path_modified)
|
| 176 |
+
print (f"✅ Poster outline modified.")
|
| 177 |
+
|
| 178 |
+
modified_poster_logic(poster_outline_path_modified, modified_poster_logic_prompt, model=model_name, config=config)
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
print(f"🖼️ Building poster HTML at: {poster_path}")
|
| 182 |
+
build_poster_from_outline(poster_outline_path=poster_outline_path_modified,poster_template_path="./poster_template/poster_template.html",poster_path=poster_path,)
|
| 183 |
+
print (f"✅ Poster HTML built.")
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
print(f"🖊️ Modifying title and authors in poster HTML...")
|
| 187 |
+
modify_title_and_author(dag_path=dag_path,poster_path=poster_path)
|
| 188 |
+
print (f"✅ Title and authors modified.")
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
poster_final_index = os.path.join(auto_path, "final")
|
| 192 |
+
os.makedirs(poster_final_index, exist_ok=True)
|
| 193 |
+
|
| 194 |
+
poster_final_output_path = os.path.join(poster_final_index, "poster_final.html")
|
| 195 |
+
print(f"🖊️ Refining poster HTML with Gemini...")
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
out = inject_img_section_to_poster(figure_path="./poster_template/expore_our_work_in_detail.jpg",auto_path=auto_path,poster_path=poster_path)
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
refinement_poster(input_html_path=poster_path, prompts=poster_refinement_prompt,output_html_path=poster_final_output_path,model=model_name, config=config)
|
| 204 |
+
|
| 205 |
+
print (f"✅ Poster HTML refined. Final poster at: {poster_final_output_path}")
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
# ============================= PR部分 ================================
|
| 209 |
+
pr_template_path="./pr_template.md"
|
| 210 |
+
basic_information_path = extract_basic_information(dag_path=dag_path, auto_path=auto_path,extract_basic_information_prompt=extract_basic_information_prompt,model=model_name, config=config)
|
| 211 |
+
|
| 212 |
+
initialize_pr_markdown(basic_information_path=basic_information_path,auto_path=auto_path,pr_template_path=pr_template_path)
|
| 213 |
+
|
| 214 |
+
pr_path=os.path.join(auto_path, "markdown.md")
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
generate_pr_from_dag(dag_path=dag_path, pr_path=pr_path, generate_pr_prompt=generate_pr_prompt, model=model_name, config=config)
|
| 218 |
+
print(f"📝 PR generated at: {pr_path}")
|
| 219 |
+
|
| 220 |
+
add_title_and_hashtag(pr_path=pr_path, add_title_and_hashtag_prompt=add_title_and_hashtag_prompt, model=model_name, config=config)
|
| 221 |
+
add_institution_tag(pr_path=pr_path)
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
dedup_consecutive_markdown_images(pr_path, inplace=True)
|
| 226 |
+
|
| 227 |
+
print(f"✅ PR markdown post-processed.")
|
| 228 |
+
|
| 229 |
+
print(f"🖊️ Refining PR markdown with LLM...")
|
| 230 |
+
pr_refine_path=os.path.join(auto_path, "markdown_refined.md")
|
| 231 |
+
|
| 232 |
+
refinement_pr(pr_path=pr_path, pr_refine_path=pr_refine_path, prompts=pr_refinement_prompt, model=model_name, config=config)
|
| 233 |
+
print (f"✅ PR markdown refined.")
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
# =============================================================
|
| 238 |
+
# 在auto目录下创建success.txt作为标志
|
| 239 |
+
success_file_path = os.path.join(auto_path, "success.txt")
|
| 240 |
+
open(success_file_path, "w").close()
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
print(f"✅ Finished processing: {subdir}\n{'-' * 80}")
|
| 245 |
+
|
| 246 |
+
print("\n🎉 All papers processed successfully!")
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
if __name__ == "__main__":
|
| 250 |
+
main()
|
mineru_outputs/readme.txt.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
mineru_outputs
|
papers/readme.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
add papers here
|
poster_template/expore_our_work_in_detail.jpg
ADDED
|
Git LFS Details
|
poster_template/poster_template.html
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
|
| 3 |
+
<html lang="zh-CN">
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="utf-8"/>
|
| 6 |
+
<title>Poster Template - HSCR (Stable Columns)</title>
|
| 7 |
+
<style>
|
| 8 |
+
:root{
|
| 9 |
+
--poster-width: 1400px;
|
| 10 |
+
--poster-height: 900px;
|
| 11 |
+
|
| 12 |
+
--header-bg: #cfe9ff;
|
| 13 |
+
--border: #1f1f1f;
|
| 14 |
+
--gap: 18px;
|
| 15 |
+
|
| 16 |
+
--section-bar: #0b3d91;
|
| 17 |
+
|
| 18 |
+
/* ===== 可压缩参数 ===== */
|
| 19 |
+
--base-font: 16px;
|
| 20 |
+
--line-height: 1.35;
|
| 21 |
+
--para-gap: 10px;
|
| 22 |
+
--li-gap: 6px;
|
| 23 |
+
--img-max-width: 100%;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
*{ box-sizing: border-box; }
|
| 27 |
+
|
| 28 |
+
body{
|
| 29 |
+
margin: 0;
|
| 30 |
+
background: #e9eef5;
|
| 31 |
+
font-family: "Comic Sans MS", cursive;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
.stage{
|
| 35 |
+
min-height: 100vh;
|
| 36 |
+
display: grid;
|
| 37 |
+
place-items: center;
|
| 38 |
+
padding: 24px;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
.poster{
|
| 42 |
+
width: var(--poster-width);
|
| 43 |
+
height: var(--poster-height);
|
| 44 |
+
background: #fff;
|
| 45 |
+
border: 3px solid var(--border);
|
| 46 |
+
display: grid;
|
| 47 |
+
grid-template-rows: 2fr 11fr;
|
| 48 |
+
overflow: hidden;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
/* ===== Header ===== */
|
| 52 |
+
.header{
|
| 53 |
+
background: var(--header-bg);
|
| 54 |
+
border-bottom: 3px solid var(--border);
|
| 55 |
+
padding: 6px 8px;
|
| 56 |
+
display: grid;
|
| 57 |
+
grid-template-columns: 7fr 1fr;
|
| 58 |
+
gap: var(--gap);
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
.title{
|
| 62 |
+
margin: 0;
|
| 63 |
+
font-size: 28px;
|
| 64 |
+
font-weight: 800;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
.authors{
|
| 68 |
+
margin-top: 6px;
|
| 69 |
+
font-size: 20px;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
.conf{
|
| 73 |
+
border-left: 3px solid var(--border);
|
| 74 |
+
display: flex;
|
| 75 |
+
align-items: center;
|
| 76 |
+
justify-content: center;
|
| 77 |
+
font-size: 42px;
|
| 78 |
+
font-weight: 800;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
/* ===== Main ===== */
|
| 82 |
+
.main{
|
| 83 |
+
padding: 18px;
|
| 84 |
+
overflow: hidden;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
.flow{
|
| 88 |
+
height: 100%;
|
| 89 |
+
column-count: 3;
|
| 90 |
+
column-gap: var(--gap);
|
| 91 |
+
column-fill: auto;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
/* ===== Sections ===== */
|
| 95 |
+
.section{
|
| 96 |
+
margin-bottom: 18px;
|
| 97 |
+
break-inside: auto;
|
| 98 |
+
background: #eef6ff;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
.section-bar{
|
| 102 |
+
background: var(--section-bar);
|
| 103 |
+
color: #fff;
|
| 104 |
+
font-weight: 800;
|
| 105 |
+
font-size: 20px;
|
| 106 |
+
padding: 5px 6px;
|
| 107 |
+
border-radius: 10px;
|
| 108 |
+
margin-bottom: 8px;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
.section-body{
|
| 112 |
+
font-size: var(--base-font);
|
| 113 |
+
line-height: var(--line-height);
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
.section-body p{
|
| 117 |
+
margin: 0 0 var(--para-gap) 0;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
.section-body ul{
|
| 121 |
+
margin: 0 0 var(--para-gap) 20px;
|
| 122 |
+
padding: 0;
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
.section-body li{
|
| 126 |
+
margin-bottom: var(--li-gap);
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
.img-section {
|
| 130 |
+
display: flex;
|
| 131 |
+
justify-content: center;
|
| 132 |
+
align-items: center;
|
| 133 |
+
gap: 8px;
|
| 134 |
+
margin: 0 0 var(--para-gap) 0;
|
| 135 |
+
width: 100%;
|
| 136 |
+
overflow: hidden;
|
| 137 |
+
box-sizing: border-box;
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
.img-section img {
|
| 141 |
+
flex: 1;
|
| 142 |
+
|
| 143 |
+
min-width: 0;
|
| 144 |
+
max-width: var(--img-max-width);
|
| 145 |
+
height: auto;
|
| 146 |
+
|
| 147 |
+
object-fit: contain;
|
| 148 |
+
border: 1px solid #000;
|
| 149 |
+
|
| 150 |
+
margin: 0;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
</style>
|
| 154 |
+
</head>
|
| 155 |
+
|
| 156 |
+
<body>
|
| 157 |
+
<div class="stage">
|
| 158 |
+
<div class="poster">
|
| 159 |
+
|
| 160 |
+
<header class="header">
|
| 161 |
+
<div>
|
| 162 |
+
<h1 class="title">HSCR: Hierarchical Self-Contrastive Rewarding for Aligning Medical Vision Language Models</h1>
|
| 163 |
+
<div class="authors">Songtao Jiang1, Yan Zhang2, Yeying Jin3, Zhihang Tang1 Yangyang Wu1, Yang Feng4, Jian Wu1,5, Zuozhu Liu1,5†
|
| 164 |
+
</div>
|
| 165 |
+
</div>
|
| 166 |
+
<div class="conf">ICML</div>
|
| 167 |
+
</header>
|
| 168 |
+
|
| 169 |
+
<main class="main">
|
| 170 |
+
<div class="flow" id="flow">
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
</div>
|
| 176 |
+
</main>
|
| 177 |
+
|
| 178 |
+
</div>
|
| 179 |
+
</div>
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
<!--The following content is strictly prohibited from being modified and must be kept in its original form.-->
|
| 183 |
+
<script>
|
| 184 |
+
(function(){
|
| 185 |
+
const flow = document.getElementById("flow");
|
| 186 |
+
const root = document.documentElement;
|
| 187 |
+
|
| 188 |
+
// 基础设置工具函数
|
| 189 |
+
function setVar(k,v,u=""){ root.style.setProperty(k, v+u); }
|
| 190 |
+
|
| 191 |
+
// 溢出检测(背包是否破裂)
|
| 192 |
+
function overflowColumns(){
|
| 193 |
+
return flow.scrollWidth > flow.clientWidth + 1;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
// 常量设定
|
| 197 |
+
const PARA_GAP = 12; // para-gap 取定值 (px)
|
| 198 |
+
|
| 199 |
+
// 边界设定 (Constraint 3)
|
| 200 |
+
const MIN_FONT = 10, MAX_FONT = 20; // base-font 范围
|
| 201 |
+
|
| 202 |
+
// 图片大小范围调整为 70% ~ 100%
|
| 203 |
+
const MIN_IMG = 60, MAX_IMG = 100;
|
| 204 |
+
|
| 205 |
+
// 步长设定 (Constraint 4)
|
| 206 |
+
const STEP_FONT = 0.1;
|
| 207 |
+
const STEP_IMG = 1;
|
| 208 |
+
|
| 209 |
+
// 辅助函数:计算依赖变量 (line-height 和 li-gap)
|
| 210 |
+
// 为了保证排版美观,这两个参数应当随字体大小动态变化
|
| 211 |
+
function getDependentVars(f) {
|
| 212 |
+
// 计算当前字体在 [MIN, MAX] 区间内的比例 (0.0 ~ 1.0)
|
| 213 |
+
const ratio = (f - MIN_FONT) / (MAX_FONT - MIN_FONT);
|
| 214 |
+
|
| 215 |
+
// line-height: 范围调整为 1.05 ~ 1.6
|
| 216 |
+
// 计算:基数 1.05 + (区间跨度 0.55 * 比例)
|
| 217 |
+
let lh = 1.05 + ratio * 0.55;
|
| 218 |
+
|
| 219 |
+
// li-gap: 范围调整为 2px ~ 8px
|
| 220 |
+
// 计算:基数 2 + (区间跨度 6 * 比例)
|
| 221 |
+
let lg = 2 + ratio * 6;
|
| 222 |
+
|
| 223 |
+
return { lh, lg };
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
// 尝试将特定大小的“物品”装入“背包”
|
| 227 |
+
// 返回 true 表示装得下,false 表示溢出
|
| 228 |
+
function tryFit(f, w) {
|
| 229 |
+
// 格式化精度
|
| 230 |
+
f = Math.round(f * 10) / 10;
|
| 231 |
+
w = Math.round(w);
|
| 232 |
+
|
| 233 |
+
const { lh, lg } = getDependentVars(f);
|
| 234 |
+
|
| 235 |
+
// 应用样式
|
| 236 |
+
setVar("--base-font", f, "px");
|
| 237 |
+
setVar("--img-max-width", w, "%");
|
| 238 |
+
setVar("--line-height", lh.toFixed(3));
|
| 239 |
+
setVar("--li-gap", lg.toFixed(1), "px");
|
| 240 |
+
setVar("--para-gap", PARA_GAP, "px");
|
| 241 |
+
|
| 242 |
+
// 检查容量
|
| 243 |
+
return !overflowColumns();
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
// 主算法:背包资源分��� (二分查找 + 贪心策略)
|
| 247 |
+
function fit(){
|
| 248 |
+
// 重置状态
|
| 249 |
+
setVar("--img-max-width",100,"%");
|
| 250 |
+
setVar("--base-font",16,"px");
|
| 251 |
+
|
| 252 |
+
// 阶段一:优先最大化 Font Size (高价值物品)
|
| 253 |
+
// 策略:假设图片使用最小尺寸(MIN_IMG),寻找能容纳的最大字体
|
| 254 |
+
let low = MIN_FONT;
|
| 255 |
+
let high = MAX_FONT;
|
| 256 |
+
let bestFont = MIN_FONT;
|
| 257 |
+
|
| 258 |
+
// 二分查找最佳字体
|
| 259 |
+
while (low <= high) {
|
| 260 |
+
let mid = (low + high) / 2;
|
| 261 |
+
// 按照精度步长对齐
|
| 262 |
+
mid = Math.floor(mid / STEP_FONT) * STEP_FONT;
|
| 263 |
+
|
| 264 |
+
if (tryFit(mid, MIN_IMG)) {
|
| 265 |
+
bestFont = mid; // 记录当前可行解
|
| 266 |
+
low = mid + STEP_FONT; // 尝试更大的
|
| 267 |
+
} else {
|
| 268 |
+
high = mid - STEP_FONT; // 尝试更小的
|
| 269 |
+
}
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
// 阶段二:在确定最佳字体后,最大化 Image Width (填充剩余空间)
|
| 273 |
+
// 策略:固定字体为 bestFont,寻找能容纳的最大图片宽度
|
| 274 |
+
let wLow = MIN_IMG;
|
| 275 |
+
let wHigh = MAX_IMG;
|
| 276 |
+
let bestImg = MIN_IMG;
|
| 277 |
+
|
| 278 |
+
while (wLow <= wHigh) {
|
| 279 |
+
let mid = Math.floor((wLow + wHigh) / 2);
|
| 280 |
+
|
| 281 |
+
if (tryFit(bestFont, mid)) {
|
| 282 |
+
bestImg = mid; // 记录当前可行解
|
| 283 |
+
wLow = mid + STEP_IMG; // 尝试更大的
|
| 284 |
+
} else {
|
| 285 |
+
wHigh = mid - STEP_IMG; // 尝试更小的
|
| 286 |
+
}
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
// 应用最终找到的最优解 (全局最优配置)
|
| 290 |
+
tryFit(bestFont, bestImg);
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
// 事件监听保持不变
|
| 294 |
+
window.addEventListener("load", fit);
|
| 295 |
+
|
| 296 |
+
window.addEventListener("resize", () => {
|
| 297 |
+
clearTimeout(window.__fitTimer);
|
| 298 |
+
window.__fitTimer = setTimeout(fit, 80);
|
| 299 |
+
});
|
| 300 |
+
|
| 301 |
+
const mo = new MutationObserver(() => {
|
| 302 |
+
clearTimeout(window.__fitTimer2);
|
| 303 |
+
window.__fitTimer2 = setTimeout(fit, 80);
|
| 304 |
+
});
|
| 305 |
+
mo.observe(flow, { childList: true, subtree: true, characterData: true });
|
| 306 |
+
|
| 307 |
+
function hookImages(){
|
| 308 |
+
const imgs = flow.querySelectorAll("img");
|
| 309 |
+
imgs.forEach(img=>{
|
| 310 |
+
if (img.__fitHooked) return;
|
| 311 |
+
img.__fitHooked = true;
|
| 312 |
+
img.addEventListener("load", () => setTimeout(fit, 50));
|
| 313 |
+
img.addEventListener("error", () => setTimeout(fit, 50));
|
| 314 |
+
});
|
| 315 |
+
}
|
| 316 |
+
hookImages();
|
| 317 |
+
const mo2 = new MutationObserver(hookImages);
|
| 318 |
+
mo2.observe(flow, { childList: true, subtree: true });
|
| 319 |
+
|
| 320 |
+
})();
|
| 321 |
+
</script>
|
| 322 |
+
|
| 323 |
+
</body>
|
| 324 |
+
</html>
|
ppt_template/Contents.html
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.contents-list {
|
| 13 |
+
font-family: 'Calibri', sans-serif;
|
| 14 |
+
font-size: 28.0pt;
|
| 15 |
+
color: #ffffff;
|
| 16 |
+
|
| 17 |
+
line-height: 1.45;
|
| 18 |
+
margin: 0;
|
| 19 |
+
padding: 0;
|
| 20 |
+
list-style-type: none;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
.contents-list li {
|
| 24 |
+
white-space: nowrap;
|
| 25 |
+
overflow: hidden;
|
| 26 |
+
text-overflow: ellipsis;
|
| 27 |
+
|
| 28 |
+
padding-bottom: 5px;
|
| 29 |
+
}
|
| 30 |
+
</style>
|
| 31 |
+
</head>
|
| 32 |
+
<body>
|
| 33 |
+
<div class="slide" name="slide" id="slide1">
|
| 34 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 35 |
+
<defs />
|
| 36 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 37 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M0 102L960.2 102 960.2 500.7 0 485.7z" shape-id="14" />
|
| 41 |
+
|
| 42 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 17.95, 18.6)">
|
| 43 |
+
<text font-family="Calibri" font-weight="bold" font-size="40.5pt" fill="#143f5e">
|
| 44 |
+
<tspan x="0" y="55.75">CONTENTS</tspan>
|
| 45 |
+
</text>
|
| 46 |
+
</g>
|
| 47 |
+
|
| 48 |
+
<!--
|
| 49 |
+
You need to revise the following parts.
|
| 50 |
+
-->
|
| 51 |
+
<foreignObject x="40" y="110" width="900" height="450">
|
| 52 |
+
<div xmlns="http://www.w3.org/1999/xhtml">
|
| 53 |
+
<ul class="contents-list">
|
| 54 |
+
<li>1. Motivation and Background</li>
|
| 55 |
+
<li>2. Key Contributions</li>
|
| 56 |
+
<li>3. Methods Overview</li>
|
| 57 |
+
<li>4. Experiments and Datasets</li>
|
| 58 |
+
<li>5. Results and Analysis</li>
|
| 59 |
+
<li>6. Conclusion and Future Work</li>
|
| 60 |
+
</ul>
|
| 61 |
+
</div>
|
| 62 |
+
</foreignObject>
|
| 63 |
+
|
| 64 |
+
</g>
|
| 65 |
+
</svg>
|
| 66 |
+
</div>
|
| 67 |
+
</body>
|
| 68 |
+
</html>
|
ppt_template/T10_4Img_2×2Grid.html
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: column;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 15px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 66 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 67 |
+
|
| 68 |
+
<div id="1-row-field" style="flex: 1; display: flex; flex-direction: row; gap: 20px; height: 100%; overflow: hidden;">
|
| 69 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 70 |
+
<!-- You need to revise the following parts. 2: image -->
|
| 71 |
+
<img src="images/4.png" class="slide-img" alt="Top Left" />
|
| 72 |
+
</div>
|
| 73 |
+
<div id="1-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 74 |
+
<!-- You need to revise the following parts. 3: image -->
|
| 75 |
+
<img src="images/4.png" class="slide-img" alt="Top Right" />
|
| 76 |
+
</div>
|
| 77 |
+
</div>
|
| 78 |
+
|
| 79 |
+
<div id="2-row-field" style="flex: 1; display: flex; flex-direction: row; gap: 20px; height: 100%; overflow: hidden;">
|
| 80 |
+
<div id="2-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 81 |
+
<!-- You need to revise the following parts. 4: image -->
|
| 82 |
+
<img src="images/4.png" class="slide-img" alt="Bottom Left" />
|
| 83 |
+
</div>
|
| 84 |
+
<div id="2-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 85 |
+
<!-- You need to revise the following parts. 5: image -->
|
| 86 |
+
<img src="images/4.png" class="slide-img" alt="Bottom Right" />
|
| 87 |
+
</div>
|
| 88 |
+
</div>
|
| 89 |
+
|
| 90 |
+
</div>
|
| 91 |
+
</foreignObject>
|
| 92 |
+
|
| 93 |
+
</g>
|
| 94 |
+
</svg>
|
| 95 |
+
</div>
|
| 96 |
+
</body>
|
| 97 |
+
</html>
|
ppt_template/T11_3Img_TopTextBottom.html
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: column;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 15px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 67 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 68 |
+
|
| 69 |
+
<div id="1-row-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 70 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 71 |
+
<!-- You need to revise the following parts. 2: images -->
|
| 72 |
+
<img src="images/5_1.png" class="slide-img" alt="Image 1" />
|
| 73 |
+
</div>
|
| 74 |
+
<div id="1-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 75 |
+
<!-- You need to revise the following parts. 3: images -->
|
| 76 |
+
<img src="images/5_1.png" class="slide-img" alt="Image 2" />
|
| 77 |
+
</div>
|
| 78 |
+
<div id="1-3-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 79 |
+
<!-- You need to revise the following parts. 4: images -->
|
| 80 |
+
<img src="images/5_3.png" class="slide-img" alt="Image 3" />
|
| 81 |
+
</div>
|
| 82 |
+
</div>
|
| 83 |
+
|
| 84 |
+
<div id="2-row-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 85 |
+
<div id="2-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 18pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 10px 25px;">
|
| 86 |
+
<!-- You need to revise the following parts. 5: text -->
|
| 87 |
+
<strong>Overview of Layered Dynamics</strong><br/>
|
| 88 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose. Within this wandering expanse, a procession of intangible echoes shimmers faintly, attempting to articulate a message that dissolves the moment it forms.
|
| 89 |
+
</div>
|
| 90 |
+
</div>
|
| 91 |
+
|
| 92 |
+
</div>
|
| 93 |
+
</foreignObject>
|
| 94 |
+
|
| 95 |
+
</g>
|
| 96 |
+
</svg>
|
| 97 |
+
</div>
|
| 98 |
+
</body>
|
| 99 |
+
</html>
|
ppt_template/T12_3Img_BottomTextTop.html
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: column;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 15px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
<foreignObject x="28" y="85" width="900" height="400">
|
| 66 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 67 |
+
|
| 68 |
+
<div id="1-row-field" style="flex: 2; display: flex; flex-direction: row; gap: 15px; height: 100%; overflow: hidden;">
|
| 69 |
+
<div id="1-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 19pt; color: #000000; line-height: 1.15; text-align: left; overflow: hidden; padding: 10px 25px;">
|
| 70 |
+
<!-- You need to revise the following parts. 2: Text -->
|
| 71 |
+
<strong>Introduction to Tri-Visual Analysis</strong><br/>
|
| 72 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose. This section explores the relationship between structural integrity and visual perception through three distinct lenses shown below.
|
| 73 |
+
</div>
|
| 74 |
+
</div>
|
| 75 |
+
|
| 76 |
+
<div id="2-row-field" style="flex: 3; display: flex; flex-direction: row; gap: 15px; height: 100%; overflow: hidden;">
|
| 77 |
+
|
| 78 |
+
<div id="2-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 79 |
+
<!-- You need to revise the following parts. 3: Image -->
|
| 80 |
+
<img src="images/4.png" class="slide-img" alt="Left Image" />
|
| 81 |
+
</div>
|
| 82 |
+
|
| 83 |
+
<div id="2-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 84 |
+
<!-- You need to revise the following parts. 4: Image -->
|
| 85 |
+
<img src="images/4.png" class="slide-img" alt="Center Image" />
|
| 86 |
+
</div>
|
| 87 |
+
|
| 88 |
+
<div id="2-3-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 89 |
+
<!-- You need to revise the following parts. 5: Image -->
|
| 90 |
+
<img src="images/4.png" class="slide-img" alt="Right Image" />
|
| 91 |
+
</div>
|
| 92 |
+
|
| 93 |
+
</div>
|
| 94 |
+
|
| 95 |
+
</div>
|
| 96 |
+
</foreignObject>
|
| 97 |
+
|
| 98 |
+
</g>
|
| 99 |
+
</svg>
|
| 100 |
+
</div>
|
| 101 |
+
</body>
|
| 102 |
+
</html>
|
ppt_template/T13_3Img.html
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
.slideImage {
|
| 7 |
+
border: 1px solid #BBBBBB;
|
| 8 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
.layout-container {
|
| 12 |
+
display: flex;
|
| 13 |
+
flex-direction: row;
|
| 14 |
+
width: 100%;
|
| 15 |
+
height: 100%;
|
| 16 |
+
gap: 20px;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.slide-img {
|
| 20 |
+
max-width: 100%;
|
| 21 |
+
max-height: 100%;
|
| 22 |
+
width: auto;
|
| 23 |
+
height: auto;
|
| 24 |
+
object-fit: contain;
|
| 25 |
+
}
|
| 26 |
+
</style>
|
| 27 |
+
</head>
|
| 28 |
+
<body>
|
| 29 |
+
<div class="slide" name="slide" id="slide1">
|
| 30 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 31 |
+
<defs />
|
| 32 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 33 |
+
|
| 34 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 35 |
+
|
| 36 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 37 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 38 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 39 |
+
</g>
|
| 40 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 41 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 42 |
+
</g>
|
| 43 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 44 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 45 |
+
</g>
|
| 46 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 47 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 48 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 49 |
+
</g>
|
| 50 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 51 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 52 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 53 |
+
</g>
|
| 54 |
+
|
| 55 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 56 |
+
|
| 57 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 58 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 59 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 60 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 61 |
+
</text>
|
| 62 |
+
</g>
|
| 63 |
+
|
| 64 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 65 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 66 |
+
|
| 67 |
+
<div id="1-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 68 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 69 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 70 |
+
<img src="images/4.png" class="slide-img" alt="Left Image" />
|
| 71 |
+
</div>
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
<div id="2-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 75 |
+
<div id="2-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 76 |
+
<!-- You need to revise the following parts. 3: Image -->
|
| 77 |
+
<img src="images/4.png" class="slide-img" alt="Center Image" />
|
| 78 |
+
</div>
|
| 79 |
+
</div>
|
| 80 |
+
|
| 81 |
+
<div id="3-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 82 |
+
<div id="3-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 83 |
+
<!-- You need to revise the following parts. 4: Image -->
|
| 84 |
+
<img src="images/4.png" class="slide-img" alt="Right Image" />
|
| 85 |
+
</div>
|
| 86 |
+
</div>
|
| 87 |
+
|
| 88 |
+
</div>
|
| 89 |
+
</foreignObject>
|
| 90 |
+
|
| 91 |
+
</g>
|
| 92 |
+
</svg>
|
| 93 |
+
</div>
|
| 94 |
+
</body>
|
| 95 |
+
</html>
|
ppt_template/T14_ImageRight_1Formula.html
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
/* 保留原有的 slideImage, layout-container, slide-img 样式 */
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB;
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: row;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 20px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 66 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 67 |
+
|
| 68 |
+
<div id="1-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 69 |
+
|
| 70 |
+
<div id="1-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 20pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 10px 25px;">
|
| 71 |
+
<!-- You need to revise the following parts. 2: Text -->
|
| 72 |
+
<strong>Detailed Explanation</strong><br/>
|
| 73 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose. This section details the primary visual focus alongside its subtle underlying signature, illustrated in the right panel.
|
| 74 |
+
</div>
|
| 75 |
+
</div>
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
<div id="2-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 79 |
+
|
| 80 |
+
<div id="2-1-image-block" style="flex: 2; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 81 |
+
<!-- You need to revise the following parts. 3: Image -->
|
| 82 |
+
<img src="images/4.png" class="slide-img" alt="Main Image" />
|
| 83 |
+
</div>
|
| 84 |
+
|
| 85 |
+
<div id="2-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 86 |
+
<!-- You need to revise the following parts. 4: Image -->
|
| 87 |
+
<img src="images/5_1.png" class="slide-img" alt="Signature Image" />
|
| 88 |
+
</div>
|
| 89 |
+
|
| 90 |
+
</div>
|
| 91 |
+
|
| 92 |
+
</div>
|
| 93 |
+
</foreignObject>
|
| 94 |
+
|
| 95 |
+
</g>
|
| 96 |
+
</svg>
|
| 97 |
+
</div>
|
| 98 |
+
</body>
|
| 99 |
+
</html>
|
ppt_template/T15_ImageLeft_1Formula.html
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: row;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 20px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 66 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 67 |
+
|
| 68 |
+
<div id="1-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 69 |
+
|
| 70 |
+
<div id="1-1-image-block" style="flex: 2; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 71 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 72 |
+
<img src="images/4.png" class="slide-img" alt="Main Left Image" />
|
| 73 |
+
</div>
|
| 74 |
+
<div id="1-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 75 |
+
<!-- You need to revise the following parts. 3: Image -->
|
| 76 |
+
<img src="images/5_1.png" class="slide-img" alt="Sub Left Image" />
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
|
| 80 |
+
<div id="2-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 81 |
+
<div id="2-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 20pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 10px 25px;">
|
| 82 |
+
<!-- You need to revise the following parts. 4: Text -->
|
| 83 |
+
<strong>Visual Hierarchy Analysis</strong><br/>
|
| 84 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose. The prominent structure on the left demonstrates the primary form, while the lower segment captures the transient details often overlooked.
|
| 85 |
+
</div>
|
| 86 |
+
</div>
|
| 87 |
+
|
| 88 |
+
</div>
|
| 89 |
+
</foreignObject>
|
| 90 |
+
|
| 91 |
+
</g>
|
| 92 |
+
</svg>
|
| 93 |
+
</div>
|
| 94 |
+
</body>
|
| 95 |
+
</html>
|
ppt_template/T16_1Img_2Formula_TopTextBottom.html
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
.slideImage {
|
| 7 |
+
border: 1px solid #BBBBBB;
|
| 8 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
.layout-container {
|
| 12 |
+
display: flex;
|
| 13 |
+
flex-direction: column;
|
| 14 |
+
width: 100%;
|
| 15 |
+
height: 100%;
|
| 16 |
+
gap: 8px;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.slide-img {
|
| 20 |
+
max-width: 100%;
|
| 21 |
+
max-height: 100%;
|
| 22 |
+
width: auto;
|
| 23 |
+
height: auto;
|
| 24 |
+
object-fit: contain;
|
| 25 |
+
}
|
| 26 |
+
</style>
|
| 27 |
+
</head>
|
| 28 |
+
<body>
|
| 29 |
+
<div class="slide" name="slide" id="slide1">
|
| 30 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 31 |
+
<defs />
|
| 32 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 33 |
+
|
| 34 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 35 |
+
|
| 36 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 37 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 38 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 39 |
+
</g>
|
| 40 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 41 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 42 |
+
</g>
|
| 43 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 44 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 45 |
+
</g>
|
| 46 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 47 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 48 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 49 |
+
</g>
|
| 50 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 51 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 52 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 53 |
+
</g>
|
| 54 |
+
|
| 55 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 56 |
+
|
| 57 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 58 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 59 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 60 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 61 |
+
</text>
|
| 62 |
+
</g>
|
| 63 |
+
|
| 64 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 65 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 66 |
+
<div id="1-row-field"; style="flex: 4; display: flex; flex-direction: column; gap: 8px; height: 100%; overflow: hidden;">
|
| 67 |
+
<div id="1-1-image-block" style="flex: 3; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 68 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 69 |
+
<img src="images/t_2.png" class="slide-img" alt="Row 1 (4/10)" />
|
| 70 |
+
</div>
|
| 71 |
+
<div id="1-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 72 |
+
<!-- You need to revise the following parts. 4: Image -->
|
| 73 |
+
<img src="images/5_1.png" class="slide-img" alt="Row 2 (1/10)" />
|
| 74 |
+
</div>
|
| 75 |
+
<div id="1-3-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 76 |
+
<!-- You need to revise the following parts. 5: Image -->
|
| 77 |
+
<img src="images/5_1.png" class="slide-img" alt="Row 3 (1/10)" />
|
| 78 |
+
</div>
|
| 79 |
+
</div>
|
| 80 |
+
|
| 81 |
+
<div id="2-row-field"; style="flex: 2; display: flex; flex-direction: column; gap: 8px; height: 100%; overflow: hidden;">
|
| 82 |
+
<div id="1-4-text-block" style="flex: 3; font-family: 'Calibri', sans-serif; font-size: 18pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 10px 25px;">
|
| 83 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose. The prominent structure on the left demonstrates the primary form, while the lower segment captures the transient details often overlooked.
|
| 84 |
+
</div>
|
| 85 |
+
</div>
|
| 86 |
+
</div>
|
| 87 |
+
</foreignObject>
|
| 88 |
+
|
| 89 |
+
</g>
|
| 90 |
+
</svg>
|
| 91 |
+
</div>
|
| 92 |
+
</body>
|
| 93 |
+
</html>
|
ppt_template/T17_2Img_1Formula_TopTextBottom.html
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: column;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 10px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 67 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 68 |
+
|
| 69 |
+
<div id="1-row-field" style="flex: 4.2; display: flex; flex-direction: row; gap: 20px; height: 100%; overflow: hidden;">
|
| 70 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 71 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 72 |
+
<img src="images/4.png" class="slide-img" alt="Top Left" />
|
| 73 |
+
</div>
|
| 74 |
+
<div id="1-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 75 |
+
<!-- You need to revise the following parts. 3: Image -->
|
| 76 |
+
<img src="images/4.png" class="slide-img" alt="Top Right" />
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
|
| 80 |
+
<div id="2-row-field" style="flex: 1.3; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 81 |
+
<div id="2-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 82 |
+
<!-- You need to revise the following parts. 4: Image -->
|
| 83 |
+
<img src="images/5_1.png" class="slide-img" alt="Middle Banner" />
|
| 84 |
+
</div>
|
| 85 |
+
</div>
|
| 86 |
+
|
| 87 |
+
<div id="3-row-field" style="flex: 4; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden; ">
|
| 88 |
+
<div id="3-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 18pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 5px 25px;">
|
| 89 |
+
<!-- You need to revise the following parts. 5: Text -->
|
| 90 |
+
<strong>Analysis of Spatial Relationships</strong>
|
| 91 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose. The upper visuals demonstrate the dual nature of the projection, while the central band represents the transformative threshold between these states.
|
| 92 |
+
</div>
|
| 93 |
+
</div>
|
| 94 |
+
|
| 95 |
+
</div>
|
| 96 |
+
</foreignObject>
|
| 97 |
+
|
| 98 |
+
</g>
|
| 99 |
+
</svg>
|
| 100 |
+
</div>
|
| 101 |
+
</body>
|
| 102 |
+
</html>
|
ppt_template/T18_2Formula_TopTextBottom.html
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
.slideImage {
|
| 7 |
+
border: 1px solid #BBBBBB;
|
| 8 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 9 |
+
}
|
| 10 |
+
.layout-container {
|
| 11 |
+
display: flex;
|
| 12 |
+
flex-direction: column;
|
| 13 |
+
width: 100%;
|
| 14 |
+
height: 100%;
|
| 15 |
+
gap: 5px;
|
| 16 |
+
}
|
| 17 |
+
.slide-img {
|
| 18 |
+
max-width: 100%;
|
| 19 |
+
max-height: 100%;
|
| 20 |
+
width: auto;
|
| 21 |
+
height: auto;
|
| 22 |
+
object-fit: contain;
|
| 23 |
+
}
|
| 24 |
+
</style>
|
| 25 |
+
</head>
|
| 26 |
+
<body>
|
| 27 |
+
<div class="slide" name="slide" id="slide1">
|
| 28 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 29 |
+
<defs />
|
| 30 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 31 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 32 |
+
|
| 33 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 34 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 35 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 36 |
+
</g>
|
| 37 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 38 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 39 |
+
</g>
|
| 40 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 41 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 42 |
+
</g>
|
| 43 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 44 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 45 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 50 |
+
</g>
|
| 51 |
+
|
| 52 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 53 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 54 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 55 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 56 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 57 |
+
</text>
|
| 58 |
+
</g>
|
| 59 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 60 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 61 |
+
<div id="1-col-field" style="flex: 1.6; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 62 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 63 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 64 |
+
<img src="images/5_1.png" class="slide-img" alt="Top Banner 1" />
|
| 65 |
+
</div>
|
| 66 |
+
</div>
|
| 67 |
+
<div id="2-col-field" style="flex: 1.6; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 68 |
+
<div id="2-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 69 |
+
<!-- You need to revise the following parts. 3: Image -->
|
| 70 |
+
<img src="images/5_1.png" class="slide-img" alt="Top Banner 2" />
|
| 71 |
+
</div>
|
| 72 |
+
</div>
|
| 73 |
+
<div id="3-col-field" style="flex: 7; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 74 |
+
<div id="3-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 20pt; color: #000000; line-height: 1.4; text-align: left; overflow: hidden; padding: 5px 25px;">
|
| 75 |
+
<!-- You need to revise the following parts. 4: Text -->
|
| 76 |
+
<strong>Comprehensive Review</strong><br/>
|
| 77 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose, weaving patterns that neither align with memory nor contradict the blurred architecture of imagined time. Within this wandering expanse, a procession of intangible echoes shimmers faintly, as if attempting to articulate a message that dissolves the moment it forms.The quick brown fox jumps over the lazy dog, illustrating the visual flow from the compact data headers above to the detailed exposition presented here.
|
| 78 |
+
</div>
|
| 79 |
+
</div>
|
| 80 |
+
</div>
|
| 81 |
+
</foreignObject>
|
| 82 |
+
</g>
|
| 83 |
+
</svg>
|
| 84 |
+
</div>
|
| 85 |
+
</body>
|
| 86 |
+
</html>
|
ppt_template/T19_2Text.html
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
.slideImage {
|
| 7 |
+
border: 1px solid #BBBBBB;
|
| 8 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 9 |
+
}
|
| 10 |
+
.layout-container {
|
| 11 |
+
display: flex;
|
| 12 |
+
flex-direction: row;
|
| 13 |
+
width: 100%;
|
| 14 |
+
height: 100%;
|
| 15 |
+
gap: 40px;
|
| 16 |
+
}
|
| 17 |
+
</style>
|
| 18 |
+
</head>
|
| 19 |
+
<body>
|
| 20 |
+
<div class="slide" name="slide" id="slide1">
|
| 21 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 22 |
+
<defs />
|
| 23 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 24 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 25 |
+
|
| 26 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 27 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 28 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 29 |
+
</g>
|
| 30 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 31 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 32 |
+
</g>
|
| 33 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 34 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 35 |
+
</g>
|
| 36 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 37 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 38 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 39 |
+
</g>
|
| 40 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 41 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 42 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 43 |
+
</g>
|
| 44 |
+
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 46 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 47 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 48 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 49 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 50 |
+
</text>
|
| 51 |
+
</g>
|
| 52 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 53 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 54 |
+
<div id="1-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 55 |
+
<div id="1-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 20pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 10px 30px;">
|
| 56 |
+
<!-- You need to revise the following parts. 2: Text -->
|
| 57 |
+
<strong>Part 1: Theoretical Basis</strong><br/>
|
| 58 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose. Weaving patterns that neither align with memory nor contradict the blurred architecture of imagined time, these elements form the foundation of our study.
|
| 59 |
+
</div>
|
| 60 |
+
</div>
|
| 61 |
+
|
| 62 |
+
<div id="2-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 63 |
+
<div id="2-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 20pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 10px 30px;">
|
| 64 |
+
<!-- You need to revise the following parts. 3: Text -->
|
| 65 |
+
<strong>Part 2: Implementation Details</strong><br/>
|
| 66 |
+
Within this wandering expanse, a procession of intangible echoes shimmers faintly. As if attempting to articulate a message that dissolves the moment it forms, the practical application requires careful observation of these transient signals to reconstruct the 3D reality.
|
| 67 |
+
</div>
|
| 68 |
+
</div>
|
| 69 |
+
</div>
|
| 70 |
+
</foreignObject>
|
| 71 |
+
</g>
|
| 72 |
+
</svg>
|
| 73 |
+
</div>
|
| 74 |
+
</body>
|
| 75 |
+
</html>
|
ppt_template/T1_TextOnly.html
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
.slideImage {
|
| 7 |
+
border: 1px solid #BBBBBB;
|
| 8 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
.layout-container {
|
| 12 |
+
display: flex;
|
| 13 |
+
flex-direction: row;
|
| 14 |
+
width: 100%;
|
| 15 |
+
height: 100%;
|
| 16 |
+
gap: 20px;
|
| 17 |
+
}
|
| 18 |
+
</style>
|
| 19 |
+
</head>
|
| 20 |
+
<body>
|
| 21 |
+
<div class="slide" name="slide" id="slide1">
|
| 22 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 23 |
+
<defs />
|
| 24 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 25 |
+
|
| 26 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 27 |
+
|
| 28 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 29 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 30 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 31 |
+
</g>
|
| 32 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 33 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 34 |
+
</g>
|
| 35 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 36 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 37 |
+
</g>
|
| 38 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 39 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 40 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 41 |
+
</g>
|
| 42 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 43 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 44 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 45 |
+
</g>
|
| 46 |
+
|
| 47 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 48 |
+
|
| 49 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 50 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 51 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 52 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 53 |
+
</text>
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 57 |
+
|
| 58 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 59 |
+
<div id="1-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 60 |
+
<div id="1-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 21pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 0 25px;">
|
| 61 |
+
<!-- You need to revise the following parts. 2: Text -->
|
| 62 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose, weaving patterns that neither align with memory nor contradict the blurred architecture of imagined time. Within this wandering expanse, a procession of intangible echoes shimmers faintly, as if attempting to articulate a message that dissolves the moment it forms. Yet the procession continues, not out of intention, but out of a peculiar inertia that guides every unreal sequence through its own recursive haze. Shadows of forgotten mechanisms revolve slowly, producing rhythms no ear has ever catalogued.
|
| 63 |
+
</div>
|
| 64 |
+
</div>
|
| 65 |
+
</div>
|
| 66 |
+
</foreignObject>
|
| 67 |
+
|
| 68 |
+
</g>
|
| 69 |
+
</svg>
|
| 70 |
+
</div>
|
| 71 |
+
</body>
|
| 72 |
+
</html>
|
ppt_template/T20_FormulaTop.html
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
.slideImage {
|
| 7 |
+
border: 1px solid #BBBBBB;
|
| 8 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
.layout-container {
|
| 12 |
+
display: flex;
|
| 13 |
+
flex-direction: column;
|
| 14 |
+
width: 100%;
|
| 15 |
+
height: 100%;
|
| 16 |
+
gap: 15px;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.slide-img {
|
| 20 |
+
max-width: 100%;
|
| 21 |
+
max-height: 100%;
|
| 22 |
+
width: auto;
|
| 23 |
+
height: auto;
|
| 24 |
+
object-fit: contain;
|
| 25 |
+
}
|
| 26 |
+
</style>
|
| 27 |
+
</head>
|
| 28 |
+
<body>
|
| 29 |
+
<div class="slide" name="slide" id="slide1">
|
| 30 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 31 |
+
<defs />
|
| 32 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 33 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 34 |
+
|
| 35 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 36 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 37 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 38 |
+
</g>
|
| 39 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 40 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 41 |
+
</g>
|
| 42 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 43 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 44 |
+
</g>
|
| 45 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 46 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 47 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 48 |
+
</g>
|
| 49 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 50 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 51 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 52 |
+
</g>
|
| 53 |
+
|
| 54 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 55 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 56 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 57 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 58 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 59 |
+
</text>
|
| 60 |
+
</g>
|
| 61 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 62 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container">
|
| 63 |
+
<div id="1-row-field" style="flex: 1; display: flex; flex-direction: row; gap: 10px; height: 100%; overflow: hidden;">
|
| 64 |
+
<div id="1-1-image-block" style="flex:1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 65 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 66 |
+
<img src="images/5_2.png" class="slide-img" alt="Slide Image" />
|
| 67 |
+
</div>
|
| 68 |
+
</div>
|
| 69 |
+
<div id="2-row-field" style="flex: 2; display: flex; flex-direction: row; gap: 10px; height: 100%; overflow:hidden">
|
| 70 |
+
<div id="2-1-text-block" style="flex:1; font-family: 'Calibri', sans-serif; font-size: 18pt; color: #000000; line-height: 1.2; text-align: left; overflow: hidden; padding: 0 15px;">
|
| 71 |
+
<!-- You need to revise the following parts. 3: Text -->
|
| 72 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose, weaving patterns of imagined time.In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose, weaving patterns of imagined time.In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose, weaving patterns of imagined time.In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose, weaving patterns of imagined time.
|
| 73 |
+
</div>
|
| 74 |
+
</div>
|
| 75 |
+
</div>
|
| 76 |
+
</foreignObject>
|
| 77 |
+
</g>
|
| 78 |
+
</svg>
|
| 79 |
+
</div>
|
| 80 |
+
</body>
|
| 81 |
+
</html>
|
ppt_template/T21_3Img_col.html
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
.slideImage {
|
| 7 |
+
border: 1px solid #BBBBBB;
|
| 8 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
.layout-container {
|
| 12 |
+
display: flex;
|
| 13 |
+
flex-direction: column;
|
| 14 |
+
width: 100%;
|
| 15 |
+
height: 100%;
|
| 16 |
+
gap: 20px;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.slide-img {
|
| 20 |
+
max-width: 100%;
|
| 21 |
+
max-height: 100%;
|
| 22 |
+
width: auto;
|
| 23 |
+
height: auto;
|
| 24 |
+
object-fit: contain;
|
| 25 |
+
}
|
| 26 |
+
</style>
|
| 27 |
+
</head>
|
| 28 |
+
<body>
|
| 29 |
+
<div class="slide" name="slide" id="slide1">
|
| 30 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 31 |
+
<defs />
|
| 32 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 33 |
+
|
| 34 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 35 |
+
|
| 36 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 37 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 38 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 39 |
+
</g>
|
| 40 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 41 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 42 |
+
</g>
|
| 43 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 44 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 45 |
+
</g>
|
| 46 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 47 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 48 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 49 |
+
</g>
|
| 50 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 51 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 52 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 53 |
+
</g>
|
| 54 |
+
|
| 55 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 56 |
+
|
| 57 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 58 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 59 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 60 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 61 |
+
</text>
|
| 62 |
+
</g>
|
| 63 |
+
|
| 64 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 65 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container">
|
| 66 |
+
|
| 67 |
+
<div id="1-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 68 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 69 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 70 |
+
<img src="images/t_2.png" class="slide-img" alt="Left Image" />
|
| 71 |
+
</div>
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
<div id="2-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 75 |
+
<div id="2-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 76 |
+
<!-- You need to revise the following parts. 3: Image -->
|
| 77 |
+
<img src="images/3.png" class="slide-img" alt="Center Image" />
|
| 78 |
+
</div>
|
| 79 |
+
</div>
|
| 80 |
+
|
| 81 |
+
<div id="3-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 82 |
+
<div id="3-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 83 |
+
<!-- You need to revise the following parts. 4: Image -->
|
| 84 |
+
<img src="images/t_2.png" class="slide-img" alt="Right Image" />
|
| 85 |
+
</div>
|
| 86 |
+
</div>
|
| 87 |
+
|
| 88 |
+
</div>
|
| 89 |
+
</foreignObject>
|
| 90 |
+
|
| 91 |
+
</g>
|
| 92 |
+
</svg>
|
| 93 |
+
</div>
|
| 94 |
+
</body>
|
| 95 |
+
</html>
|
ppt_template/T2_ImageRight.html
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
width: 100%;
|
| 15 |
+
height: 100%;
|
| 16 |
+
gap: 20px;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.slide-img {
|
| 20 |
+
max-width: 100%;
|
| 21 |
+
max-height: 100%;
|
| 22 |
+
width: auto;
|
| 23 |
+
height: auto;
|
| 24 |
+
object-fit: contain;
|
| 25 |
+
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 68 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 69 |
+
|
| 70 |
+
<div id="1-col-field"; style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 71 |
+
<div id="1-1-text-block"; style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 21pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 0 15px;">
|
| 72 |
+
<!-- You need to revise the following parts. 2: Text -->
|
| 73 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose, weaving patterns that neither align with memory nor contradict the blurred architecture of imagined time. Within this wandering expanse, a procession of intangible echoes shimmers faintly, as if attempting to articulate a message that dissolves the moment it forms.
|
| 74 |
+
</div>
|
| 75 |
+
</div>
|
| 76 |
+
|
| 77 |
+
<div id="2-col-field"; style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 78 |
+
<div id="2-1-image-block"; style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 79 |
+
<!-- You need to revise the following parts. 3: Figure -->
|
| 80 |
+
<img src="images/7.png" class="slide-img" alt="Slide Image" />
|
| 81 |
+
</div>
|
| 82 |
+
</div>
|
| 83 |
+
|
| 84 |
+
</div>
|
| 85 |
+
</foreignObject>
|
| 86 |
+
|
| 87 |
+
</g>
|
| 88 |
+
</svg>
|
| 89 |
+
</div>
|
| 90 |
+
</body>
|
| 91 |
+
</html>
|
ppt_template/T3_ImageLeft.html
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
width: 100%;
|
| 15 |
+
height: 100%;
|
| 16 |
+
gap: 20px;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.slide-img {
|
| 20 |
+
max-width: 100%;
|
| 21 |
+
max-height: 100%;
|
| 22 |
+
width: auto;
|
| 23 |
+
height: auto;
|
| 24 |
+
object-fit: contain;
|
| 25 |
+
}
|
| 26 |
+
</style>
|
| 27 |
+
</head>
|
| 28 |
+
<body>
|
| 29 |
+
<div class="slide" name="slide" id="slide1">
|
| 30 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 31 |
+
<defs />
|
| 32 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 33 |
+
|
| 34 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 35 |
+
|
| 36 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 37 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 38 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 39 |
+
</g>
|
| 40 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 41 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 42 |
+
</g>
|
| 43 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 44 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 45 |
+
</g>
|
| 46 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 47 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 48 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 49 |
+
</g>
|
| 50 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 51 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 52 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 53 |
+
</g>
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 66 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 67 |
+
|
| 68 |
+
<div id="1-col-field"; style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 69 |
+
<div id="1-1-image-block"; style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 70 |
+
<!-- You need to revise the following parts. 3: Figure -->
|
| 71 |
+
<img src="images/7.png" class="slide-img" alt="Slide Image" />
|
| 72 |
+
</div>
|
| 73 |
+
</div>
|
| 74 |
+
|
| 75 |
+
<div id="2-col-field"; style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 76 |
+
<div id="2-1-text-block"; style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 21pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 0 15px;">
|
| 77 |
+
<!-- You need to revise the following parts. 2: Text -->
|
| 78 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose, weaving patterns that neither align with memory nor contradict the blurred architecture of imagined time. Within this wandering expanse, a procession of intangible echoes shimmers faintly, as if attempting to articulate a message that dissolves the moment it forms.
|
| 79 |
+
</div>
|
| 80 |
+
</div>
|
| 81 |
+
|
| 82 |
+
</div>
|
| 83 |
+
</foreignObject>
|
| 84 |
+
|
| 85 |
+
</g>
|
| 86 |
+
</svg>
|
| 87 |
+
</div>
|
| 88 |
+
</body>
|
| 89 |
+
</html>
|
ppt_template/T4_ImageTop.html
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
.slideImage {
|
| 7 |
+
border: 1px solid #BBBBBB;
|
| 8 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
.layout-container {
|
| 12 |
+
display: flex;
|
| 13 |
+
flex-direction: column;
|
| 14 |
+
width: 100%;
|
| 15 |
+
height: 100%;
|
| 16 |
+
gap: 15px;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.slide-img {
|
| 20 |
+
max-width: 100%;
|
| 21 |
+
max-height: 100%;
|
| 22 |
+
width: auto;
|
| 23 |
+
height: auto;
|
| 24 |
+
object-fit: contain;
|
| 25 |
+
}
|
| 26 |
+
</style>
|
| 27 |
+
</head>
|
| 28 |
+
<body>
|
| 29 |
+
<div class="slide" name="slide" id="slide1">
|
| 30 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 31 |
+
<defs />
|
| 32 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 33 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 34 |
+
|
| 35 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 36 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 37 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 38 |
+
</g>
|
| 39 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 40 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 41 |
+
</g>
|
| 42 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 43 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 44 |
+
</g>
|
| 45 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 46 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 47 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 48 |
+
</g>
|
| 49 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 50 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 51 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 52 |
+
</g>
|
| 53 |
+
|
| 54 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 55 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 56 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 57 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 58 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 59 |
+
</text>
|
| 60 |
+
</g>
|
| 61 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 62 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 63 |
+
<div id="1-row-field" style="flex: 5; display: flex; flex-direction: row; gap: 10px; height: 100%; overflow: hidden;">
|
| 64 |
+
<div id="1-1-image-block" style="flex:1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 65 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 66 |
+
<img src="images/2.png" class="slide-img" alt="Slide Image" />
|
| 67 |
+
</div>
|
| 68 |
+
</div>
|
| 69 |
+
<div id="2-row-field" style="flex: 2; display: flex; flex-direction: row; gap: 10px; height: 100%; overflow:hidden">
|
| 70 |
+
<div id="2-1-text-block" style="flex:1; font-family: 'Calibri', sans-serif; font-size: 18pt; color: #000000; line-height: 1.2; text-align: left; overflow: hidden; padding: 0 15px;">
|
| 71 |
+
<!-- You need to revise the following parts. 3: Text -->
|
| 72 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose, weaving patterns of imagined time.
|
| 73 |
+
</div>
|
| 74 |
+
</div>
|
| 75 |
+
</div>
|
| 76 |
+
</foreignObject>
|
| 77 |
+
</g>
|
| 78 |
+
</svg>
|
| 79 |
+
</div>
|
| 80 |
+
</body>
|
| 81 |
+
</html>
|
ppt_template/T5_TwoImages.html
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
.slideImage {
|
| 7 |
+
border: 1px solid #BBBBBB;
|
| 8 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
.layout-container {
|
| 12 |
+
display: flex;
|
| 13 |
+
flex-direction: row;
|
| 14 |
+
width: 100%;
|
| 15 |
+
height: 100%;
|
| 16 |
+
gap: 20px;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.slide-img {
|
| 20 |
+
max-width: 100%;
|
| 21 |
+
max-height: 100%;
|
| 22 |
+
width: auto;
|
| 23 |
+
height: auto;
|
| 24 |
+
object-fit: contain;
|
| 25 |
+
}
|
| 26 |
+
</style>
|
| 27 |
+
</head>
|
| 28 |
+
<body>
|
| 29 |
+
<div class="slide" name="slide" id="slide1">
|
| 30 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 31 |
+
<defs />
|
| 32 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 33 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 34 |
+
|
| 35 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 36 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 37 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 38 |
+
</g>
|
| 39 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 40 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 41 |
+
</g>
|
| 42 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 43 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 44 |
+
</g>
|
| 45 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 46 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 47 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 48 |
+
</g>
|
| 49 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 50 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 51 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 52 |
+
</g>
|
| 53 |
+
|
| 54 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 55 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 56 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 57 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 58 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 59 |
+
</text>
|
| 60 |
+
</g>
|
| 61 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 62 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 63 |
+
<div id="1-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 64 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 65 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 66 |
+
<img src="images/4.png" class="slide-img" alt="Left Image" />
|
| 67 |
+
</div>
|
| 68 |
+
</div>
|
| 69 |
+
<div id="2-col-field" style="flex: 1; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 70 |
+
<div id="2-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 71 |
+
<!-- You need to revise the following parts. 3: Image -->
|
| 72 |
+
<img src="images/4.png" class="slide-img" alt="Right Image" />
|
| 73 |
+
</div>
|
| 74 |
+
</div>
|
| 75 |
+
</div>
|
| 76 |
+
</foreignObject>
|
| 77 |
+
</g>
|
| 78 |
+
</svg>
|
| 79 |
+
</div>
|
| 80 |
+
</body>
|
| 81 |
+
</html>
|
ppt_template/T6_TwoImages2.html
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: column;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 15px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subject -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 67 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 68 |
+
|
| 69 |
+
<div id="1-row-field" style="flex: 3; display: flex; flex-direction: row; gap: 10px; height: 100%; overflow: hidden;">
|
| 70 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 71 |
+
<!-- You need to revise the following parts. 2: image -->
|
| 72 |
+
<img src="images/4.png" class="slide-img" alt="Left Image" />
|
| 73 |
+
</div>
|
| 74 |
+
<div id="2-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 75 |
+
<!-- You need to revise the following parts. 3: image -->
|
| 76 |
+
<img src="images/4.png" class="slide-img" alt="Right Image" />
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
|
| 80 |
+
<div id="2-row-field" style="flex: 2; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow: hidden;">
|
| 81 |
+
<div id="2-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 21pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 0 15px;">
|
| 82 |
+
<!-- You need to revise the following parts. 4: Text -->
|
| 83 |
+
In the quiet lattice of an unnamed elsewhere, the murmuring fragments of hollow constellations drift without purpose. Within this wandering expanse, a procession of intangible echoes shimmers faintly.
|
| 84 |
+
</div>
|
| 85 |
+
</div>
|
| 86 |
+
|
| 87 |
+
</div>
|
| 88 |
+
</foreignObject>
|
| 89 |
+
|
| 90 |
+
</g>
|
| 91 |
+
</svg>
|
| 92 |
+
</div>
|
| 93 |
+
</body>
|
| 94 |
+
</html>
|
ppt_template/T7_2×2_TopImage.html
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: column;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 15px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 66 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 67 |
+
|
| 68 |
+
<div id="1-row-field" style="flex: 1; display: flex; flex-direction: row; gap: 20px; height: 100%; overflow: hidden;">
|
| 69 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 70 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 71 |
+
<img src="images/4.png" class="slide-img" alt="Top Left" />
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
<div id="1-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 75 |
+
<!-- You need to revise the following parts. 3: Image -->
|
| 76 |
+
<img src="images/4.png" class="slide-img" alt="Top Right" />
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
|
| 80 |
+
<div id="2-row-field" style="flex: 1; display: flex; flex-direction: row; gap: 20px; height: 100%; overflow: hidden;">
|
| 81 |
+
<div id="2-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 21pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 0 20px;">
|
| 82 |
+
<strong>Part 1: The Concept</strong><br/>
|
| 83 |
+
<!-- You need to revise the following parts. 4: Text -->
|
| 84 |
+
In the quiet lattice of an unnamed elsewhere, fragments drift without purpose, weaving patterns that align with memory.
|
| 85 |
+
</div>
|
| 86 |
+
|
| 87 |
+
<div id="2-2-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 21pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 0 20px;">
|
| 88 |
+
<strong>Part 2: The Application</strong><br/>
|
| 89 |
+
<!-- You need to revise the following parts. 5: Text -->
|
| 90 |
+
Within this wandering expanse, a procession of intangible echoes shimmers faintly, attempting to articulate a message.
|
| 91 |
+
</div>
|
| 92 |
+
</div>
|
| 93 |
+
|
| 94 |
+
</div>
|
| 95 |
+
</foreignObject>
|
| 96 |
+
|
| 97 |
+
</g>
|
| 98 |
+
</svg>
|
| 99 |
+
</div>
|
| 100 |
+
</body>
|
| 101 |
+
</html>
|
ppt_template/T8_2×2_BottomImage.html
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: column;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 15px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 66 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 67 |
+
|
| 68 |
+
<div id="1-row-field" style="flex: 1; display: flex; flex-direction: row; gap: 20px; height: 100%; overflow: hidden;">
|
| 69 |
+
<div id="1-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 20pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 0 25px;">
|
| 70 |
+
<!-- You need to revise the following parts. 2: Text -->
|
| 71 |
+
<strong>Theoretical Framework</strong><br/>
|
| 72 |
+
In the quiet lattice of an unnamed elsewhere, fragments drift without purpose, weaving patterns that align with memory.
|
| 73 |
+
</div>
|
| 74 |
+
<div id="1-2-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 20pt; color: #000000; line-height: 1.3; text-align: left; overflow: hidden; padding: 0 25px;">
|
| 75 |
+
<!-- You need to revise the following parts. 3: Text -->
|
| 76 |
+
<strong>Practical Analysis</strong><br/>
|
| 77 |
+
Within this wandering expanse, a procession of intangible echoes shimmers faintly, attempting to articulate a message.
|
| 78 |
+
</div>
|
| 79 |
+
</div>
|
| 80 |
+
|
| 81 |
+
<div id="2-row-field" style="flex: 1; display: flex; flex-direction: row; gap: 10px; height: 100%; overflow: hidden;">
|
| 82 |
+
<div id="2-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 83 |
+
<!-- You need to revise the following parts. 4: Image -->
|
| 84 |
+
<img src="images/4.png" class="slide-img" alt="Bottom Left" />
|
| 85 |
+
</div>
|
| 86 |
+
<div id="2-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 87 |
+
<!-- You need to revise the following parts. 5: Image -->
|
| 88 |
+
<img src="images/4.png" class="slide-img" alt="Bottom Right" />
|
| 89 |
+
</div>
|
| 90 |
+
</div>
|
| 91 |
+
|
| 92 |
+
</div>
|
| 93 |
+
</foreignObject>
|
| 94 |
+
|
| 95 |
+
</g>
|
| 96 |
+
</svg>
|
| 97 |
+
</div>
|
| 98 |
+
</body>
|
| 99 |
+
</html>
|
ppt_template/T9_2×2_AltTextImg.html
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slideImage {
|
| 8 |
+
border: 1px solid #BBBBBB; /* 浅灰色边框,使 SVG 区域清晰可见 */
|
| 9 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 增加柔和阴影 */
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
.layout-container {
|
| 13 |
+
display: flex;
|
| 14 |
+
flex-direction: column;
|
| 15 |
+
width: 100%;
|
| 16 |
+
height: 100%;
|
| 17 |
+
gap: 15px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.slide-img {
|
| 21 |
+
max-width: 100%;
|
| 22 |
+
max-height: 100%;
|
| 23 |
+
width: auto;
|
| 24 |
+
height: auto;
|
| 25 |
+
object-fit: contain;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
| 28 |
+
</head>
|
| 29 |
+
<body>
|
| 30 |
+
<div class="slide" name="slide" id="slide1">
|
| 31 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 32 |
+
<defs />
|
| 33 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 34 |
+
|
| 35 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 36 |
+
|
| 37 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 38 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 39 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 40 |
+
</g>
|
| 41 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 42 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 43 |
+
</g>
|
| 44 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 46 |
+
</g>
|
| 47 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 48 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 49 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 52 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 53 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 54 |
+
</g>
|
| 55 |
+
|
| 56 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M21 71L33 23 660 23.6 648 71z" shape-id="2" />
|
| 57 |
+
|
| 58 |
+
<g transform="matrix(1.0, 0.0, 0.0, 1.0, 75, 30)">
|
| 59 |
+
<text shape-id="2" font-family="Calibri" font-weight="bold" font-size="18.0pt" fill="#ffffff">
|
| 60 |
+
<!-- You need to revise the following parts. 1: Subjects -->
|
| 61 |
+
<tspan x="0" y="26.5">Bridging 2D and 3D: From Lifting to Learning</tspan>
|
| 62 |
+
</text>
|
| 63 |
+
</g>
|
| 64 |
+
|
| 65 |
+
<foreignObject x="28" y="104" width="900" height="400">
|
| 66 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="layout-container" id="root">
|
| 67 |
+
|
| 68 |
+
<div id="1-row-field" style="flex: 1; display: flex; flex-direction: row; gap: 20px; height: 100%; overflow: hidden;">
|
| 69 |
+
<div id="1-1-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 70 |
+
<!-- You need to revise the following parts. 2: Image -->
|
| 71 |
+
<img src="images/4.png" class="slide-img" alt="Top Image" />
|
| 72 |
+
</div>
|
| 73 |
+
<div id="1-2-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 20pt; color: #000000; line-height: 1.25; text-align: left; overflow: hidden; padding: 0 15px;">
|
| 74 |
+
<!-- You need to revise the following parts. 3: Text -->
|
| 75 |
+
<strong>Phase 1: Observation</strong><br/>
|
| 76 |
+
In the quiet lattice of an unnamed elsewhere, fragments drift without purpose, weaving patterns that align with memory.
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
|
| 80 |
+
<div id="2-row-field" style="flex: 1; display: flex; flex-direction: row; gap: 20px; height: 100%; overflow: hidden;">
|
| 81 |
+
<div id="2-1-text-block" style="flex: 1; font-family: 'Calibri', sans-serif; font-size: 20pt; color: #000000; line-height: 1.25; text-align: left; overflow: hidden; padding: 0 15px;">
|
| 82 |
+
<!-- You need to revise the following parts. 4: Text -->
|
| 83 |
+
<strong>Phase 2: Execution</strong><br/>
|
| 84 |
+
Within this wandering expanse, a procession of intangible echoes shimmers faintly, attempting to articulate a message.
|
| 85 |
+
</div>
|
| 86 |
+
<div id="2-2-image-block" style="flex: 1; display: flex; align-items: center; justify-content: center; overflow: hidden;">
|
| 87 |
+
<!-- You need to revise the following parts. 5: Image -->
|
| 88 |
+
<img src="images/4.png" class="slide-img" alt="Bottom Image" />
|
| 89 |
+
</div>
|
| 90 |
+
</div>
|
| 91 |
+
|
| 92 |
+
</div>
|
| 93 |
+
</foreignObject>
|
| 94 |
+
|
| 95 |
+
</g>
|
| 96 |
+
</svg>
|
| 97 |
+
</div>
|
| 98 |
+
</body>
|
| 99 |
+
</html>
|
ppt_template/Title Slide.html
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta http-equiv="X-UA-Compatible" content="IE=9">
|
| 5 |
+
<style>
|
| 6 |
+
|
| 7 |
+
.slide-title {
|
| 8 |
+
font-family: 'Calibri', sans-serif;
|
| 9 |
+
font-weight: bold;
|
| 10 |
+
font-size: 30.0pt;
|
| 11 |
+
color: #000000;
|
| 12 |
+
text-align: center;
|
| 13 |
+
display: flex;
|
| 14 |
+
align-items: center;
|
| 15 |
+
justify-content: center;
|
| 16 |
+
height: 100%;
|
| 17 |
+
line-height: 1.2;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
.slide-authors {
|
| 22 |
+
font-family: 'Calibri', sans-serif;
|
| 23 |
+
font-weight: bold;
|
| 24 |
+
font-size: 24.0pt;
|
| 25 |
+
color: #888888;
|
| 26 |
+
text-align: center;
|
| 27 |
+
display: flex;
|
| 28 |
+
align-items: center;
|
| 29 |
+
justify-content: center;
|
| 30 |
+
height: 100%;
|
| 31 |
+
line-height: 1.4;
|
| 32 |
+
padding: 0 20px;
|
| 33 |
+
}
|
| 34 |
+
</style>
|
| 35 |
+
</head>
|
| 36 |
+
<body>
|
| 37 |
+
<div class="slide" name="slide" id="slide1">
|
| 38 |
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.333333in" height="7.5in" viewBox="0 0 960 540" version="1.1" class="slideImage">
|
| 39 |
+
<defs />
|
| 40 |
+
<g text-rendering="geometricPrecision" xml:space="preserve" transform="scale(1.0,1.0)">
|
| 41 |
+
|
| 42 |
+
<rect x="0" y="0" width="960" height="540" fill="#ffffff" />
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M-0.2 160.4L960 160.4 960 352.2-0.2 352.2z" shape-id="14" />
|
| 46 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M77.3 440.1L165.7 74.4 776.6 74.4 865 440.1z" shape-id="13" />
|
| 47 |
+
<path fill="#043a5d" fill-rule="evenodd" d="M74.4 439.4L74.4 439.4 162.8 73.7 163.4 71.4 165.7 71.4 776.6 71.4 778.9 71.4 779.5 73.7 867.9 439.4 868.8 443.1 865 443.1 77.3 443.1 73.5 443.1 74.4 439.4zM80.2 440.8L77.3 437.1 865 437.1 862.1 440.8 773.6 75.1 776.6 77.4 165.7 77.4 168.7 75.1 80.2 440.8z" shape-id="13" />
|
| 48 |
+
<g transform="matrix(0.82903755, -0.5591929, 0.5591929, 0.82903755, -13.02281, 22.004297)">
|
| 49 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M6.65 51.2L29.47 13.4 52.3 51.2z" shape-id="6" />
|
| 50 |
+
</g>
|
| 51 |
+
<g transform="matrix(-0.81915206, 0.57357645, -0.57357645, -0.81915206, 211.76512, 80.13071)">
|
| 52 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M55.25 107.55L93.25 39.35 131.25 107.55z" shape-id="7" />
|
| 53 |
+
</g>
|
| 54 |
+
<g transform="matrix(0.89879405, 0.43837115, -0.43837115, 0.89879405, 234.443, 40.515747)">
|
| 55 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M-66.8 600.5L9.6 455.5 125.7 600.5z" shape-id="8" />
|
| 56 |
+
<path fill="#688291" fill-rule="evenodd" d="M-67.2 600.3L-67.2 600.3 9.2 455.2 9.5 454.5 10 455.1 126.1 600.2 126.7 601 125.7 601-66.8 601-67.6 601-67.2 600.3zM-66.3 600.8L-66.8 600 125.7 600 125.3 600.9 9.2 455.8 10.1 455.7-66.3 600.8z" shape-id="8" />
|
| 57 |
+
</g>
|
| 58 |
+
<g transform="matrix(-0.39073113, 0.92050487, -0.92050487, -0.39073113, 1741.5249, -181.64023)">
|
| 59 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M878 527L930.9 444 983.8 527z" shape-id="9" />
|
| 60 |
+
</g>
|
| 61 |
+
<g transform="matrix(-0.8571673, 0.5150381, -0.5150381, -0.8571673, 2045.3938, 505.16202)">
|
| 62 |
+
<path fill="#093b5e" fill-rule="evenodd" d="M933.35 551.3L952.65 521.1 971.95 551.3z" shape-id="10" />
|
| 63 |
+
</g>
|
| 64 |
+
<g transform="matrix(0.4539905, 0.8910065, -0.8910065, 0.4539905, 384.46686, -675.1429)">
|
| 65 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M688 24.9L743.1-72.7 798.2 24.9z" shape-id="11" />
|
| 66 |
+
<path fill="#688291" fill-rule="evenodd" d="M687.6 24.7L687.6 24.7 742.7-72.9 743.1-73.7 743.5-72.9 798.6 24.7 799 25.4 798.2 25.4 688 25.4 687.2 25.4 687.6 24.7zM688.5 25.1L688 24.4 798.2 24.4 797.7 25.1 742.7-72.4 743.5-72.4 688.5 25.1z" shape-id="11" />
|
| 67 |
+
</g>
|
| 68 |
+
<g transform="matrix(-0.5150381, 0.8571673, -0.8571673, -0.5150381, 1527.4514, -743.14044)">
|
| 69 |
+
<path fill="#ffffff" fill-rule="evenodd" d="M862.2 153L974-32 1085.7 153z" shape-id="12" />
|
| 70 |
+
<path fill="#688291" fill-rule="evenodd" d="M861.8 152.7L861.8 152.7 973.5-32.2 974-32.9 974.4-32.2 1086.1 152.7 1086.6 153.5 1085.7 153.5 862.2 153.5 861.3 153.5 861.8 152.7zM862.6 153.3L862.2 152.5 1085.7 152.5 1085.3 153.3 973.5-31.7 974.4-31.7 862.6 153.3z" shape-id="12" />
|
| 71 |
+
</g>
|
| 72 |
+
<g transform="matrix(1.0, 0.0, 0.0, -1.0, 0.0, 517.69995)">
|
| 73 |
+
<path fill="#41719c" fill-rule="evenodd" d="M212.4 256.9L212.4 256.9 737.1 257.5 737 260.8 212.4 260.2z" shape-id="15" />
|
| 74 |
+
</g>
|
| 75 |
+
|
| 76 |
+
<!--
|
| 77 |
+
You need to revise the following parts. 1: Title
|
| 78 |
+
-->
|
| 79 |
+
<foreignObject x="190" y="110" width="580" height="150">
|
| 80 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="slide-title">
|
| 81 |
+
Denoising MCMC for Accelerating Diffusion-Based Generative Model
|
| 82 |
+
</div>
|
| 83 |
+
</foreignObject>
|
| 84 |
+
|
| 85 |
+
<!--
|
| 86 |
+
You need to revise the following parts. 2: Authors
|
| 87 |
+
-->
|
| 88 |
+
<foreignObject x="165" y="280" width="630" height="150">
|
| 89 |
+
<div xmlns="http://www.w3.org/1999/xhtml" class="slide-authors">
|
| 90 |
+
Jiazhong Cen, Xudong Zhou, Jiemin Fang, Changsong Wen, Lingxi Xie, Xiaopeng Zhang, Wei Shen, Qi Tian
|
| 91 |
+
</div>
|
| 92 |
+
</foreignObject>
|
| 93 |
+
|
| 94 |
+
</g>
|
| 95 |
+
</svg>
|
| 96 |
+
</div>
|
| 97 |
+
</body>
|
| 98 |
+
</html>
|
ppt_template/format.txt
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
title:
|
| 2 |
+
font-family: 'Calibri', sans-serif;
|
| 3 |
+
font-weight: bold;
|
| 4 |
+
font-size: 30.0pt;
|
| 5 |
+
color: #000000;
|
| 6 |
+
text-align: center;
|
| 7 |
+
display: flex;
|
| 8 |
+
align-items: center;
|
| 9 |
+
justify-content: center;
|
| 10 |
+
height: 100%;
|
| 11 |
+
line-height: 1.2;
|
| 12 |
+
|
| 13 |
+
content list:
|
| 14 |
+
font-family: 'Calibri', sans-serif;
|
| 15 |
+
font-size: 28.0pt;
|
| 16 |
+
color: #ffffff;
|
| 17 |
+
line-height: 1.45;
|
| 18 |
+
margin: 0;
|
| 19 |
+
padding: 0;
|
| 20 |
+
list-style-type: none;
|
| 21 |
+
limit:
|
| 22 |
+
white-space: nowrap;
|
| 23 |
+
overflow: hidden;
|
| 24 |
+
text-overflow: ellipsis;
|
| 25 |
+
padding-bottom: 5px;
|
| 26 |
+
|
| 27 |
+
text:
|
| 28 |
+
font-family: 'Calibri', sans-serif; /* 使用Calibri字体 */
|
| 29 |
+
font-size: 21pt; /* 21磅字体大小 */
|
| 30 |
+
color: #000000; /* 黑色文字 */
|
| 31 |
+
line-height: 1.3; /* 1.3倍行高,适中的行间距 */
|
| 32 |
+
text-align: left; /* 左对齐 */
|
| 33 |
+
overflow: hidden; /* 溢出隐藏 */
|
| 34 |
+
|
ppt_template/images/2.png
ADDED
|
Git LFS Details
|
ppt_template/images/3.png
ADDED
|
ppt_template/images/4.png
ADDED
|
Git LFS Details
|
ppt_template/images/5_1.png
ADDED
|
ppt_template/images/5_2.png
ADDED
|
ppt_template/images/5_3.png
ADDED
|
ppt_template/images/7.png
ADDED
|
Git LFS Details
|
ppt_template/images/t_2.png
ADDED
|
Git LFS Details
|
pr_template.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#
|
| 2 |
+
|
| 3 |
+
✍️ **Authors**
|
| 4 |
+
|
| 5 |
+
🌐 **Direct Link**
|
| 6 |
+
|
| 7 |
+
📚 **Paper Title**
|
| 8 |
+
|
| 9 |
+
🏛️**Institution**
|
| 10 |
+
|
| 11 |
+
🔍 **Key Question**:
|
| 12 |
+
|
| 13 |
+
💡 **Brilliant Idea**:
|
| 14 |
+
|
| 15 |
+
🚀 **Core Methods**:
|
| 16 |
+
|
| 17 |
+
📊 **Core Results**:
|
| 18 |
+
|
| 19 |
+
🧠 **Significance/Impact**:
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
🏷️**Hashtag**
|
| 23 |
+
Broad: #AI;
|
| 24 |
+
Specific: #Tag1 #Tag2 #Tag3;
|
| 25 |
+
Community: #Tag1
|
| 26 |
+
Strategic Mentions:#
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
CTA:Our paper is closely aligned with current hot topics. Please read,Bookmark and download the paper now to learn about our work and stay up to date with the latest trends👇. Time is running out—please pay attention to our work immediately so you don’t miss it!🔥🔥🔥
|
prompt.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"poster_graph": "You are an assistant that analyzes the structure of an academic paper and produces a document graph in **JSON** format.\n\nGoal:\n- Identify the hierarchical and semantic relationships between sections, subsections, figures, tables, and algorithms.\n- Represent the paper as a graph of nodes and edges.\n\nOutput format (JSON schema):\n{\n \"nodes\": [\n {\n \"id\": \"sec:introduction\", // unique ID, use prefixes like sec:, sub:, fig:, tab:, alg:\n \"type\": \"Section\", // one of: Section, Subsection, Figure, Table, Algorithm\n \"title\": \"Introduction\", // title or short caption\n \"summary\": \"1-2 sentence summary of this part\", // brief textual summary\n \"pages\": [1,2] // page indices where this content appears\n }\n ],\n \"edges\": [\n {\n \"source\": \"sec:introduction\", // source node ID\n \"target\": \"fig:1\", // target node ID\n \"relation\": \"illustrates\", // one of: illustrates, supports, cites, extends, is_part_of, contradicts\n \"weight\": 0.9 // normalized relevance (0–1)\n }\n ]\n}\n\nInstructions:\n1. Create a small but meaningful subset of nodes that reflect the paper's logical structure.\n2. Prefer strong relations such as a figure illustrating a section, or an algorithm belonging to a method section.\n3. Keep the JSON concise — only include the most informative nodes and the top ~10 most relevant edges.\n4. Do NOT output any explanations, commentary, or Markdown formatting. Output must be pure JSON.\n5. Ensure all node IDs are unique and appear in edges consistently.\n\nPurpose:\nThis JSON graph will later be used as a structure guide when generating a visual poster layout, so maintain semantic accuracy between paper elements.",
|
| 3 |
+
|
| 4 |
+
"section_split_prompt": "You will receive a full academic paper in Markdown format. Your task is to SPLIT the Markdown into multiple Markdown chunks by identifying TOP-LEVEL SECTIONS based on semantic structure and overall document organization, NOT by strict regular expressions. You must first analyze the entire Markdown to determine which headings represent main sections of the paper(For example, Introduction, Methods, Experiment, Ablation, Conclusion, etc.), even if their formatting is inconsistent (e.g., '# 3CULTURE EXPLORER', '# III Method', or '# Experiments'), and then split ONLY at those main section boundaries. You must NOT split at subsections or lower-level headings (such as 1.1, 2.3, A., or any nested structure). You must NOT change, rewrite, summarize, reorder, or reformat ANY original text; you may ONLY split the Markdown. You must NOT create a separate chunk for the title, authors, abstract, keywords, or any front matter. Splitting MUST begin from the Introduction section (the section may not be explicitly named \"Introduction\" and must be identified by semantic judgment). When determining the Introduction section, you must NOT include the paper title, author information, abstract, keywords, or any other front matter as part of the Introduction chunk. You MUST output ONLY the markdown chunks separated by the exact delimiter '===SPLIT===', with no explanations, comments, or extra text. Do NOT modify any Markdown content. Only split.To emphasize again: your splitting result must NOT contain the paper title or author information, and the splitting must start strictly from the Introduction section or a semantically equivalent section.",
|
| 5 |
+
|
| 6 |
+
"clean_prompt":"You are an assistant that edits scientific paper markdown files **by only deleting irrelevant sections**.\n\n### 🎯 Task Objective\nGiven a full paper in Markdown format, remove any sections that are unrelated to the main body, while preserving all essential scientific content.\n\n### ⚙️ Rules\n1. **Only perform deletion.** Do not rewrite, paraphrase, or modify any sentence, word, or symbol.\n2. **Preserve all markdown formatting exactly** (headings, equations, tables, images, citations, etc.).\n3. **Remove** any sections whose title or meaning matches (even loosely) any of the following:\n - Abstract / Summary / Overview\n - Related Work / Previous Work / Background / Literature Review\n - Appendix / Supplementary Material / Acknowledgements\n - References / Bibliography / Citation List / Limitations\n 4. **Keep** all of the following sections and their content:\n - Title / Paper Title line\n - Author or affiliation block\n - Introduction / Motivation / Problem Statement\n - Methods / Approach / Model / Architecture\n - Experiments / Results / Evaluation / Analysis\n - Conclusion / Discussion / Future Work (if relevant)\n5. If the section name is ambiguous, decide by meaning: remove only if it serves as background or references.\n\n### 📦 Output\nReturn the cleaned markdown text only, without explanation. Keep identical markdown syntax, spacing, and formatting.",
|
| 7 |
+
|
| 8 |
+
"initialize_dag_prompt":"You will receive the full Markdown content of an academic paper in a **separate user message**. Your task is to analyze the Markdown and initialize a JSON DAG containing **only a single root node** that represents the entire paper.\n\n### --- DAG SPECIFICATION ---\nYour output must be a JSON object with the following structure, and **must not include explanations or markdown fences**:\n\n{\n \"nodes\": [\n {\n \"name\": \"<string>\",\n \"content\": \"<string>\",\n \"github\": \"<string or empty>\",\n \"edge\": [],\n \"level\": 0,\n \"visual_node\": []\n }\n ]\n}\n\n### --- ROOT NODE RULES ---\n1. **Root Node Identification**\n - Represents the entire paper.\n - `name`: Use the paper title. This is the first non-empty line OR the first top-level markdown heading.\n - `content`: Use the author and affiliation information immediately following the title. You MUST explicitly control the output format of this field as follows:\n \n **FORMAT REQUIREMENT**\n - First list all author names, separated by commas.\n - Then list all affiliations, separated by commas.\n - The author list and the affiliation list MUST be separated by six dots: `......`.\n \n **Required format**:\n Author1, Author2, Author3......Affiliation1, Affiliation2, Affiliation3\n \n **Additional constraints**:\n - Do NOT interleave authors and affiliations.\n - Do NOT use newlines.\n - Do NOT add labels such as \"Authors:\" or \"Affiliations:\".\n - If affiliations are unavailable, still include `......` followed by an empty string.\n - `github`: Identify the GitHub repository link explicitly provided in the paper (e.g., in the abstract, introduction, footnotes, or a dedicated code/repository section). If a valid GitHub URL is found, assign it directly to this field (e.g., \"https://github.com/multimodal-art-projection/P2P\"). If no GitHub link is provided in the paper, use an empty string.\n\n2. **Root Node Attributes**\n - `edge`: Always an empty list at this initialization stage.\n - `level`: Always 0.\n - `visual_node`: Always an empty list.\n\n### --- OUTPUT RULES ---\n- Output ONLY valid JSON.\n- DO NOT include explanations or markdown fences.\n- Ensure the JSON uses UTF-8 clean strings.\n\nWhen I send you the Markdown, produce the JSON DAG according to these rules.",
|
| 9 |
+
|
| 10 |
+
"visual_dag_prompt": "You will receive:\n1. A list of extracted image references in the format \"\".\n2. The full Markdown of the paper.\n\nYour task:\nGenerate a JSON file named `visual_dag.json`.\n\n### --- VISUAL DAG SPECIFICATION ---\nReturn **ONLY** a JSON object in the following structure (no backticks, no explanation):\n\n{\n \"nodes\": [\n {\n \"name\": \"<the image reference, e.g. >\",\n \"caption\": \"<caption extracted or generated>\",\n \"visual_node\": 1,\n \"formula\": <0 or 1>\n }\n ]\n}\n\n### --- CAPTION EXTRACTION RULES ---\n\nFor each image reference:\n\n1. Search the FULL Markdown for where this image appears.\n2. Check the nearby context (within the same block or the following text)\n to see whether the paper provides a caption.\n Caption formats may include:\n - \"Figure 3: xxx\"\n - \"Fig. 2. xxx\"\n - \"**Figure 4.** xxx\"\n - \"Equation 1\"\n - Any line that clearly describes the picture.\n\n3. If a caption exists:\n → Copy the caption **verbatim** into the \"caption\" field.\n\n4. If NO caption exists in the original Markdown:\n → Write a short descriptive caption summarizing what the image likely represents.\n\n5. Set:\n \"visual_node\": 1\n\n### --- FORMULA DETECTION RULES ---\n\nFor each image, determine if it is a **Mathematical Formula** based on the context.\n\n1. **Set \"formula\": 1** IF:\n - The image represents a mathematical equation or a sequence of math symbols.\n - The context refers to it as \"Equation\", \"Eq.\", or implies it is a mathematical expression.\n - It is likely a screenshot of a formula (typically wide and short in aspect ratio).\n\n2. **Set \"formula\": 0** IF:\n - It is a Figure, Chart, Plot, Diagram, Photo, or Illustration.\n - It is a Table.\n - It is an Algorithm or Pseudo-code block.\n\n### --- OUTPUT RULES ---\n- The output must be **valid JSON only**.\n- DO NOT output markdown fences.\n- DO NOT explain anything.\n- DO NOT include any text except the JSON.\n- Do not reorder or remove images.\n\nBegin when ready.",
|
| 11 |
+
|
| 12 |
+
"section_dag_generation_prompt": "You are given one section of a scientific paper in Markdown format. Your task is to organize the content of this section into a directed acyclic graph (DAG) and output it as a single JSON object.\n\nGENERAL SETUP\n-------------\nAt the end of this message, you will see two parts:\n\n1) A line block labeled `=== SECTION NAME ===` that contains the name of the section (e.g., \"1 Introduction\", \"2 Methods\"). The name includes numeric prefixes such as \"1\" or \"3.2\".\n2) A block labeled `=== SECTION MARKDOWN (FULL) ===` that contains the full Markdown text of this section.\n\nYour job is to read the section name and the full Markdown, then construct a DAG of nodes that describes the logical and semantic structure of this section.\n\nJSON OUTPUT FORMAT\n------------------\nYou must output exactly one valid JSON object. The top-level structure must be:\n\n{\n \"nodes\": [\n {\n \"name\": \"...\",\n \"content\": \"...\",\n \"edge\": [],\n \"level\": 0,\n \"visual_node\": []\n }\n ]\n}\n\nDetails:\n- The top-level object must contain a single key: \"nodes\".\n- \"nodes\" must be an array of node objects.\n- Each node object MUST contain ALL of the following five fields:\n 1. \"name\" (string): the name of the node.\n 2. \"content\" (string): the original Markdown text corresponding to this node.\n 3. \"edge\" (array of strings): names of child nodes that this node points to.\n 4. \"level\" (integer): the level of this node in the hierarchy, starting from 1.\n 5. \"visual_node\" (array): always an empty array []. You do not need to fill this with anything.\n\nNo other top-level keys are allowed. All nodes must be included in this single \"nodes\" array.\n\nROOT NODE (LEVEL 1)\n-------------------\n1. Create exactly one root node that represents the entire section.\n2. The root node MUST satisfy:\n - \"name\": exactly the section name that you are given (with numeric prefixes).\n - \"content\": the full Markdown text of the entire section.\n - \"edge\": an array of the names of its direct child nodes (initially, this can be empty, but after you create children, it must list them).\n - \"level\": 1\n - \"visual_node\": []\n\nCONTENT PARTITIONING INTO CHILD NODES\n-------------------------------------\nYou must partition the root node's \"content\" into multiple child nodes based on semantic and topical coherence. The goal is to create a meaningful hierarchical structure, not just to copy the full text.\n\nKey rules:\n1. Child nodes must cover disjoint, non-overlapping segments of the original Markdown text.\n - Within a single parent node, two different child nodes must not share the same text span.\n - Together, child nodes do not need to cover 100% of the parent content, but they should cover the important parts.\n\n2. How to partition:\n - If the section already contains explicit subsections (e.g., \"3.1\", \"3.2\", \"3.3\" in Methods):\n - You may group multiple closely related subsections into a single child node. For example, if 3.1 and 3.2 are strongly related, you can create one child node whose content is the union of 3.1 and 3.2, and another child node for 3.3.\n - If there are no explicit subsections (e.g., a plain Introduction):\n - You may partition the content by paragraphs or logical blocks.\n - For example, you can group the first few paragraphs that introduce the background into one child node, and the later paragraphs that describe contributions or problem statements into another child node.\n\n3. For each child node of a given parent node:\n - Choose a short and descriptive \"name\" that summarizes its role or content, in English if possible (e.g., \"Background of the problem\", \"Overview of proposed method\", \"Motivation and challenges\").\n - Set \"content\" to exactly the corresponding original Markdown text for this node (no overlap with sibling nodes).\n - Set \"edge\" to an empty array (you will later add children when you recurse on this node).\n - Set \"level\" to (parent.level + 1).\n - Set \"visual_node\" to [].\n\n4. After you create the child nodes, you must update the parent node's \"edge\" array so that it contains the \"name\" of each child node.\n\nRECURSIVE REFINEMENT (LEVELS 2 TO 4)\n------------------------------------\nYou must apply the same partitioning logic recursively to deeper levels:\n\n1. Start from the root node (level 1), partition its content into child nodes (level 2).\n2. Then, for each level-2 node, analyze its \"content\" again and see if it can be further partitioned into smaller subnodes (level 3).\n3. Then, for each level-3 node, you may further partition into level-4 nodes.\n\nDepth constraint:\n- You should create a reasonably deep and informative hierarchy, but the maximum depth is level 4.\n- That is, nodes with \"level\" = 4 are leaf nodes and must not be further split.\n\nHeuristics and preferences:\n1. When deciding whether a node should continue to be split, you should, whenever conditions allow (i.e., level < 3), prefer to continue splitting the node. The split can be into two parts or more, as long as it is reasonable.\n2. Try to split nodes until they reach level 3 or level 4 whenever possible. Avoid stopping at level 2 unless further splitting is impossible or semantically unreasonable.\n3. For sections that include automatic subsections in the paper’s Markdown (e.g., Methods divided into 3.1, 3.2, 3.3), when partitioning the section at level 1, you may group different subsections into a new node based on semantic relatedness. For example, Methods 3.1 and 3.2 may be grouped into one level-2 node, while 3.3 may become its own level-2 node. These nodes can then be further split, such as splitting 3.1 and 3.2 into separate level-3 nodes.\n4. For sections without subsections, partition based on paragraphs. For example, if 3.3 has no further subsection structure, you may split it into multiple child nodes according to paragraphs, while still considering semantic coherence.\n5. Higher-level nodes (smaller level number) should be more abstract and cover broader portions of the content.\n6. Lower-level nodes (larger level number) should be more specific, focusing on smaller or more fine-grained segments.\n7. Nodes with very short content or nodes that cannot be reasonably split may be kept as leaf nodes.\n\nGRAPH STRUCTURE REQUIREMENTS\n----------------------------\n1. The graph must be a directed acyclic graph (DAG).\n - In practice, you should build a tree-like structure where each node points only to its child nodes.\n - Do NOT create back edges or cycles.\n\n2. Edges:\n - The \"edge\" field of a node is a list of the names of its direct child nodes.\n - Every name that appears in any \"edge\" array must correspond to exactly one node in the \"nodes\" array.\n - If a node has no children, its \"edge\" must be an empty array [].\n\n3. Levels:\n - The root node must have \"level\": 1.\n - Each child node must have \"level\" = (parent.level + 1).\n - Do not create nodes with level greater than 4.\n\nOUTPUT RULES\n------------\n1. You must output ONLY a single valid JSON object.\n - Do NOT wrap it in Markdown code fences (no ```json or ``` of any kind).\n - Do NOT add any extra commentary, explanation, or text outside the JSON.\n\n2. All strings must be valid JSON strings.\n - Escape newlines and quotation marks as required by JSON.\n - The final output must be parseable by a standard JSON parser without errors.\n\n3. Every node MUST contain all five fields exactly:\n - \"name\"\n - \"content\"\n - \"edge\"\n - \"level\"\n - \"visual_node\"\n\nRemember:\n- Use the section name from the `=== SECTION NAME ===` block as the root node's name.\n- Use the full Markdown from the `=== SECTION MARKDOWN (FULL) ===` block as the root node's content.\n- Build a meaningful, hierarchical DAG up to depth 4.\n- Output only the JSON object, nothing else. In the output JSON, the 'content' field of every node must be a single line string. Multi-line content is not allowed. Even if the original Markdown spans multiple lines, you must merge andnormalize it into one single line (e.g., by replacing newlines with spaces).\n 5. It's recommended that you may group multiple closely related subsections into a single child node. For example, if 3.1 and 3.2 are strongly related, you can create one child node whose content is the union of 3.1 and 3.2, and another child node for 3.3.",
|
| 13 |
+
|
| 14 |
+
"outline_initialize_prompt": "You are an assistant that generates an initial outline.json for a slide-based academic presentation.\n\nRules:\n1. You must ONLY generate a valid JSON array. Do NOT include explanations or markdown.\n2. The output outline.json must contain EXACTLY TWO nodes.\n3. Each node must strictly follow this schema:\n {\n \"text\": string,\n \"figure\": [],\n \"formula\": [],\n \"template\": string\n }\n\nInitialization logic:\n- You will be given the first node of a dag.json.\n- The dag node has fields such as: name, content, edge.\n\nNode 1 (Title Slide):\n- Use dag.name as the paper title.\n- Use dag.content as the author information.\n- Combine them into the text field, formatted as:\n \"<Title>\\n<Author>\"\n- Set figure = []\n- Set formula = []\n- Set template = \"Title Slide.html\"\n\nNode 2 (Contents Slide):\n- Use dag.edge to generate the contents list.\n- For each item in edge:\n - If it starts with a numbering prefix (e.g., \"1 \", \"2. \", \"3-\"), remove the prefix.\n- Join the cleaned section titles with commas and line breaks.\n- Put the result into the text field.\n- Set figure = []\n- Set formula = []\n- Set template = \"Contents.html\"\n\nDo not add extra nodes. Do not infer additional content.",
|
| 15 |
+
|
| 16 |
+
"generate_complete_outline_prompt": "You are an expert academic slide writer. You will be given ONE selected_node in JSON format, containing name, content, and visual_node fields. Your task is to generate EXACTLY ONE outline node for a presentation slide.\n\nRules:\n1. Output MUST be a single JSON object, not an array, with the following schema:\n{\n \"text\": string,\n \"figure\": [],\n \"formula\": [],\n \"template\": null\n}\n\n2. text:\n- Summarize the selected_node.content into a concise, clear paragraph suitable for ONE PPT slide.\n- Do NOT start with phrases like \"This slide introduces\" or \"In this section\".\n- Write direct academic content only.\n\n3. figure and formula:\n- Read ALL items in selected_node.visual_node.\n- If an item has formula == 0, copy the entire item (name, caption, resolution) into figure.\n- If an item has formula == 1, copy the entire item (name, caption, resolution) into formula.\n- If none exist, leave the corresponding array empty.\n\n4. template:\n- Always set template to null.\n\n5. Do NOT invent images, formulas, or content.\n6. Do NOT include explanations, comments, or markdown fences.\n7. Return ONLY the JSON object.",
|
| 17 |
+
|
| 18 |
+
"arrange_template_prompt": "You are an expert slide layout and template selector for PowerPoint-like presentations.\n\nYour goal:\nGiven a single slide node from an outline.json file, you must choose exactly ONE template filename from the allowed set and return it in JSON format.\n\nThe slide node you will receive has the following structure (top-level outline is a list of such nodes):\n[\n {\n \"text\": \"...\", // plain text that will be placed directly on the slide\n \"figure\": [ // list of image objects, can be empty\n {\n \"name\": \"...\", // image identifier or markdown image string\n \"caption\": \"...\", // text caption for the image\n \"resolution\": \"WIDTHxHEIGHT\" // e.g. \"602x350\" (width x height)\n },\n ...\n ],\n \"formula\": [ // list of formula objects, can be empty\n {\n \"latex\": \"...\", // or another field name, but there will be a \"resolution\" field\n \"resolution\": \"WIDTHxHEIGHT\" // same format: width x height\n },\n ...\n ],\n \"template\": null // or a template filename string like \"T2_ImageRight.html\"\n },\n ...\n]\n\nYou must:\n1. Carefully inspect how many figures (images) and formulas the slide has (use the \"figure\" and \"formula\" arrays).\n2. Use each figure's and formula's \"resolution\" string to decide whether it is wide (width > height) or narrow/tall (height > width).\n3. Choose the template whose structure best matches:\n - the total count of images and formulas;\n - whether images/formulas are wide or narrow;\n - whether the slide is mostly text-only.\n4. If there is no perfect match, choose the closest reasonable template.\n5. Always return a valid template name that exists in the list below, with the exact filename (e.g. \"T2_ImageRight.html\").\n\nDefinitions about width/height:\n- A \"wide\" image or formula has a resolution where the first number (width) is significantly larger than the second number (height). For example, \"800x400\" is clearly wide.\n- A \"narrow\"/\"tall\" image or formula has a resolution where the second number (height) is significantly larger than the first number (width). For example, \"400x800\" is tall.\n\nAvailable templates (you MUST choose one of these):\n1. T1_TextOnly.html\n - Only contains centered text.\n - Use this when the slide only contains text and has no images or formulas.\n\n2. T2_ImageRight.html\n - Left half: text area.\n - Right half: one image.\n - The image is slightly wide.\n - Use this when there is mostly text and exactly one relatively wide image that should be on the right.\n\n3. T3_ImageLeft.html\n - Right half: text area.\n - Left half: one image.\n - The image is slightly wide.\n - Use this when there is mostly text and exactly one relatively wide image that should be on the left.\n\n4. T4_ImageTop.html\n - Top large area: one wide image.\n - Bottom small area: one block of text.\n - Use this when there is one wide image that should be emphasized at the top with some text below.\n\n5. T5_TwoImages.html\n - Left 1/2: one slightly wide image.\n - Right 1/2: one slightly wide image.\n - Use this for exactly two wide images side by side, with little or no text.\n\n6. T6_TwoImages2.html\n - Slide is split into top 3/4 and bottom 1/4.\n - Top 3/4: two wide images side by side (left and right).\n - Bottom 1/4: one text block.\n - Use this when there are two wide images that should be on top with a small text section below.\n\n7. T7_2×2_TopImage.html\n - Slide is divided into four equal quadrants: top-left, top-right, bottom-left, bottom-right.\n - Top-left and top-right: each contains a wide image.\n - Bottom-left and bottom-right: each contains a text block.\n - Use this when there are exactly two wide images and two text blocks, and images should be on the top row.\n\n8. T8_2×2_BottomImage.html\n - Four equal quadrants.\n - Bottom-left and bottom-right: each contains a wide image.\n - Top-left and top-right: each contains a text block.\n - Use this when there are exactly two wide images and two text blocks, and images should be on the bottom row.\n\n9. T9_2×2_AltTextImg.html\n - Four equal quadrants.\n - Top-left and bottom-right: wide images.\n - Top-right and bottom-left: text blocks.\n - Use this when there are two wide images and two text blocks arranged in an alternating diagonal pattern.\n\n10. T10_4Img_2×2Grid.html\n - Four equal quadrants.\n - Each quadrant contains a wide image.\n - Use this when there are four images (typically wide) and essentially no text content, or text is minimal.\n\n11. T11_3Img_TopTextBottom.html\n - The top part contains three formulas, and the bottom part contains one text block.\n - Use this when there are exactly three formulas to show together and some explanatory text underneath.\n\n12. T12_3Img_BottomTextTop.html\n - Slide is divided into top 1/3 and bottom 2/3.\n - Top 1/3: one text block.\n - Bottom 2/3: three images from left to right, all about the same size and approximately square.\n - Use this when you have three almost-square images and a short text description above them.\n\n13. T13_3Img.html\n - From left to right: three narrow/tall images of similar size.\n - Use this when there are exactly three narrow images that should be placed horizontally.\n\n14. T14_ImageRight_1Formula.html\n - Left 1/2: one text block.\n - Right 1/2: from top to bottom, one wide image and one formula.\n - Use this when the slide has text + one wide image + one formula, and the image+formula should be on the right.\n\n15. T15_ImageLeft_1Formula.html\n - Right 1/2: one text block.\n - Left 1/2: from top to bottom, one wide image and one formula.\n - Use this when the slide has text + one wide image + one formula, and the image+formula should be on the left.\n\n16. T16_1Img_2Formula_TopTextBottom.html\n - From top to bottom: one very wide image, one formula, one formula, then one text block.\n - Use this when there is one very wide image plus two formulas and some text.\n\n17. T17_2Img_1Formula_TopTextBottom.html\n - Slide is divided vertically into three bands in the ratio 4/9, 1/9, 4/9.\n - Top 4/9: two wide images side by side (left and right).\n - Middle 1/9: one formula.\n - Bottom 4/9: one text block.\n - Use this when you have two wide images, one formula, and some text.\n\n18. T18_2Formula_TopTextBottom.html\n - From top to bottom: one formula, one formula, then one text block.\n - Use this when the slide primarily has two formulas and some text.\n\n19. T19_2Text.html\n - Two text blocks: left side text and right side text.\n - Use this when there are two separate text sections that should be displayed side by side, and there are no images or formulas. 20. T20_FormulaTop.html - Top area contains one formula and bottom area contains one text block; use this when the slide has exactly one formula that should be emphasized at the top with explanatory text below.\n\n21. T21_3Img_col.html - Slide is divided into three equal vertical sections (top 1/3, middle 1/3, bottom 1/3), each containing one wide image; use this when there are exactly three wide images stacked vertically with little or no text. \n\nDecision rules (important):\n- If there is only text and no images/formulas, strongly prefer T1_TextOnly.html or T19_2Text.html depending on whether you need one or two distinct text blocks.\n- When the node has exactly one wide image and text, use T2_ImageRight.html or T3_ImageLeft.html based on which side seems more natural. If there is no additional hint, you may choose either.\n- When the node contains formulas, prefer templates that explicitly mention formulas in their description (T11, T14, T15, T16, T17, T18) if the structure matches the counts.\n- Always try to match the number of images and formulas in the node with the number expected by the template.\n- If the node has more content items than the template can clearly hold, choose the template that still best reflects the main visual structure and ignore the minor mismatch.\n- If the orientation (wide vs narrow) does not match perfectly, choose the closest layout and assume small differences are acceptable.\n\nOutput format (VERY IMPORTANT):\n- You must respond ONLY with a single JSON object on the first line.\n- No explanations, no additional text.\n- The JSON object must have exactly one field: \"template\".\n- Example of a valid response:\n {\"template\": \"T2_ImageRight.html\"}\n\nIf you are unsure, pick the closest reasonable template and still obey the JSON-only response requirement.",
|
| 19 |
+
|
| 20 |
+
"generate_ppt_with_gemini_prompt" : "You are given (1) a slide node (JSON) and (2) an HTML slide template. Your task: revise the HTML template to produce the final slide HTML using the node content. Node fields: text (slide textual content), figure (list of images to display, each has name, caption, resolution), formula (list of formula images to display, each has name, caption, resolution), template (template filename). IMPORTANT RULES: 1) Only modify places in the HTML that are marked by comments like <!-- You need to revise the following parts. X: ... -->. 2) For 'Subjects' sections: replace the placeholder title with ONE concise summary sentence for this slide. 3) For 'Image' sections (<img ...>): replace src with the relative path extracted from node.figure/formula[i].name; the node image name may be markdown like '', use only 'images/abc.jpg'. 4) For 'Text' sections: replace the placeholder text with the node.text content, formatted cleanly in HTML; keep it readable and you may use <p>, <ul><li>, <br/> appropriately. 5) If the template expects more images/text blocks than provided by the node, leave the missing positions unchanged and do not invent content. 6) If the node provides more images than the template has slots, fill slots in order and ignore the rest. 7) Preserve all other HTML, CSS, and structure exactly. OUTPUT FORMAT: Return ONLY the revised HTML as plain text. Do NOT wrap it in markdown fences. Do NOT add explanations.",
|
| 21 |
+
|
| 22 |
+
"commenter_prompt": "Role: UI Design Auditor & Bridge Specialist\n\nProfile\nYou are a Senior UI/UX Designer. Your core capability is 'Visual Diagnosis' and 'Instruction Translation'. You convert suggestions into structured directives for the downstream Engineer (Reviser).\n\nDesign Principles\n1. Information Completeness First: Prioritize displaying the full content. Try layout adjustments before reducing font size.\n2. Strict Adherence to Outline: Any added content must be strictly derived from the Outline. Do NOT hallucinate.\n3. Structural Fidelity: Do NOT alter the fundamental layout topology. You may only fine-tune the spatial ratios (Flex).\n4. Typography Constraints: For body text (non-title), the font-size MUST NOT exceed 24pt, and the line-height MUST NOT exceed 1.5.\n\nSuccess Criteria (Stop Conditions)\nIf the slide meets ALL the following criteria, you MUST mark it as 'PASS' and stop optimizing:\n1. No Large Voids: There are no massive, awkward empty white spaces.\n2. No Overflow: No text is cut off, overlapping, or spilling out of containers.\n3. Good Legibility: Text size is within the valid range (16pt <= size <= 24pt) and distinct.\n4. Balanced Visuals: Images are not squeezed too small and occupy appropriate space.\n\nAudit Dimensions\n1. Layout Balance: Check Image/Text Flex ratio. If image is too small, trigger RESIZE.\n2. Space Utilization (Whitespace): Check for excessive empty space.\n - Priority 1: If layout ratio is reasonable, trigger TYPOGRAPHY to increase font size (up to a MAX of 24pt) or line height (up to a MAX of 1.5) to fill the void.\n - Priority 2: Trigger RESIZE to reduce this text section's flex ratio (give space to image) ONLY if font is already at 24pt or text area is disproportionately wide.\n - Priority 3: Trigger ADD_CONTENT only as a last resort.\n3. Boundary Integrity (Overflow): Check for overflow.\n - Priority 1: Trigger RESIZE. Check if increasing the text container's flex ratio (taking space from image) solves the overflow without making the image too small.\n - Priority 2: Trigger TYPOGRAPHY to reduce font size (min 16pt) ONLY if resizing is insufficient or impossible.\n - Priority 3: Trigger REWRITE_SHORTEN ONLY if font size is at 16pt and text still overflows.\n4. Legibility: Check font size. If <16pt, trigger TYPOGRAPHY to increase size. If >24pt, trigger TYPOGRAPHY to reduce size to 24pt.\n5. Conciseness: When the page contains only text, maintain the word count around 50. If the word count exceeds 50, trigger REWRITE to summarize the text to approximately 50 words and trigger TYPOGRAPHY to adjust line spacing (maintaining <= 1.5).\n\nOutput Format (Strict Adherence)\n\n## Part 1: Audit Conclusion\nStatus: [PASS / NEEDS_REVISION]\nReason: [If PASS, explain why it meets criteria. If NEEDS_REVISION, summarize the failure.]\n\n## Part 2: Engineer-Oriented Instructions\n(Generate ONLY if Status is NEEDS_REVISION. Otherwise output 'None')\nFormat: - [TARGET: Element Description] -> [ACTION: RESIZE/REWRITE/TYPOGRAPHY] -> [DETAIL: Specific Operation]\n\nExamples:\n- [TARGET: Body text] -> [ACTION: TYPOGRAPHY] -> [DETAIL: Significant whitespace detected. Increase font size to the limit of 24pt and line-height to 1.5 to fill the container.]\n- [TARGET: Main body text] -> [ACTION: REWRITE] -> [DETAIL: Pure text slide exceeds 50 words. Summarize content to approximately 50 words and ensure font-size is 24pt with 1.5 line-height.]\n\nI will provide historical evaluations and revision records, based on previous records and the current status of the page images for evaluation and modifications. Please wait for input to begin.",
|
| 23 |
+
|
| 24 |
+
"reviser_prompt": "Role: UI Layout Refactor Engineer (JSON Refactorer)\n\nProfile\nYou are a backend logic module. Your task is to receive natural language instructions and modify JSON data. Your core task is to **generate raw HTML strings capable of being directly rendered by a browser**, strictly forbidding HTML entity escaping.\n\nTask Inputs\n1. Auditor Instructions\n2. Original Layout Tree (JSON)\n3. PPT Outline\n\nCore Processing Logic\n\nStep 1: Node Location\nParse [TARGET] to find the corresponding `content-block` or `layout-field`.\n\nStep 2: Parameter Modification\nModify based on [ACTION]:\n\n1. ACTION: RESIZE (Adjust Flex)\n - Adjust the `flex` value of the target node and its siblings proportionally.\n\n2. ACTION: REWRITE/ADD_CONTENT (Modify Content to Raw HTML)\n - Extract [DETAIL] content.\n - **Structural Requirement**: To improve legibility, you must process text into a structured format. **Prioritize using bulleted lists (`<ul><li>`)** over plain paragraphs. Ensure the text structure is adapted to the layout tree hierarchy.\n - **Mandatory Format**: Must output HTML tags containing raw angle brackets `<` and `>`.\n - **Absolute Prohibitions**:\n - ❌ **STRICTLY FORBIDDEN** to use `<` instead of `<`.\n - ❌ **STRICTLY FORBIDDEN** to use `>` instead of `>`.\n - ❌ **STRICTLY FORBIDDEN** to use `&` instead of `&`.\n - Allowed tags: `<ul>`, `<li>`, `<p>`, `<b>`, `<br>`.\n - The target system's renderer **cannot parse** entity encodings; if you output `<`, the system will error. You must output `<`.\n - Overwrite the target node's `content` field.\n\n3. ACTION: TYPOGRAPHY\n - Modify `typography.font-size` (>= 16pt).\n\n4. ACTION: MODIFY_TITLE (Update Heading)\n - Extract the new title text from [DETAIL].\n - Locate the `heading` field of the target node and overwrite it directly.\n\nConstraints\n1. Output must be valid JSON.\n2. **JSON Escaping vs HTML Escaping**:\n - ✅ **MUST** escape double quotes: `\"` (Requirement of JSON syntax)\n - ❌ **FORBIDDEN** to escape angle brackets: `<` (Requirement of your task)\n\nCorrect vs Incorrect Examples\n- ❌ Incorrect (Unstructured text): \"content\": \"This is point one. This is point two.\"\n- ✅ Correct (Bulleted structure): \"content\": \"<ul><li>This is point one</li><li>This is point two</li></ul>\"\n\nInput Processing\nRead instructions and JSON, output the modified JSON.",
|
| 25 |
+
|
| 26 |
+
"poster_outline_prompt":"You are given a section node JSON (SECTION_JSON) from a paper DAG. The section JSON you see has NO visual_node field and must be treated as authoritative.\n\nSECTION_JSON:\n{SECTION_JSON}\n\nHAS_VISUAL: {HAS_VISUAL}\n\nIf HAS_VISUAL is true, you are also given the best visual node JSON (VISUAL_JSON), plus IMAGE_SRC and ALT_TEXT. The visual content MUST ONLY come from this provided IMAGE_SRC (do not invent or substitute any other image).\n\nVISUAL_JSON:\n{VISUAL_JSON}\n\nIMAGE_SRC: {IMAGE_SRC}\nALT_TEXT: {ALT_TEXT}\n\nTask:\n1) Write ONE concise paragraph summarizing ONLY the section's content for a scientific poster. Constraints: 2–5 sentences, factual, non-hallucinatory, no bullet lists, and avoid starting with \"This section\" Additional constraint: The summary must contain no more than 40 words and be written with strong logical coherence and smooth transitions to minimize perplexity (PPL).\n2) Output EXACTLY ONE HTML section block in the required template below. Output ONLY the HTML and nothing else.\n\nStrict output rules:\n- Output only ONE <section class=\"section\">...</section> block.\n- Do NOT add markdown fences, explanations, or extra text.\n- The <div class=\"section-bar\"> must be the section title (use SECTION_JSON.name).\n- Replace the sample paragraph text with your summary paragraph.\n- If HAS_VISUAL is true AND IMAGE_SRC is non-empty, include exactly one <div class=\"img-section\"> with one <img> whose src is exactly IMAGE_SRC and alt is ALT_TEXT.\n- If HAS_VISUAL is false OR IMAGE_SRC is empty, do NOT output any img-section or img tag.\n\nRequired HTML template (follow structure exactly):\n<section class=\"section\">\n <div class=\"section-bar\" contenteditable=\"true\">SECTION_TITLE</div>\n <div class=\"section-body\" contenteditable=\"true\">\n\n <p>SUMMARY_TEXT</p>\n\n <div class=\"img-section\">\n <img src=\"IMAGE_SRC\" alt=\"ALT_TEXT\" class=\"figure\" />\n </div>\n </div>\n</section>",
|
| 27 |
+
|
| 28 |
+
"modified_poster_logic_prompt":"You are given an HTML-like poster outline consisting of multiple <section class=\"section\"> blocks. Each section has a title in <div class=\"section-bar\">...</div> and main text in the first <p>...</p> inside <div class=\"section-body\">.\n\nYour task: Write ONLY bridging sentences to connect the narrative flow between sections.\n- You MUST generate one bridging sentence for each section from the FIRST section up to the SECOND-TO-LAST section.\n- Each bridging sentence should be placed at the END of that section's first <p>...</p>, and should naturally lead into the NEXT section.\n- The sentence MUST be content-aware: it should reference the next section's topic (based on its title and/or content) without adding new technical claims.\n\nSTRICT OUTPUT REQUIREMENTS:\n1) Output ONLY a valid JSON array of strings.\n2) The array length MUST equal (number_of_sections - 1).\n3) The i-th string corresponds to the i-th section (0-indexed) and bridges to section i+1.\n4) Do NOT output any HTML. Do NOT output explanations. Do NOT output markdown fences.\n5) Each string should be a single sentence in fluent academic English, concise (about 12–25 words), and must not include newline characters.\n\nCONTENT SAFETY / FORMATTING CONSTRAINTS:\n- Do NOT modify, rewrite, paraphrase, or comment on any existing text.\n- Do NOT include section numbers.\n- Avoid generic filler like \"In conclusion\". Prefer specific transitions like \"Next, we turn to ...\" while reflecting the next section’s topic.\n\nNow wait for the user to provide the full poster outline text.You may prioritize the following transition patterns: when the next section is intended to introduce, elaborate on, or substantiate a method or idea, use phrasing such as “To introduce / elaborate on / substantiate <the content of the next section>, we next present <the title or core focus of the next section>.”; if the next section is an experimental section (e.g., the title contains Experiment(s) or the content discusses experimental setups, results, or performance), use transitions like “Next, we evaluate <the experimental subject or benchmark> to demonstrate …” or “We then conduct experiments on <the target task or dataset> to empirically validate the proposed method.”; in all cases, the transition sentence should explicitly point to the next section’s topic without introducing new technical details or conclusions, serving only to ensure narrative continuity.",
|
| 29 |
+
|
| 30 |
+
"poster_refinement_prompt": "You are an expert Academic Poster Designer and Web Developer. Your task is to refine an existing HTML poster based on its visual rendering (screenshot) and the current code. Output ONLY the full, valid, and corrected HTML code inside a single code block.\n\nI will provide the following content:\n1. **Current Poster Code (HTML)**\n2. **Visual Render (Image)**\n\n**TASKS:**\n\n**Task 1: Fix LaTeX/Encoding Issues**\n- Scan the HTML for raw LaTeX code that is not rendering correctly (e.g., \"$d_S \\ge 10$\").\n- **FIX:** Replace raw LaTeX with standard HTML entities or Unicode text to ensure readability (e.g., change \"$d_S \\ge 10$\" to \"dS ≥ 10\").\n- Remove any garbled characters or artifacts caused by math rendering failures.\n\n**Task 2: Normalize Section Headers**\n- Locate all elements with `class=\"section-bar\"`.\n- Remove any leading numbering, alphabetic prefixes, or meaningless characters (e.g., \"1.\", \"2.1\", \"A.\", \"E.\", \"-\") from the text content.\n- Ensure only the core title text remains.\n- **Example:** Change `<div class=\"section-bar\" contenteditable=\"true\">E. Implementation details</div>` to `<div class=\"section-bar\" contenteditable=\"true\">Implementation details</div>`.\n\n**Output Requirement:**\n- Return the **complete, runnable HTML code**.\n- Do not break the existing CSS layout style; only inject or fix content.\n\nI will now provide the Current Poster HTML and the Rendered Screenshot. Please wait for these inputs and then generate the final HTML code. IMPORTANT: During refinement, do NOT modify any font-related settings, including but not limited to font-family, font names, font styles, or font sources.",
|
| 31 |
+
|
| 32 |
+
"extract_basic_information_prompt":"You will be given a single JSON object named ROOT_NODE_JSON representing the root node of a paper DAG. Your task is to extract and format the paper's basic metadata.\n\nINPUT:\n- ROOT_NODE_JSON.name: paper title.\n- ROOT_NODE_JSON.content: contains authors followed by institutions (the first part is a comma-separated list of author names; the second part is a comma-separated list of institutions). The boundary may be indicated by a newline, multiple spaces, or a transition from person names to organization names. Infer the best split.\n- ROOT_NODE_JSON.github: a GitHub/project URL string. If missing, empty, null, or not a valid URL, output N/A.\n\nOUTPUT REQUIREMENTS (STRICT):\n- Output exactly 4 lines, in this exact order and with these exact labels:\nTitle: <title>\nAuthor: <author1, author2, ...>\nInstitution: <institution1, institution2, ...>\nGithub: <url_or_N/A>\n- Do NOT add any extra lines, explanations, bullets, numbering, code fences, or markdown.\n- Preserve original capitalization for names and institutions.\n- If authors or institutions cannot be reliably separated, make the best effort: keep person names in Author, organizations in Institution.",
|
| 33 |
+
|
| 34 |
+
"futurework_and_reference_prompt":"You are given a paper Markdown (MD). Your job:\n1) Find whether the paper includes a Future Work / Future work / Future directions / Limitations and future work / Discussion and future work section (or future-work-like content). If it exists, extract the key points and rewrite them into ONE concise paragraph (scientific, factual, non-hallucinatory). If it does NOT exist, write a reasonable Future Work paragraph by summarizing limitations and plausible next steps based ONLY on the provided MD. Do NOT invent results or claims not present in MD.\n2) Find the References/Bibliography section in MD and select the FIRST THREE references as they appear. Preserve author/title/venue/year/URL text exactly as present in MD. Do not invent missing bibliographic fields. If references are numbered, keep the numbering; otherwise create [1], [2], [3]. Each reference must be a single line string.\n\nOUTPUT FORMAT (STRICT):\nReturn ONLY valid JSON (no markdown fences, no extra text):\n{\n \"future_work\": \"<ONE paragraph, no newlines>\",\n \"references\": [\"ref1\", \"ref2\", \"ref3\"]\n}\n\nMD:\n{MD_TEXT}\n",
|
| 35 |
+
|
| 36 |
+
"contribution_prompt":"You are a professional academic editor. Your task is to identify and summarize the 'Contributions' of a research paper based on the provided Markdown content.\n\nRules:\n1. Identification: If a 'Contribution' section exists, extract and refine the key points. If NOT, analyze the Introduction or Conclusion to summarize the main contributions yourself.\n2. Constraints: Summarize the contributions into concise points. **Each point must be strictly under 25 words.**\n3. Format Requirement: Output ONLY pure plain text.\n - Do NOT use Markdown formatting (no bolding, headers, or bullet points).\n - Do NOT use HTML tags.\n - Separate distinct points using double newlines (\\n\\n).\n - The output must be ready to be wrapped in <p> tags directly.",
|
| 37 |
+
|
| 38 |
+
"generate_pr_prompt":"You will receive ONE JSON object describing a paper section node with fields: name, content, visual_node (a list of image objects/paths). Your task: (1) Determine which high-level paper part this section belongs to: Introduction-like, Methods-like, Experiments/Results-like, or Conclusion-like, based on name and content. (2) Output ONLY ONE of the following formats (no extra text):\n\n[If Introduction-like]\nKey Question: <2-3 sentences, engaging question/surprising fact/relatable hook>\nBrilliant Idea: <2-3 sentences background/context/idea>\n<OPTIONAL one image markdown on a new line, choose the single most important image if available: >\n\n[If Methods-like]\nCore Methods: <concise but as comprehensive as possible summary of concepts/methods>\n<OPTIONAL one image markdown on a new line: >\n\n[If Experiments/Results-like]\nCore Results: <key experiments + main conclusions>\n<OPTIONAL one image markdown on a new line: >\n\n[If Conclusion-like]\nSignificance/Impact: <potential impact, applications, importance>\n\nRules: Use English labels exactly as shown. If no suitable image exists, omit the image line entirely. Choose at most ONE image. Do not output code fences. Here is the node JSON:\n{NODE_JSON}",
|
| 39 |
+
|
| 40 |
+
"add_title_and_hashtag_prompt":"You will receive a Markdown promotion draft for an academic paper.\n\nTASK:\n1) Write a short, catchy, easy-to-understand Title that accurately summarizes the core topic or main finding for a general audience. Prefer a hook style (question / key result / clear takeaway). Avoid excessive jargon, but keep scientific accuracy.\n2) Generate EXACTLY 3 highly relevant Specific Tags (each must start with '#', PascalCase recommended; no spaces inside a tag).\n3) Generate EXACTLY 1 Community Tag related to activity/community (must start with '#'; no spaces inside the tag).\n\nINPUT MARKDOWN (do not rewrite it, only use it as context):\n{MD_TEXT}\n\nOUTPUT FORMAT (strictly follow, one item per line; every tag MUST include '#'):\nTitle: <your title>\nSpecific Tag: <#Tag1> <#Tag2> <#Tag3>\nCommunity Tag: <#CommunityTag>",
|
| 41 |
+
|
| 42 |
+
"pr_refinement_prompt": "Refine the content of each section to match the 'Xiaohongshu' (Little Red Book) style in English. \n\nRequirements:\n1. **Style**: Use a lively, engaging, and 'sharing with friends' tone. Use short paragraphs and bullet points.\n2. **Visuals**: Generously use relevant emojis to structure the text and add vibe.\n3. **Content**: Strictly retain all original information and technical details. Do NOT add any information not present in the source text.\n4. **Length**: Keep the word count approximately the same as the original text.\n5. **Format**: Return valid Markdown.",
|
| 43 |
+
|
| 44 |
+
"section_generation_prompt":"You are given ONE section of an academic paper in Markdown format. Your task is to convert it into a DAG-style JSON object with schema: {\"nodes\":[{\"name\":string,\"content\":string,\"edge\":string[],\"level\":int,\"visual_node\":[]}...]}. STRICT RULES: (1) Output ONLY valid JSON (no markdown fences, no commentary, no extra keys). (2) Use the provided SECTION_FILENAME as the ROOT node name. (3) ROOT node: name = SECTION_FILENAME; content = the ENTIRE original Markdown exactly as given; level = 1; visual_node = []; edge = a list of subsection node names extracted from this Markdown. (4) Subsection nodes: Identify ALL subsections whose headings contain hierarchical numbering like '3.1', '3.2', '4.1', '4.3' etc. Treat each such heading as a subsection boundary. For each subsection, create ONE node where: name = the subsection heading text (remove leading Markdown #'s, trim spaces, keep the numbering and title text); content = the FULL Markdown belonging to that subsection ONLY (from its heading line up to before the next same-level numbered subsection heading or end of document), preserving original text exactly; level = 2; edge = []; visual_node = []. (5) ROOT.edge must exactly match the list of subsection node 'name' values, in their original order of appearance. (6) Do NOT invent subsections that are not present. (7) If no numbered subsections exist, output only the ROOT node with edge=[]. INPUTS YOU WILL RECEIVE: SECTION_FILENAME and SECTION_MARKDOWN. Now produce the JSON."
|
| 45 |
+
|
| 46 |
+
}
|
src/DAG2poster.py
ADDED
|
@@ -0,0 +1,871 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import json
|
| 3 |
+
import os
|
| 4 |
+
import re
|
| 5 |
+
import shutil
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
from typing import Optional
|
| 8 |
+
from openai import OpenAI
|
| 9 |
+
from google import genai
|
| 10 |
+
from typing import Any, Dict, List, Optional
|
| 11 |
+
import traceback
|
| 12 |
+
import shutil
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
from bs4 import BeautifulSoup
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
# ========== Generate poster_outline.txt via Gemini (section-by-section) ==========
|
| 18 |
+
def _load_json(path: str) -> Dict[str, Any]:
|
| 19 |
+
if not os.path.exists(path):
|
| 20 |
+
raise FileNotFoundError(f"JSON not found: {path}")
|
| 21 |
+
with open(path, "r", encoding="utf-8") as f:
|
| 22 |
+
return json.load(f)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def _ensure_dag_schema(dag_obj: Any) -> Dict[str, Any]:
|
| 26 |
+
"""
|
| 27 |
+
Robustness: if LLM/other step produced a single node dict instead of {"nodes":[...]},
|
| 28 |
+
wrap it into the expected schema.
|
| 29 |
+
"""
|
| 30 |
+
if isinstance(dag_obj, dict) and "nodes" in dag_obj and isinstance(dag_obj["nodes"], list):
|
| 31 |
+
return dag_obj
|
| 32 |
+
if isinstance(dag_obj, dict) and "name" in dag_obj and "content" in dag_obj:
|
| 33 |
+
return {"nodes": [dag_obj]}
|
| 34 |
+
raise ValueError("Invalid dag.json schema: expected {'nodes': [...]} or a single node dict.")
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def _resolution_area(resolution: Any) -> int:
|
| 38 |
+
"""
|
| 39 |
+
resolution can be like "536x86" (string) or [536, 86] etc.
|
| 40 |
+
Returns area; invalid -> 0
|
| 41 |
+
"""
|
| 42 |
+
if resolution is None:
|
| 43 |
+
return 0
|
| 44 |
+
if isinstance(resolution, str):
|
| 45 |
+
m = re.match(r"^\s*(\d+)\s*[xX]\s*(\d+)\s*$", resolution)
|
| 46 |
+
if not m:
|
| 47 |
+
return 0
|
| 48 |
+
w = int(m.group(1))
|
| 49 |
+
h = int(m.group(2))
|
| 50 |
+
return w * h
|
| 51 |
+
if isinstance(resolution, (list, tuple)) and len(resolution) >= 2:
|
| 52 |
+
try:
|
| 53 |
+
w = int(resolution[0])
|
| 54 |
+
h = int(resolution[1])
|
| 55 |
+
return w * h
|
| 56 |
+
except Exception:
|
| 57 |
+
return 0
|
| 58 |
+
if isinstance(resolution, dict):
|
| 59 |
+
# sometimes {"width":..., "height":...}
|
| 60 |
+
try:
|
| 61 |
+
w = int(resolution.get("width", 0))
|
| 62 |
+
h = int(resolution.get("height", 0))
|
| 63 |
+
return w * h
|
| 64 |
+
except Exception:
|
| 65 |
+
return 0
|
| 66 |
+
return 0
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def _strip_md_image(s: str) -> str:
|
| 70 |
+
return (s or "").strip()
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def _extract_image_src_from_md(md_image: str) -> Optional[str]:
|
| 74 |
+
"""
|
| 75 |
+
md_image example: "" or "  "
|
| 76 |
+
returns "images/xxx.jpg" (without surrounding spaces)
|
| 77 |
+
"""
|
| 78 |
+
if not md_image:
|
| 79 |
+
return None
|
| 80 |
+
m = re.search(r"!\[[^\]]*\]\(([^)]+)\)", md_image.strip())
|
| 81 |
+
if not m:
|
| 82 |
+
return None
|
| 83 |
+
return m.group(1).strip()
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def _safe_section_title(name: str) -> str:
|
| 87 |
+
"""
|
| 88 |
+
Optional cleanup: remove trailing .md if present.
|
| 89 |
+
"""
|
| 90 |
+
if not name:
|
| 91 |
+
return ""
|
| 92 |
+
name = name.strip()
|
| 93 |
+
if name.lower().endswith(".md"):
|
| 94 |
+
name = name[:-3]
|
| 95 |
+
return name.strip()
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def _remove_key_deep(obj: Any, key_to_remove: str) -> Any:
|
| 99 |
+
"""
|
| 100 |
+
Create a JSON-serializable copy of obj with a top-level key removed if dict.
|
| 101 |
+
(We only need to remove section_node["visual_node"] at top-level, but keep it safe.)
|
| 102 |
+
"""
|
| 103 |
+
if isinstance(obj, dict):
|
| 104 |
+
return {k: _remove_key_deep(v, key_to_remove) for k, v in obj.items() if k != key_to_remove}
|
| 105 |
+
if isinstance(obj, list):
|
| 106 |
+
return [_remove_key_deep(x, key_to_remove) for x in obj]
|
| 107 |
+
return obj
|
| 108 |
+
|
| 109 |
+
def generate_poster_outline_txt(
|
| 110 |
+
dag_path: str,
|
| 111 |
+
poster_outline_path: str,
|
| 112 |
+
poster_outline_prompt: str,
|
| 113 |
+
model: str = "gemini-2.5-pro",
|
| 114 |
+
api_key: Optional[str] = None,
|
| 115 |
+
base_url: Optional[str] = None,
|
| 116 |
+
client: Optional[Any] = None, # Type relaxed to accept both clients
|
| 117 |
+
overwrite: bool = True,
|
| 118 |
+
config: dict = None
|
| 119 |
+
) -> None:
|
| 120 |
+
"""
|
| 121 |
+
Read dag.json from dag_path, iterate root->section nodes, and for each section:
|
| 122 |
+
- choose the largest-resolution visual node referenced by section["visual_node"]
|
| 123 |
+
- send (section_without_visual_node, best_visual_node_if_any, IMAGE_SRC, ALT_TEXT) to LLM
|
| 124 |
+
- LLM returns EXACTLY one <section class="section">...</section> HTML block
|
| 125 |
+
- append/write to poster_outline_path
|
| 126 |
+
|
| 127 |
+
Supports both OpenAI and Google GenAI (Gemini) clients.
|
| 128 |
+
"""
|
| 129 |
+
# Resolve dag.json path
|
| 130 |
+
if os.path.isdir(dag_path):
|
| 131 |
+
dag_json_path = os.path.join(dag_path, "dag.json")
|
| 132 |
+
else:
|
| 133 |
+
dag_json_path = dag_path
|
| 134 |
+
|
| 135 |
+
dag_obj = _ensure_dag_schema(_load_json(dag_json_path))
|
| 136 |
+
nodes: List[Dict[str, Any]] = dag_obj.get("nodes", [])
|
| 137 |
+
if not nodes:
|
| 138 |
+
raise ValueError("dag.json has empty 'nodes'.")
|
| 139 |
+
|
| 140 |
+
# Root node is the first node by your spec
|
| 141 |
+
root = nodes[0]
|
| 142 |
+
root_edges = root.get("edge", [])
|
| 143 |
+
if not isinstance(root_edges, list) or not root_edges:
|
| 144 |
+
raise ValueError("Root node has no valid 'edge' list of section names.")
|
| 145 |
+
|
| 146 |
+
# Build lookup: name -> node (first occurrence)
|
| 147 |
+
name2node: Dict[str, Dict[str, Any]] = {}
|
| 148 |
+
for n in nodes:
|
| 149 |
+
if isinstance(n, dict) and "name" in n:
|
| 150 |
+
name2node.setdefault(str(n["name"]), n)
|
| 151 |
+
|
| 152 |
+
# Determine Model Type
|
| 153 |
+
is_gemini = "gemini" in model.lower()
|
| 154 |
+
|
| 155 |
+
# Prepare Client if not provided
|
| 156 |
+
if client is None:
|
| 157 |
+
api_keys_config = config.get("api_keys", {}) if config else {}
|
| 158 |
+
|
| 159 |
+
if is_gemini:
|
| 160 |
+
# Setup Google GenAI Client
|
| 161 |
+
api_key = api_key or api_keys_config.get("gemini_api_key") or os.getenv("GOOGLE_API_KEY")
|
| 162 |
+
|
| 163 |
+
client = genai.Client(api_key=api_key)
|
| 164 |
+
else:
|
| 165 |
+
# Setup OpenAI Client
|
| 166 |
+
api_key = api_key or api_keys_config.get("openai_api_key") or os.getenv("OPENAI_API_KEY")
|
| 167 |
+
|
| 168 |
+
client = OpenAI(api_key=api_key)
|
| 169 |
+
|
| 170 |
+
# Output file init
|
| 171 |
+
out_dir = os.path.dirname(os.path.abspath(poster_outline_path))
|
| 172 |
+
if out_dir and not os.path.exists(out_dir):
|
| 173 |
+
os.makedirs(out_dir, exist_ok=True)
|
| 174 |
+
|
| 175 |
+
write_mode = "w" if overwrite else "a"
|
| 176 |
+
with open(poster_outline_path, write_mode, encoding="utf-8") as f_out:
|
| 177 |
+
# Iterate sections in the order of root.edge
|
| 178 |
+
for sec_name in root_edges:
|
| 179 |
+
if sec_name not in name2node:
|
| 180 |
+
raise KeyError(f"Section node not found by name from root.edge: {sec_name}")
|
| 181 |
+
|
| 182 |
+
section_node = name2node[sec_name]
|
| 183 |
+
if not isinstance(section_node, dict):
|
| 184 |
+
raise ValueError(f"Invalid section node for name={sec_name}")
|
| 185 |
+
|
| 186 |
+
# Find all visual nodes referenced by this section
|
| 187 |
+
visual_refs = section_node.get("visual_node", [])
|
| 188 |
+
best_visual_node: Optional[Dict[str, Any]] = None
|
| 189 |
+
best_area = -1
|
| 190 |
+
best_image_src: Optional[str] = None
|
| 191 |
+
|
| 192 |
+
if isinstance(visual_refs, list) and len(visual_refs) > 0:
|
| 193 |
+
for ref in visual_refs:
|
| 194 |
+
ref_str = _strip_md_image(str(ref))
|
| 195 |
+
cand = name2node.get(ref_str)
|
| 196 |
+
|
| 197 |
+
if cand is None:
|
| 198 |
+
for k, v in name2node.items():
|
| 199 |
+
if isinstance(k, str) and k.strip() == ref_str.strip():
|
| 200 |
+
cand = v
|
| 201 |
+
break
|
| 202 |
+
|
| 203 |
+
if cand is None or not isinstance(cand, dict):
|
| 204 |
+
continue
|
| 205 |
+
|
| 206 |
+
area = _resolution_area(cand.get("resolution"))
|
| 207 |
+
if area > best_area:
|
| 208 |
+
best_area = area
|
| 209 |
+
best_visual_node = cand
|
| 210 |
+
best_image_src = _extract_image_src_from_md(str(cand.get("name", "")))
|
| 211 |
+
|
| 212 |
+
if best_visual_node is not None and not best_image_src:
|
| 213 |
+
for ref in visual_refs:
|
| 214 |
+
tmp = _extract_image_src_from_md(str(ref))
|
| 215 |
+
if tmp:
|
| 216 |
+
best_image_src = tmp
|
| 217 |
+
break
|
| 218 |
+
|
| 219 |
+
# Build the section JSON WITHOUT visual_node attribute
|
| 220 |
+
section_wo_visual = _remove_key_deep(section_node, "visual_node")
|
| 221 |
+
section_wo_visual["name"] = _safe_section_title(str(section_wo_visual.get("name", "")))
|
| 222 |
+
|
| 223 |
+
# Compose ALT_TEXT
|
| 224 |
+
alt_text = None
|
| 225 |
+
if best_visual_node is not None:
|
| 226 |
+
cap = best_visual_node.get("caption")
|
| 227 |
+
if isinstance(cap, str) and cap.strip():
|
| 228 |
+
alt_text = cap.strip()
|
| 229 |
+
if not alt_text:
|
| 230 |
+
alt_text = "Figure"
|
| 231 |
+
|
| 232 |
+
# Compose prompt input fields
|
| 233 |
+
section_json_str = json.dumps(section_wo_visual, ensure_ascii=False, indent=2)
|
| 234 |
+
|
| 235 |
+
if best_visual_node is not None:
|
| 236 |
+
visual_json_str = json.dumps(best_visual_node, ensure_ascii=False, indent=2)
|
| 237 |
+
image_src = best_image_src or ""
|
| 238 |
+
if image_src and not image_src.startswith("images/") and "images/" in image_src:
|
| 239 |
+
pass
|
| 240 |
+
payload = poster_outline_prompt.format(
|
| 241 |
+
SECTION_JSON=section_json_str,
|
| 242 |
+
HAS_VISUAL="true",
|
| 243 |
+
VISUAL_JSON=visual_json_str,
|
| 244 |
+
IMAGE_SRC=image_src,
|
| 245 |
+
ALT_TEXT=alt_text,
|
| 246 |
+
)
|
| 247 |
+
else:
|
| 248 |
+
payload = poster_outline_prompt.format(
|
| 249 |
+
SECTION_JSON=section_json_str,
|
| 250 |
+
HAS_VISUAL="false",
|
| 251 |
+
VISUAL_JSON="",
|
| 252 |
+
IMAGE_SRC="",
|
| 253 |
+
ALT_TEXT="",
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
# Call API based on model type
|
| 257 |
+
html_block = ""
|
| 258 |
+
if is_gemini:
|
| 259 |
+
# Gemini New API Call
|
| 260 |
+
# Note: config is passed via helper if needed, usually default generation config is fine
|
| 261 |
+
resp = client.models.generate_content(
|
| 262 |
+
model=model,
|
| 263 |
+
contents=payload
|
| 264 |
+
)
|
| 265 |
+
if resp.text:
|
| 266 |
+
html_block = resp.text
|
| 267 |
+
else:
|
| 268 |
+
raise RuntimeError("Gemini returned empty content.")
|
| 269 |
+
else:
|
| 270 |
+
# OpenAI API Call
|
| 271 |
+
resp = client.chat.completions.create(
|
| 272 |
+
model=model,
|
| 273 |
+
messages=[{"role": "user", "content": payload}],
|
| 274 |
+
)
|
| 275 |
+
if not hasattr(resp, "choices") or not resp.choices:
|
| 276 |
+
raise RuntimeError("OpenAI returned empty choices.")
|
| 277 |
+
|
| 278 |
+
html_block = resp.choices[0].message.content
|
| 279 |
+
|
| 280 |
+
if not isinstance(html_block, str) or not html_block.strip():
|
| 281 |
+
raise RuntimeError("LLM returned empty content string.")
|
| 282 |
+
|
| 283 |
+
# Append to output file
|
| 284 |
+
f_out.write(html_block.strip())
|
| 285 |
+
f_out.write("\n\n")
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
# ========== Modify poster_outline.txt ==========
|
| 289 |
+
def modify_poster_outline(
|
| 290 |
+
poster_outline_path: str,
|
| 291 |
+
poster_paper_name: str,
|
| 292 |
+
modified_poster_outline_path: str
|
| 293 |
+
):
|
| 294 |
+
"""
|
| 295 |
+
功能:
|
| 296 |
+
1. 找到 section-bar 内容等于 poster_paper_name 的 section (忽略大小写):
|
| 297 |
+
- 将其 section-bar 改为 "Introduction"
|
| 298 |
+
- 将该 section 移动到文件最前面
|
| 299 |
+
2. 对其余 section:
|
| 300 |
+
- 删除 section-bar 标题前的数字序号
|
| 301 |
+
3. 只保留处理后的前 6 个 section
|
| 302 |
+
4. 将最终结果保存到 modified_poster_outline_path
|
| 303 |
+
"""
|
| 304 |
+
|
| 305 |
+
text = Path(poster_outline_path).read_text(encoding="utf-8")
|
| 306 |
+
|
| 307 |
+
# ===== 1. 提取所有 section 块 =====
|
| 308 |
+
section_pattern = re.compile(
|
| 309 |
+
r"<section class=\"section\">.*?</section>",
|
| 310 |
+
re.DOTALL
|
| 311 |
+
)
|
| 312 |
+
sections = section_pattern.findall(text)
|
| 313 |
+
|
| 314 |
+
intro_section = None
|
| 315 |
+
other_sections = []
|
| 316 |
+
|
| 317 |
+
# 预处理目标名称:去除首尾空格并转小写,用于后续比较
|
| 318 |
+
target_name_normalized = poster_paper_name.strip().lower()
|
| 319 |
+
|
| 320 |
+
for sec in sections:
|
| 321 |
+
# 提取 section-bar 内容
|
| 322 |
+
m = re.search(
|
| 323 |
+
r"<div class=\"section-bar\" contenteditable=\"true\">(.*?)</div>",
|
| 324 |
+
sec,
|
| 325 |
+
re.DOTALL
|
| 326 |
+
)
|
| 327 |
+
if not m:
|
| 328 |
+
continue
|
| 329 |
+
|
| 330 |
+
# 获取原始内容用于后续替换,同时获取用于比较的归一化字符串
|
| 331 |
+
original_title = m.group(1).strip()
|
| 332 |
+
current_title_normalized = original_title.lower()
|
| 333 |
+
|
| 334 |
+
# ===== 2. 处理 paper title 对应的 section (修改点:忽略大小写) =====
|
| 335 |
+
if current_title_normalized == target_name_normalized:
|
| 336 |
+
# 改名为 Introduction
|
| 337 |
+
sec = re.sub(
|
| 338 |
+
r"<div class=\"section-bar\" contenteditable=\"true\">.*?</div>",
|
| 339 |
+
'<div class="section-bar" contenteditable="true">Introduction</div>',
|
| 340 |
+
sec,
|
| 341 |
+
count=1,
|
| 342 |
+
flags=re.DOTALL
|
| 343 |
+
)
|
| 344 |
+
intro_section = sec
|
| 345 |
+
else:
|
| 346 |
+
# ===== 3. 删除其余 section 标题前的数字序号 =====
|
| 347 |
+
# 例如: "2 Contextual Auction Design" -> "Contextual Auction Design"
|
| 348 |
+
new_title = re.sub(r"^\s*\d+(\.\d+)*\s*", "", original_title)
|
| 349 |
+
|
| 350 |
+
# 仅替换标题部分
|
| 351 |
+
sec = sec.replace(original_title, new_title, 1)
|
| 352 |
+
other_sections.append(sec)
|
| 353 |
+
|
| 354 |
+
# ===== 4. 重新组合内容(Introduction 在最前) =====
|
| 355 |
+
final_sections = []
|
| 356 |
+
if intro_section is not None:
|
| 357 |
+
final_sections.append(intro_section)
|
| 358 |
+
final_sections.extend(other_sections)
|
| 359 |
+
|
| 360 |
+
# ===== 5. (修改点) 只保留前 6 个 section =====
|
| 361 |
+
final_sections = final_sections[:6]
|
| 362 |
+
# ===== 5.5 清洗 section-bar:确保以字母单词开头 =====
|
| 363 |
+
cleaned_sections = []
|
| 364 |
+
|
| 365 |
+
for sec in final_sections:
|
| 366 |
+
def _clean_title(match):
|
| 367 |
+
title = match.group(1)
|
| 368 |
+
# 去掉开头所有非字母字符(直到第一个字母)
|
| 369 |
+
cleaned_title = re.sub(r"^[^A-Za-z]+", "", title)
|
| 370 |
+
return f'<div class="section-bar" contenteditable="true">{cleaned_title}</div>'
|
| 371 |
+
sec = re.sub(
|
| 372 |
+
r'<div class="section-bar" contenteditable="true">(.*?)</div>',
|
| 373 |
+
_clean_title,
|
| 374 |
+
sec,
|
| 375 |
+
count=1,
|
| 376 |
+
flags=re.DOTALL
|
| 377 |
+
)
|
| 378 |
+
cleaned_sections.append(sec)
|
| 379 |
+
|
| 380 |
+
final_sections = cleaned_sections
|
| 381 |
+
final_text = "\n\n".join(final_sections)
|
| 382 |
+
|
| 383 |
+
# ===== 6. 保存结果 =====
|
| 384 |
+
Path(modified_poster_outline_path).write_text(final_text, encoding="utf-8")
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
# ========== Build final poster HTML from outline.txt + template ==========
|
| 388 |
+
def build_poster_from_outline(
|
| 389 |
+
poster_outline_path: str,
|
| 390 |
+
poster_template_path: str,
|
| 391 |
+
poster_path: str,
|
| 392 |
+
) -> str:
|
| 393 |
+
"""
|
| 394 |
+
输入:
|
| 395 |
+
- poster_outline_path: 一个 .txt 文件路径,内容为要插入的 HTML 片段(若干 <section> ... </section> 等)
|
| 396 |
+
- poster_template_path: poster 模板路径(目录 或 具体文件)。函数会在此路径下定位 poster_template.html
|
| 397 |
+
- poster_path: 输出 HTML 保存路径(完整文件路径,如 /xxx/my_poster.html)
|
| 398 |
+
|
| 399 |
+
行为:
|
| 400 |
+
1) 定位 poster_template.html(不修改原文件)
|
| 401 |
+
2) 复制一份到 poster_path
|
| 402 |
+
3) 在复制后的 HTML 中,找到:
|
| 403 |
+
<main class="main">
|
| 404 |
+
<div class="flow" id="flow">
|
| 405 |
+
...这里...
|
| 406 |
+
</div>
|
| 407 |
+
</main>
|
| 408 |
+
并将 outline txt 的内容插入到 <div class="flow" id="flow"> 与其 </div> 之间
|
| 409 |
+
4) 做基础稳健性处理:换行规范化、缩进对齐、避免破坏标签结构
|
| 410 |
+
|
| 411 |
+
返回:
|
| 412 |
+
- poster_path(便于上层链式调用)
|
| 413 |
+
"""
|
| 414 |
+
# ---------- 基础检查 ----------
|
| 415 |
+
if not os.path.isfile(poster_outline_path):
|
| 416 |
+
raise FileNotFoundError(f"poster_outline_path not found: {poster_outline_path}")
|
| 417 |
+
|
| 418 |
+
if not poster_path.lower().endswith(".html"):
|
| 419 |
+
raise ValueError(f"poster_path must be an .html file path, got: {poster_path}")
|
| 420 |
+
|
| 421 |
+
os.makedirs(os.path.dirname(os.path.abspath(poster_path)), exist_ok=True)
|
| 422 |
+
|
| 423 |
+
# ---------- 定位模板文件 poster_template.html ----------
|
| 424 |
+
template_file = None
|
| 425 |
+
if os.path.isdir(poster_template_path):
|
| 426 |
+
candidate = os.path.join(poster_template_path, "poster_template.html")
|
| 427 |
+
if os.path.isfile(candidate):
|
| 428 |
+
template_file = candidate
|
| 429 |
+
else:
|
| 430 |
+
# 兜底:递归搜索同名文件(防止模板目录层级不固定)
|
| 431 |
+
for root, _, files in os.walk(poster_template_path):
|
| 432 |
+
if "poster_template.html" in files:
|
| 433 |
+
template_file = os.path.join(root, "poster_template.html")
|
| 434 |
+
break
|
| 435 |
+
else:
|
| 436 |
+
# poster_template_path 可能直接就是某个文件
|
| 437 |
+
if os.path.isfile(poster_template_path) and os.path.basename(poster_template_path) == "poster_template.html":
|
| 438 |
+
template_file = poster_template_path
|
| 439 |
+
elif os.path.isfile(poster_template_path):
|
| 440 |
+
# 兜底:如果用户传的是某个 html 文件,也允许用它作为模板
|
| 441 |
+
template_file = poster_template_path
|
| 442 |
+
|
| 443 |
+
if template_file is None:
|
| 444 |
+
raise FileNotFoundError(
|
| 445 |
+
f"Cannot locate poster_template.html under: {poster_template_path}"
|
| 446 |
+
)
|
| 447 |
+
|
| 448 |
+
# ---------- 读取 outline 内容,并做换行规范化 ----------
|
| 449 |
+
with open(poster_outline_path, "r", encoding="utf-8") as f:
|
| 450 |
+
outline_raw = f.read()
|
| 451 |
+
|
| 452 |
+
# 统一换行到 '\n',并去掉 BOM
|
| 453 |
+
outline_raw = outline_raw.replace("\ufeff", "").replace("\r\n", "\n").replace("\r", "\n").strip()
|
| 454 |
+
|
| 455 |
+
# 如果 outline 为空,允许插入空内容(但仍会保持结构)
|
| 456 |
+
# 给 outline 末尾补一个换行,避免与 </div> 直接黏连
|
| 457 |
+
if outline_raw:
|
| 458 |
+
outline_raw += "\n"
|
| 459 |
+
|
| 460 |
+
# ---------- 复制模板到输出路径(不修改原模板) ----------
|
| 461 |
+
shutil.copyfile(template_file, poster_path)
|
| 462 |
+
|
| 463 |
+
# ---------- 读取复制后的 html ----------
|
| 464 |
+
with open(poster_path, "r", encoding="utf-8") as f:
|
| 465 |
+
html = f.read()
|
| 466 |
+
|
| 467 |
+
html = html.replace("\ufeff", "").replace("\r\n", "\n").replace("\r", "\n")
|
| 468 |
+
|
| 469 |
+
# ---------- 在 <div class="flow" id="flow"> ... </div> 内插入 ----------
|
| 470 |
+
# 说明:
|
| 471 |
+
# - 使用非贪婪匹配,尽量锁定 main/flow 这个区域
|
| 472 |
+
# - 捕获 div 起始标签、原内部内容、div 结束标签
|
| 473 |
+
pattern = re.compile(
|
| 474 |
+
r'(<main\s+class="main"\s*>\s*'
|
| 475 |
+
r'<div\s+class="flow"\s+id="flow"\s*>\s*)'
|
| 476 |
+
r'(.*?)'
|
| 477 |
+
r'(\s*</div>\s*</main>)',
|
| 478 |
+
flags=re.DOTALL | re.IGNORECASE,
|
| 479 |
+
)
|
| 480 |
+
|
| 481 |
+
m = pattern.search(html)
|
| 482 |
+
if not m:
|
| 483 |
+
# 再做一次更宽松的匹配(只要求 flow div,不强依赖 main 结构)
|
| 484 |
+
pattern2 = re.compile(
|
| 485 |
+
r'(<div\s+class="flow"\s+id="flow"\s*>\s*)'
|
| 486 |
+
r'(.*?)'
|
| 487 |
+
r'(\s*</div>)',
|
| 488 |
+
flags=re.DOTALL | re.IGNORECASE,
|
| 489 |
+
)
|
| 490 |
+
m2 = pattern2.search(html)
|
| 491 |
+
if not m2:
|
| 492 |
+
raise ValueError(
|
| 493 |
+
'Cannot find target insertion block: <div class="flow" id="flow"> ... </div>'
|
| 494 |
+
)
|
| 495 |
+
|
| 496 |
+
prefix, _, suffix = m2.group(1), m2.group(2), m2.group(3)
|
| 497 |
+
base_indent = _infer_indent_from_prefix(prefix, html, m2.start(1))
|
| 498 |
+
outline_formatted = _indent_block(outline_raw, base_indent + " ") # 默认在 div 内再缩进 2 空格
|
| 499 |
+
new_block = prefix + "\n" + outline_formatted + suffix
|
| 500 |
+
html = html[: m2.start()] + new_block + html[m2.end():]
|
| 501 |
+
else:
|
| 502 |
+
prefix, _, suffix = m.group(1), m.group(2), m.group(3)
|
| 503 |
+
base_indent = _infer_indent_from_prefix(prefix, html, m.start(1))
|
| 504 |
+
outline_formatted = _indent_block(outline_raw, base_indent + " ")
|
| 505 |
+
new_block = prefix + "\n" + outline_formatted + suffix
|
| 506 |
+
html = html[: m.start()] + new_block + html[m.end():]
|
| 507 |
+
|
| 508 |
+
# ---------- 轻量格式稳健性:清理过多空行 ----------
|
| 509 |
+
html = _collapse_blank_lines(html)
|
| 510 |
+
|
| 511 |
+
# ---------- 写回输出 ----------
|
| 512 |
+
with open(poster_path, "w", encoding="utf-8", newline="\n") as f:
|
| 513 |
+
f.write(html)
|
| 514 |
+
|
| 515 |
+
return poster_path
|
| 516 |
+
|
| 517 |
+
|
| 518 |
+
def _infer_indent_from_prefix(prefix: str, full_html: str, prefix_start_idx: int) -> str:
|
| 519 |
+
"""
|
| 520 |
+
推断插入区域的基础缩进(用于让插入块的空格更“正确”)。
|
| 521 |
+
策略:取 prefix_start_idx 所在行的前导空白作为 base indent。
|
| 522 |
+
"""
|
| 523 |
+
line_start = full_html.rfind("\n", 0, prefix_start_idx) + 1
|
| 524 |
+
line = full_html[line_start:prefix_start_idx]
|
| 525 |
+
m = re.match(r"[ \t]*", line)
|
| 526 |
+
return m.group(0) if m else ""
|
| 527 |
+
|
| 528 |
+
|
| 529 |
+
def _indent_block(text: str, indent: str) -> str:
|
| 530 |
+
"""
|
| 531 |
+
将一段多行文本整体缩进到指定 indent。
|
| 532 |
+
- 空行保持为空行(不强塞空格),避免出现“看起来很多空格”的脏格式
|
| 533 |
+
"""
|
| 534 |
+
if not text:
|
| 535 |
+
return ""
|
| 536 |
+
lines = text.split("\n")
|
| 537 |
+
out = []
|
| 538 |
+
for ln in lines:
|
| 539 |
+
if ln.strip() == "":
|
| 540 |
+
out.append("")
|
| 541 |
+
else:
|
| 542 |
+
out.append(indent + ln)
|
| 543 |
+
return "\n".join(out) + ("\n" if not text.endswith("\n") else "")
|
| 544 |
+
|
| 545 |
+
|
| 546 |
+
def _collapse_blank_lines(html: str, max_blank: int = 2) -> str:
|
| 547 |
+
"""
|
| 548 |
+
将连续空行压缩到最多 max_blank 行,避免插入后产生大量空白。
|
| 549 |
+
"""
|
| 550 |
+
# 先把只含空白的行变成真正空行
|
| 551 |
+
html = re.sub(r"[ \t]+\n", "\n", html)
|
| 552 |
+
# 压缩空行:\n\n\n... -> 最多 max_blank+1 个 \n(表示 max_blank 个空行)
|
| 553 |
+
html = re.sub(r"\n{"+str(max_blank+2)+r",}", "\n" * (max_blank + 1), html)
|
| 554 |
+
return html
|
| 555 |
+
|
| 556 |
+
|
| 557 |
+
# ========== 修改 poster.html 中的 title 和 authors ==========
|
| 558 |
+
def modify_title_and_author(dag_path: str, poster_path: str) -> None:
|
| 559 |
+
if not os.path.exists(dag_path):
|
| 560 |
+
raise FileNotFoundError(f"dag.json not found: {dag_path}")
|
| 561 |
+
if not os.path.exists(poster_path):
|
| 562 |
+
raise FileNotFoundError(f"poster.html not found: {poster_path}")
|
| 563 |
+
|
| 564 |
+
with open(dag_path, "r", encoding="utf-8") as f:
|
| 565 |
+
dag: Dict[str, Any] = json.load(f)
|
| 566 |
+
|
| 567 |
+
nodes = dag.get("nodes")
|
| 568 |
+
if not isinstance(nodes, list) or len(nodes) == 0:
|
| 569 |
+
raise ValueError("Invalid dag.json: missing or empty 'nodes' list")
|
| 570 |
+
|
| 571 |
+
first = nodes[0]
|
| 572 |
+
if not isinstance(first, dict):
|
| 573 |
+
raise ValueError("Invalid dag.json: first node is not an object")
|
| 574 |
+
|
| 575 |
+
title = str(first.get("name", "")).strip()
|
| 576 |
+
authors = str(first.get("content", "")).strip()
|
| 577 |
+
|
| 578 |
+
if not title:
|
| 579 |
+
raise ValueError("Invalid dag.json: first node 'name' (title) is empty")
|
| 580 |
+
if not authors:
|
| 581 |
+
raise ValueError("Invalid dag.json: first node 'content' (authors) is empty")
|
| 582 |
+
|
| 583 |
+
with open(poster_path, "r", encoding="utf-8") as f:
|
| 584 |
+
html = f.read()
|
| 585 |
+
|
| 586 |
+
title_pattern = re.compile(
|
| 587 |
+
r'(<h1\s+class="title"\s*>)(.*?)(</h1\s*>)',
|
| 588 |
+
flags=re.IGNORECASE | re.DOTALL,
|
| 589 |
+
)
|
| 590 |
+
if not title_pattern.search(html):
|
| 591 |
+
raise ValueError('Cannot find <h1 class="title">...</h1> in poster.html')
|
| 592 |
+
|
| 593 |
+
html = title_pattern.sub(lambda m: m.group(1) + title + m.group(3), html, count=1)
|
| 594 |
+
|
| 595 |
+
authors_pattern = re.compile(
|
| 596 |
+
r'(<div\s+class="authors"\s*>)(.*?)(</div\s*>)',
|
| 597 |
+
flags=re.IGNORECASE | re.DOTALL,
|
| 598 |
+
)
|
| 599 |
+
if not authors_pattern.search(html):
|
| 600 |
+
raise ValueError('Cannot find <div class="authors">...</div> in poster.html')
|
| 601 |
+
|
| 602 |
+
html = authors_pattern.sub(lambda m: m.group(1) + authors + m.group(3), html, count=1)
|
| 603 |
+
|
| 604 |
+
with open(poster_path, "w", encoding="utf-8") as f:
|
| 605 |
+
f.write(html)
|
| 606 |
+
|
| 607 |
+
|
| 608 |
+
def inject_img_section_to_poster(
|
| 609 |
+
figure_path: str,
|
| 610 |
+
auto_path: str,
|
| 611 |
+
poster_path: str,
|
| 612 |
+
target_filename: str = "expore_our_work_in_detail.jpg",
|
| 613 |
+
) -> str:
|
| 614 |
+
"""
|
| 615 |
+
1) 将 figure_path 指向的图片复制到 auto_path/images/ 下(文件名固定为 target_filename)
|
| 616 |
+
2) 读取 poster_path 对应的 HTML,定位 <main class="main"> 内部的
|
| 617 |
+
<div class="flow" id="flow">(若存在),把 img-section 插入到该 flow div 的末尾,
|
| 618 |
+
从而保证新增块出现在 `</div> </main>` 的 </div>(flow 的闭合)之前。
|
| 619 |
+
若找不到 flow div,则退化为插入到 main 的末尾。
|
| 620 |
+
|
| 621 |
+
返回:写回后的 poster_path(绝对路径)
|
| 622 |
+
"""
|
| 623 |
+
auto_dir = Path(auto_path).expanduser().resolve()
|
| 624 |
+
poster_file = Path(poster_path).expanduser().resolve()
|
| 625 |
+
src_figure = Path(figure_path).expanduser().resolve()
|
| 626 |
+
|
| 627 |
+
if not src_figure.exists() or not src_figure.is_file():
|
| 628 |
+
raise FileNotFoundError(f"figure_path not found or not a file: {src_figure}")
|
| 629 |
+
if not auto_dir.exists() or not auto_dir.is_dir():
|
| 630 |
+
raise FileNotFoundError(f"auto_path not found or not a directory: {auto_dir}")
|
| 631 |
+
if not poster_file.exists() or not poster_file.is_file():
|
| 632 |
+
raise FileNotFoundError(f"poster_path not found or not a file: {poster_file}")
|
| 633 |
+
|
| 634 |
+
# 1) copy image into auto/images/
|
| 635 |
+
images_dir = auto_dir / "images"
|
| 636 |
+
images_dir.mkdir(parents=True, exist_ok=True)
|
| 637 |
+
|
| 638 |
+
dst_figure = images_dir / target_filename
|
| 639 |
+
shutil.copy2(src_figure, dst_figure)
|
| 640 |
+
|
| 641 |
+
# 2) edit poster html
|
| 642 |
+
html_text = poster_file.read_text(encoding="utf-8")
|
| 643 |
+
soup = BeautifulSoup(html_text, "html.parser")
|
| 644 |
+
|
| 645 |
+
main_tag = soup.find("main", class_="main")
|
| 646 |
+
if main_tag is None:
|
| 647 |
+
raise ValueError(f'Cannot find <main class="main"> in poster: {poster_file}')
|
| 648 |
+
|
| 649 |
+
# Prefer inserting into the flow div so the new block sits right before </div> </main>
|
| 650 |
+
flow_tag = main_tag.find("div", attrs={"class": "flow", "id": "flow"})
|
| 651 |
+
|
| 652 |
+
# Avoid duplicate insertion
|
| 653 |
+
target_src = f"images/{target_filename}"
|
| 654 |
+
existing_img = main_tag.find("img", attrs={"src": target_src})
|
| 655 |
+
if existing_img is None:
|
| 656 |
+
new_div = soup.new_tag("div", attrs={"class": "img-section"})
|
| 657 |
+
new_img = soup.new_tag(
|
| 658 |
+
"img",
|
| 659 |
+
attrs={"src": target_src, "alt": "", "class": "figure"},
|
| 660 |
+
)
|
| 661 |
+
new_div.append(new_img)
|
| 662 |
+
|
| 663 |
+
if flow_tag is not None:
|
| 664 |
+
# Insert before </div> of flow
|
| 665 |
+
flow_tag.append(new_div)
|
| 666 |
+
else:
|
| 667 |
+
# Fallback: append to main
|
| 668 |
+
main_tag.append(new_div)
|
| 669 |
+
|
| 670 |
+
# Write back
|
| 671 |
+
poster_file.write_text(str(soup), encoding="utf-8")
|
| 672 |
+
|
| 673 |
+
return str(poster_file)
|
| 674 |
+
|
| 675 |
+
|
| 676 |
+
# =================================优化逻辑性==================================
|
| 677 |
+
def _parse_sections(html_text: str) -> List[dict]:
|
| 678 |
+
"""
|
| 679 |
+
解析每个 <section class="section"> ... </section> 块,提取:
|
| 680 |
+
- section_block: 原始块文本
|
| 681 |
+
- title: section-bar 内标题
|
| 682 |
+
- first_p_inner: 第一个 <p>...</p> 的 inner 文本(可为空)
|
| 683 |
+
- p_span: 第一个 <p>...</p> 的 (start,end) 在 section_block 内的 span(包含<p>..</p>)
|
| 684 |
+
"""
|
| 685 |
+
section_pat = re.compile(
|
| 686 |
+
r'(<section\s+class="section"\s*>.*?</section>)',
|
| 687 |
+
re.DOTALL | re.IGNORECASE,
|
| 688 |
+
)
|
| 689 |
+
sections = []
|
| 690 |
+
for m in section_pat.finditer(html_text):
|
| 691 |
+
block = m.group(1)
|
| 692 |
+
|
| 693 |
+
# 标题
|
| 694 |
+
title_m = re.search(
|
| 695 |
+
r'<div\s+class="section-bar"[^>]*>(.*?)</div>',
|
| 696 |
+
block,
|
| 697 |
+
re.DOTALL | re.IGNORECASE,
|
| 698 |
+
)
|
| 699 |
+
title = title_m.group(1).strip() if title_m else ""
|
| 700 |
+
|
| 701 |
+
# 只处理第一个 <p>...</p>
|
| 702 |
+
p_m = re.search(r'(<p\b[^>]*>)(.*?)(</p>)', block, re.DOTALL | re.IGNORECASE)
|
| 703 |
+
if p_m:
|
| 704 |
+
p_open, p_inner, p_close = p_m.group(1), p_m.group(2), p_m.group(3)
|
| 705 |
+
p_span = (p_m.start(0), p_m.end(0))
|
| 706 |
+
first_p_inner = p_inner
|
| 707 |
+
else:
|
| 708 |
+
p_span = None
|
| 709 |
+
first_p_inner = ""
|
| 710 |
+
|
| 711 |
+
sections.append(
|
| 712 |
+
{
|
| 713 |
+
"section_block": block,
|
| 714 |
+
"title": title,
|
| 715 |
+
"first_p_inner": first_p_inner,
|
| 716 |
+
"p_span": p_span,
|
| 717 |
+
"match_span_in_full": (m.start(1), m.end(1)), # span in full html_text
|
| 718 |
+
}
|
| 719 |
+
)
|
| 720 |
+
return sections
|
| 721 |
+
|
| 722 |
+
|
| 723 |
+
def _extract_json_array(text: str) -> List[str]:
|
| 724 |
+
"""
|
| 725 |
+
从模型输出中提取 JSON 数组(允许模型带少量前后缀文本,但最终必须能抽到一个 [...])。
|
| 726 |
+
"""
|
| 727 |
+
text = text.strip()
|
| 728 |
+
# 直接就是JSON数组
|
| 729 |
+
if text.startswith("["):
|
| 730 |
+
try:
|
| 731 |
+
arr = json.loads(text)
|
| 732 |
+
if isinstance(arr, list) and all(isinstance(x, str) for x in arr):
|
| 733 |
+
return arr
|
| 734 |
+
except Exception:
|
| 735 |
+
pass
|
| 736 |
+
|
| 737 |
+
# 尝试抽取第一个 [...] 段
|
| 738 |
+
m = re.search(r"\[[\s\S]*\]", text)
|
| 739 |
+
if not m:
|
| 740 |
+
raise ValueError("LLM output does not contain a JSON array.")
|
| 741 |
+
arr_str = m.group(0)
|
| 742 |
+
arr = json.loads(arr_str)
|
| 743 |
+
if not (isinstance(arr, list) and all(isinstance(x, str) for x in arr)):
|
| 744 |
+
raise ValueError("Extracted JSON is not a list of strings.")
|
| 745 |
+
return arr
|
| 746 |
+
|
| 747 |
+
def modified_poster_logic(
|
| 748 |
+
poster_outline_path_modified: str,
|
| 749 |
+
modified_poster_logic_prompt: str,
|
| 750 |
+
model: Optional[str] = None,
|
| 751 |
+
temperature: float = 0.2,
|
| 752 |
+
config: dict = None
|
| 753 |
+
) -> str:
|
| 754 |
+
"""
|
| 755 |
+
读取 poster_outline_path_modified(txt) 的 HTML-like 内容;
|
| 756 |
+
把全文发给 LLM,让其“只输出”从第一个到倒数第二个小节需要追加的衔接句(JSON 数组,顺序一致);
|
| 757 |
+
然后将这些衔接句依次追加到每个小节的第一个 <p>...</p> 的末尾(在 </p> 前),不改变任何原格式/内容;
|
| 758 |
+
最后覆盖写回原 txt,并返回该 txt 的绝对路径。
|
| 759 |
+
"""
|
| 760 |
+
txt_path = Path(poster_outline_path_modified).expanduser().resolve()
|
| 761 |
+
if not txt_path.exists() or not txt_path.is_file():
|
| 762 |
+
raise FileNotFoundError(f"txt not found: {txt_path}")
|
| 763 |
+
|
| 764 |
+
html_text = txt_path.read_text(encoding="utf-8")
|
| 765 |
+
|
| 766 |
+
# 注意:_parse_sections 和 _extract_json_array 需在上下文环境中定义
|
| 767 |
+
sections = _parse_sections(html_text)
|
| 768 |
+
if len(sections) < 2:
|
| 769 |
+
return str(txt_path)
|
| 770 |
+
|
| 771 |
+
# 需要加衔接句的小节数量:从第1到倒数第2 => len(sections)-1
|
| 772 |
+
expected_n = len(sections) - 1
|
| 773 |
+
|
| 774 |
+
# 确定模型名称
|
| 775 |
+
model_name = model or os.getenv("OPENAI_MODEL") or "gpt-4o"
|
| 776 |
+
is_gemini = "gemini" in model_name.lower()
|
| 777 |
+
|
| 778 |
+
# 获取 API 配置
|
| 779 |
+
api_keys_config = config.get("api_keys", {}) if config else {}
|
| 780 |
+
|
| 781 |
+
out_text = ""
|
| 782 |
+
|
| 783 |
+
if is_gemini:
|
| 784 |
+
# --- Gemini Client Setup ---
|
| 785 |
+
api_key = api_keys_config.get("gemini_api_key") or os.getenv("GOOGLE_API_KEY")
|
| 786 |
+
|
| 787 |
+
client = genai.Client(api_key=api_key)
|
| 788 |
+
|
| 789 |
+
# Call Gemini
|
| 790 |
+
# 将 system prompt 放入配置中,user content 放入 contents
|
| 791 |
+
resp = client.models.generate_content(
|
| 792 |
+
model=model_name,
|
| 793 |
+
contents=html_text,
|
| 794 |
+
config={
|
| 795 |
+
"system_instruction": modified_poster_logic_prompt,
|
| 796 |
+
"temperature": temperature,
|
| 797 |
+
}
|
| 798 |
+
)
|
| 799 |
+
if not resp.text:
|
| 800 |
+
raise RuntimeError("Gemini returned empty text.")
|
| 801 |
+
out_text = resp.text
|
| 802 |
+
|
| 803 |
+
else:
|
| 804 |
+
# --- OpenAI Client Setup ---
|
| 805 |
+
api_key = api_keys_config.get("openai_api_key") or os.getenv("OPENAI_API_KEY")
|
| 806 |
+
|
| 807 |
+
client = OpenAI(api_key=api_key)
|
| 808 |
+
|
| 809 |
+
# Call OpenAI
|
| 810 |
+
messages = [
|
| 811 |
+
{"role": "system", "content": modified_poster_logic_prompt},
|
| 812 |
+
{"role": "user", "content": html_text},
|
| 813 |
+
]
|
| 814 |
+
resp = client.chat.completions.create(
|
| 815 |
+
model=model_name,
|
| 816 |
+
messages=messages,
|
| 817 |
+
temperature=temperature,
|
| 818 |
+
)
|
| 819 |
+
out_text = resp.choices[0].message.content or ""
|
| 820 |
+
|
| 821 |
+
# 解析返回的 JSON
|
| 822 |
+
transitions = _extract_json_array(out_text)
|
| 823 |
+
|
| 824 |
+
if len(transitions) != expected_n:
|
| 825 |
+
# 容错:如果 LLM 偶尔多生成或少生成,可根据实际情况决定是报错还是截断/填充
|
| 826 |
+
# 这里保持原逻辑报错
|
| 827 |
+
raise ValueError(
|
| 828 |
+
f"Transition count mismatch: expected {expected_n}, got {len(transitions)}"
|
| 829 |
+
)
|
| 830 |
+
|
| 831 |
+
# 逐个 section 进行插入:只改 <p>...</p> inner 的末尾(</p> 前)
|
| 832 |
+
new_html_parts = []
|
| 833 |
+
cursor = 0
|
| 834 |
+
|
| 835 |
+
for i, sec in enumerate(sections):
|
| 836 |
+
full_start, full_end = sec["match_span_in_full"]
|
| 837 |
+
# 先拼接 section 之前的内容(保持原样)
|
| 838 |
+
new_html_parts.append(html_text[cursor:full_start])
|
| 839 |
+
|
| 840 |
+
block = sec["section_block"]
|
| 841 |
+
p_span = sec["p_span"]
|
| 842 |
+
|
| 843 |
+
if i <= len(sections) - 2: # 第1到倒数第2个 section
|
| 844 |
+
trans = transitions[i].strip()
|
| 845 |
+
if trans and p_span:
|
| 846 |
+
# 在该 section 的第一个 </p> 前插入
|
| 847 |
+
p_start, p_end = p_span
|
| 848 |
+
p_block = block[p_start:p_end]
|
| 849 |
+
|
| 850 |
+
close_idx = p_block.lower().rfind("</p>")
|
| 851 |
+
if close_idx == -1:
|
| 852 |
+
new_block = block
|
| 853 |
+
else:
|
| 854 |
+
insert = (" " + trans) if not p_block[:close_idx].endswith((" ", "\n", "\t")) else trans
|
| 855 |
+
new_p_block = p_block[:close_idx] + insert + p_block[close_idx:]
|
| 856 |
+
new_block = block[:p_start] + new_p_block + block[p_end:]
|
| 857 |
+
else:
|
| 858 |
+
new_block = block
|
| 859 |
+
else:
|
| 860 |
+
# 最后一个 section 不加衔接句
|
| 861 |
+
new_block = block
|
| 862 |
+
|
| 863 |
+
new_html_parts.append(new_block)
|
| 864 |
+
cursor = full_end
|
| 865 |
+
|
| 866 |
+
# 追加尾部
|
| 867 |
+
new_html_parts.append(html_text[cursor:])
|
| 868 |
+
new_html_text = "".join(new_html_parts)
|
| 869 |
+
|
| 870 |
+
txt_path.write_text(new_html_text, encoding="utf-8")
|
| 871 |
+
return str(txt_path)
|
src/DAG2ppt.py
ADDED
|
@@ -0,0 +1,773 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import os
|
| 3 |
+
import re
|
| 4 |
+
from typing import Optional
|
| 5 |
+
from openai import OpenAI
|
| 6 |
+
from google import genai
|
| 7 |
+
from typing import Any, Dict, List, Optional, Union
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
# ========== 生成selected_nodes.json ==========
|
| 11 |
+
def generate_selected_nodes(dag_json_path, max_len, output_path='selected_node.json'):
|
| 12 |
+
|
| 13 |
+
# 1. 读取 dag.json
|
| 14 |
+
with open(dag_json_path, 'r', encoding='utf-8') as f:
|
| 15 |
+
dag_data = json.load(f)
|
| 16 |
+
|
| 17 |
+
all_nodes = dag_data.get('nodes', [])
|
| 18 |
+
|
| 19 |
+
# 2. 构建辅助字典,方便通过 name 快速查找节点信息
|
| 20 |
+
# 同时区分普通节点和视觉节点
|
| 21 |
+
node_map = {node['name']: node for node in all_nodes}
|
| 22 |
+
|
| 23 |
+
# 3. 初始化队列
|
| 24 |
+
# 找到根节点 (level=0)
|
| 25 |
+
root_node = next((node for node in all_nodes if node.get('level') == 0), None)
|
| 26 |
+
|
| 27 |
+
if not root_node:
|
| 28 |
+
raise ValueError("Root node (level 0) not found in dag.json")
|
| 29 |
+
|
| 30 |
+
# 获取根节点的子节点 (Sections) 作为初始队列
|
| 31 |
+
# 注意:这里队列存储的是节点的 name
|
| 32 |
+
current_queue = list(root_node.get('edge', []))
|
| 33 |
+
|
| 34 |
+
# 初始化计数器
|
| 35 |
+
node_num = len(current_queue)
|
| 36 |
+
level_num = 1
|
| 37 |
+
|
| 38 |
+
# 4. 循环处理队列,直到 level_num 达到 5
|
| 39 |
+
while level_num < 5:
|
| 40 |
+
i = 0
|
| 41 |
+
while i < len(current_queue):
|
| 42 |
+
node_name = current_queue[i]
|
| 43 |
+
node_info = node_map.get(node_name)
|
| 44 |
+
|
| 45 |
+
if not node_info:
|
| 46 |
+
# 异常情况:队列里的节点在map里找不到
|
| 47 |
+
i += 1
|
| 48 |
+
continue
|
| 49 |
+
|
| 50 |
+
# ===== 新增逻辑:如果结点 name 含有 "introduction"/"INTRODUCTION",则跳过该结点 =====
|
| 51 |
+
# 注意:不修改其他逻辑,仅在处理该结点时直接跳过
|
| 52 |
+
if "introduction" in node_name.lower():
|
| 53 |
+
i += 1
|
| 54 |
+
continue
|
| 55 |
+
|
| 56 |
+
# 这里的 level 属性可能缺失,默认给个非当前level的值
|
| 57 |
+
current_node_level = node_info.get('level', -1)
|
| 58 |
+
|
| 59 |
+
# 判断这个结点的level是否等于level_num
|
| 60 |
+
if current_node_level != level_num:
|
| 61 |
+
i += 1
|
| 62 |
+
continue
|
| 63 |
+
|
| 64 |
+
# 获取子节点
|
| 65 |
+
children_names = node_info.get('edge', [])
|
| 66 |
+
num_children = len(children_names)
|
| 67 |
+
|
| 68 |
+
if num_children == 0:
|
| 69 |
+
# 没有子节点,无法展开
|
| 70 |
+
i += 1
|
| 71 |
+
continue
|
| 72 |
+
|
| 73 |
+
potential_total_num = len(current_queue) + num_children
|
| 74 |
+
if len(current_queue) + num_children <= max_len:
|
| 75 |
+
# 执行展开操作
|
| 76 |
+
current_queue[i:i+1] = children_names
|
| 77 |
+
else:
|
| 78 |
+
# 大于 max_num,不展开,处理下一个
|
| 79 |
+
i += 1
|
| 80 |
+
|
| 81 |
+
# 当处理完当前队列的最后一个结点时,level+1
|
| 82 |
+
level_num += 1
|
| 83 |
+
|
| 84 |
+
# 5. 生成最终结果
|
| 85 |
+
final_nodes_list = []
|
| 86 |
+
|
| 87 |
+
for node_name in current_queue:
|
| 88 |
+
original_node = node_map.get(node_name)
|
| 89 |
+
if not original_node:
|
| 90 |
+
continue
|
| 91 |
+
|
| 92 |
+
# 深拷贝以避免修改原始数据(也可以直接构建新字典)
|
| 93 |
+
# 这里为了安全起见构建新字典
|
| 94 |
+
export_node = original_node.copy()
|
| 95 |
+
|
| 96 |
+
original_visual_list = export_node.get('visual_node', [])
|
| 97 |
+
|
| 98 |
+
# 某些节点可能 visual_node 字段是空的或者不存在
|
| 99 |
+
if original_visual_list:
|
| 100 |
+
expanded_visual_nodes = []
|
| 101 |
+
|
| 102 |
+
# 确保它是列表,有些脏数据可能不是列表
|
| 103 |
+
if isinstance(original_visual_list, list):
|
| 104 |
+
for v_name in original_visual_list:
|
| 105 |
+
# 根据 name 查找视觉节点详细信息
|
| 106 |
+
v_node_full = node_map.get(v_name)
|
| 107 |
+
if v_node_full:
|
| 108 |
+
expanded_visual_nodes.append(v_node_full)
|
| 109 |
+
else:
|
| 110 |
+
# 如果找不到,保留原名或者忽略,这里选择保留原结构提醒缺失
|
| 111 |
+
expanded_visual_nodes.append({"name": v_name, "error": "Node not found"})
|
| 112 |
+
|
| 113 |
+
# 替换原有属性
|
| 114 |
+
export_node['visual_node'] = expanded_visual_nodes
|
| 115 |
+
|
| 116 |
+
final_nodes_list.append(export_node)
|
| 117 |
+
|
| 118 |
+
# 6. 写入文件
|
| 119 |
+
output_data = {"selected_nodes": final_nodes_list}
|
| 120 |
+
|
| 121 |
+
with open(output_path, 'w', encoding='utf-8') as f:
|
| 122 |
+
json.dump(final_nodes_list, f, ensure_ascii=False, indent=4)
|
| 123 |
+
|
| 124 |
+
print(f"Successfully generated {output_path} with {len(final_nodes_list)} nodes.")
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
# ========== 初始化outline ==========
|
| 130 |
+
import os
|
| 131 |
+
import json
|
| 132 |
+
from openai import OpenAI
|
| 133 |
+
from google import genai
|
| 134 |
+
from google.genai import types
|
| 135 |
+
|
| 136 |
+
def outline_initialize(dag_json_path, outline_initialize_prompt, model, config):
|
| 137 |
+
"""
|
| 138 |
+
使用 LLM 初始化 outline.json(仅创建两个节点:Title + Contents)
|
| 139 |
+
适配 OpenAI 和 Google Gemini (新版 google-genai SDK)
|
| 140 |
+
|
| 141 |
+
输入:
|
| 142 |
+
dag_json_path: dag.json 文件路径
|
| 143 |
+
outline_initialize_prompt: 传给 LLM 的 prompt(字符串)
|
| 144 |
+
model: 模型名称 (例如 "gpt-4o" 或 "gemini-2.0-flash")
|
| 145 |
+
config: 配置字典,需包含 ['api_keys']['gemini_api_key']
|
| 146 |
+
|
| 147 |
+
输出:
|
| 148 |
+
outline.json: 保存在 dag.json 同目录
|
| 149 |
+
返回 python list(outline 结构)
|
| 150 |
+
"""
|
| 151 |
+
|
| 152 |
+
# --- load dag.json ---
|
| 153 |
+
if not os.path.exists(dag_json_path):
|
| 154 |
+
raise FileNotFoundError(f"dag.json not found: {dag_json_path}")
|
| 155 |
+
|
| 156 |
+
with open(dag_json_path, "r", encoding="utf-8") as f:
|
| 157 |
+
dag_data = json.load(f)
|
| 158 |
+
|
| 159 |
+
# --- extract first node ---
|
| 160 |
+
if isinstance(dag_data, list):
|
| 161 |
+
first_node = dag_data[0]
|
| 162 |
+
elif isinstance(dag_data, dict) and "nodes" in dag_data:
|
| 163 |
+
first_node = dag_data["nodes"][0]
|
| 164 |
+
else:
|
| 165 |
+
raise ValueError("Unsupported dag.json format")
|
| 166 |
+
|
| 167 |
+
first_node_text = json.dumps(first_node, ensure_ascii=False, indent=2)
|
| 168 |
+
|
| 169 |
+
# 系统提示词
|
| 170 |
+
system_prompt = "You are an expert academic presentation outline generator."
|
| 171 |
+
|
| 172 |
+
raw_output = ""
|
| 173 |
+
|
| 174 |
+
# --- LLM Call Switch ---
|
| 175 |
+
# 简单的判别逻辑:如果模型名包含 "gemini" 则调用 Google SDK,否则默认为 OpenAI 兼容 SDK
|
| 176 |
+
if "gemini" in model.lower():
|
| 177 |
+
# --- Gemini Call (google-genai SDK) ---
|
| 178 |
+
api_key = config['api_keys'].get('gemini_api_key')
|
| 179 |
+
|
| 180 |
+
# 配置 Client
|
| 181 |
+
client = genai.Client(api_key=api_key)
|
| 182 |
+
|
| 183 |
+
# 构造 user 消息内容
|
| 184 |
+
user_content = f"{outline_initialize_prompt}\n\nData Context:\n{first_node_text}"
|
| 185 |
+
|
| 186 |
+
try:
|
| 187 |
+
response = client.models.generate_content(
|
| 188 |
+
model=model,
|
| 189 |
+
contents=user_content,
|
| 190 |
+
config=types.GenerateContentConfig(
|
| 191 |
+
system_instruction=system_prompt,
|
| 192 |
+
temperature=0.0,
|
| 193 |
+
response_mime_type="application/json" # 强制 Gemini 输出 JSON,提高稳定性
|
| 194 |
+
)
|
| 195 |
+
)
|
| 196 |
+
raw_output = response.text
|
| 197 |
+
except Exception as e:
|
| 198 |
+
raise RuntimeError(f"Gemini API call failed: {str(e)}")
|
| 199 |
+
|
| 200 |
+
else:
|
| 201 |
+
# --- OpenAI Call ---
|
| 202 |
+
api_key = config['api_keys'].get('openai_api_key')
|
| 203 |
+
|
| 204 |
+
client = OpenAI(api_key=api_key)
|
| 205 |
+
|
| 206 |
+
try:
|
| 207 |
+
response = client.chat.completions.create(
|
| 208 |
+
model=model,
|
| 209 |
+
messages=[
|
| 210 |
+
{
|
| 211 |
+
"role": "system",
|
| 212 |
+
"content": system_prompt
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"role": "user",
|
| 216 |
+
"content": outline_initialize_prompt
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
"role": "user",
|
| 220 |
+
"content": first_node_text
|
| 221 |
+
}
|
| 222 |
+
],
|
| 223 |
+
temperature=0
|
| 224 |
+
)
|
| 225 |
+
raw_output = response.choices[0].message.content.strip()
|
| 226 |
+
except Exception as e:
|
| 227 |
+
raise RuntimeError(f"OpenAI API call failed: {str(e)}")
|
| 228 |
+
|
| 229 |
+
# --- Extract JSON (Generic cleaning logic) ---
|
| 230 |
+
cleaned = raw_output.strip()
|
| 231 |
+
|
| 232 |
+
# Remove ```json ... ``` markdown fences
|
| 233 |
+
if cleaned.startswith("```"):
|
| 234 |
+
cleaned = cleaned.strip("`")
|
| 235 |
+
if cleaned.lstrip().startswith("json"):
|
| 236 |
+
cleaned = cleaned.split("\n", 1)[1]
|
| 237 |
+
|
| 238 |
+
# Robustness: locate JSON block via first [ and last ]
|
| 239 |
+
try:
|
| 240 |
+
first = cleaned.index("[")
|
| 241 |
+
last = cleaned.rindex("]")
|
| 242 |
+
cleaned = cleaned[first:last + 1]
|
| 243 |
+
except ValueError:
|
| 244 |
+
pass # Try parsing the whole string if brackets aren't found cleanly
|
| 245 |
+
|
| 246 |
+
try:
|
| 247 |
+
outline_data = json.loads(cleaned)
|
| 248 |
+
except json.JSONDecodeError:
|
| 249 |
+
raise ValueError(f"LLM output is not valid JSON:\nRaw Output: {raw_output}")
|
| 250 |
+
|
| 251 |
+
# --- Save outline.json ---
|
| 252 |
+
out_dir = os.path.dirname(dag_json_path)
|
| 253 |
+
out_path = os.path.join(out_dir, "outline.json")
|
| 254 |
+
|
| 255 |
+
with open(out_path, "w", encoding="utf-8") as f:
|
| 256 |
+
json.dump(outline_data, f, indent=4, ensure_ascii=False)
|
| 257 |
+
|
| 258 |
+
print(f"✅ Outline saved to: {out_path} (Model: {model})")
|
| 259 |
+
|
| 260 |
+
return outline_data
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
# ========== 调用 gpt 生成完整 outline ==========
|
| 264 |
+
def generate_complete_outline(
|
| 265 |
+
selected_node_path,
|
| 266 |
+
outline_path,
|
| 267 |
+
generate_complete_outline_prompt,
|
| 268 |
+
model,
|
| 269 |
+
config
|
| 270 |
+
):
|
| 271 |
+
"""
|
| 272 |
+
逐个 selected_node 调用 LLM,生成 outline 节点并追加到 outline.json
|
| 273 |
+
适配 OpenAI 和 Google Gemini (新版 google-genai SDK)
|
| 274 |
+
|
| 275 |
+
输入:
|
| 276 |
+
selected_node_path: selected_node.json 路径
|
| 277 |
+
outline_path: outline.json 路径
|
| 278 |
+
generate_complete_outline_prompt: 给 LLM 的 prompt(字符串)
|
| 279 |
+
model: 模型名称 (例如 "gpt-4o" 或 "gemini-2.0-flash")
|
| 280 |
+
config: 配置字典
|
| 281 |
+
|
| 282 |
+
输出:
|
| 283 |
+
更新后的 outline.json
|
| 284 |
+
返回 outline(list)
|
| 285 |
+
"""
|
| 286 |
+
|
| 287 |
+
# --- load selected_node.json ---
|
| 288 |
+
if not os.path.exists(selected_node_path):
|
| 289 |
+
raise FileNotFoundError(f"selected_node.json not found: {selected_node_path}")
|
| 290 |
+
|
| 291 |
+
with open(selected_node_path, "r", encoding="utf-8") as f:
|
| 292 |
+
selected_nodes = json.load(f)
|
| 293 |
+
|
| 294 |
+
if not isinstance(selected_nodes, list):
|
| 295 |
+
raise ValueError("selected_node.json must be a list")
|
| 296 |
+
|
| 297 |
+
# --- load outline.json ---
|
| 298 |
+
if not os.path.exists(outline_path):
|
| 299 |
+
raise FileNotFoundError(f"outline.json not found: {outline_path}")
|
| 300 |
+
|
| 301 |
+
with open(outline_path, "r", encoding="utf-8") as f:
|
| 302 |
+
outline_data = json.load(f)
|
| 303 |
+
|
| 304 |
+
if not isinstance(outline_data, list):
|
| 305 |
+
raise ValueError("outline.json must be a list")
|
| 306 |
+
|
| 307 |
+
# --- Initialize Client based on model ---
|
| 308 |
+
is_gemini = "gemini" in model.lower()
|
| 309 |
+
client = None
|
| 310 |
+
system_prompt = "You are an expert academic presentation outline generator."
|
| 311 |
+
|
| 312 |
+
if is_gemini:
|
| 313 |
+
api_key = config['api_keys'].get('gemini_api_key')
|
| 314 |
+
|
| 315 |
+
client = genai.Client(api_key=api_key)
|
| 316 |
+
else:
|
| 317 |
+
api_key = config['api_keys'].get('openai_api_key')
|
| 318 |
+
client = OpenAI(api_key=api_key)
|
| 319 |
+
|
| 320 |
+
# --- iterate selected nodes ---
|
| 321 |
+
for idx, node in enumerate(selected_nodes):
|
| 322 |
+
|
| 323 |
+
payload = {
|
| 324 |
+
"name": node.get("name"),
|
| 325 |
+
"content": node.get("content"),
|
| 326 |
+
"visual_node": node.get("visual_node", [])
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
payload_text = json.dumps(payload, ensure_ascii=False, indent=2)
|
| 330 |
+
raw_output = ""
|
| 331 |
+
|
| 332 |
+
try:
|
| 333 |
+
if is_gemini:
|
| 334 |
+
# --- Gemini Call ---
|
| 335 |
+
user_content = f"{generate_complete_outline_prompt}\n\nNode Data:\n{payload_text}"
|
| 336 |
+
response = client.models.generate_content(
|
| 337 |
+
model=model,
|
| 338 |
+
contents=user_content,
|
| 339 |
+
config=types.GenerateContentConfig(
|
| 340 |
+
system_instruction=system_prompt,
|
| 341 |
+
temperature=0.0,
|
| 342 |
+
response_mime_type="application/json"
|
| 343 |
+
)
|
| 344 |
+
)
|
| 345 |
+
raw_output = response.text
|
| 346 |
+
else:
|
| 347 |
+
# --- OpenAI Call ---
|
| 348 |
+
response = client.chat.completions.create(
|
| 349 |
+
model=model,
|
| 350 |
+
messages=[
|
| 351 |
+
{
|
| 352 |
+
"role": "system",
|
| 353 |
+
"content": system_prompt
|
| 354 |
+
},
|
| 355 |
+
{
|
| 356 |
+
"role": "user",
|
| 357 |
+
"content": generate_complete_outline_prompt
|
| 358 |
+
},
|
| 359 |
+
{
|
| 360 |
+
"role": "user",
|
| 361 |
+
"content": payload_text
|
| 362 |
+
}
|
| 363 |
+
],
|
| 364 |
+
temperature=0
|
| 365 |
+
)
|
| 366 |
+
raw_output = response.choices[0].message.content.strip()
|
| 367 |
+
|
| 368 |
+
except Exception as e:
|
| 369 |
+
print(f"⚠️ Error processing node {idx} ({node.get('name')}): {e}")
|
| 370 |
+
continue # Skip this node or handle error as needed
|
| 371 |
+
|
| 372 |
+
# --- clean JSON ---
|
| 373 |
+
cleaned = raw_output.strip()
|
| 374 |
+
|
| 375 |
+
if cleaned.startswith("```"):
|
| 376 |
+
cleaned = cleaned.strip("`")
|
| 377 |
+
if cleaned.lstrip().startswith("json"):
|
| 378 |
+
cleaned = cleaned.split("\n", 1)[1]
|
| 379 |
+
|
| 380 |
+
try:
|
| 381 |
+
first = cleaned.index("{")
|
| 382 |
+
last = cleaned.rindex("}")
|
| 383 |
+
cleaned = cleaned[first:last + 1]
|
| 384 |
+
except Exception:
|
| 385 |
+
pass
|
| 386 |
+
|
| 387 |
+
try:
|
| 388 |
+
outline_node = json.loads(cleaned)
|
| 389 |
+
except json.JSONDecodeError:
|
| 390 |
+
# print error but maybe continue? strict raise for now
|
| 391 |
+
raise ValueError(
|
| 392 |
+
f"LLM output is not valid JSON for selected_node index {idx}:\n{raw_output}"
|
| 393 |
+
)
|
| 394 |
+
|
| 395 |
+
# --- append to outline ---
|
| 396 |
+
outline_data.append(outline_node)
|
| 397 |
+
|
| 398 |
+
# --- save outline.json ---
|
| 399 |
+
with open(outline_path, "w", encoding="utf-8") as f:
|
| 400 |
+
json.dump(outline_data, f, indent=4, ensure_ascii=False)
|
| 401 |
+
|
| 402 |
+
print(f"✅ Complete outline updated: {outline_path}")
|
| 403 |
+
|
| 404 |
+
return outline_data
|
| 405 |
+
|
| 406 |
+
|
| 407 |
+
# ========== 调用 LLM 为每一张ppt配模板 ==========
|
| 408 |
+
SlideType = Dict[str, Any]
|
| 409 |
+
OutlineType = List[SlideType]
|
| 410 |
+
JsonType = Union[Dict[str, Any], List[Any], str, int, float, bool, None]
|
| 411 |
+
|
| 412 |
+
def arrange_template(
|
| 413 |
+
outline_path: str,
|
| 414 |
+
arrange_template_prompt: str,
|
| 415 |
+
model: str,
|
| 416 |
+
config: Dict[str, Any]
|
| 417 |
+
) -> OutlineType:
|
| 418 |
+
"""
|
| 419 |
+
Read an outline.json, call LLM to choose a PPT template for slides with null template.
|
| 420 |
+
适配 OpenAI 和 Google Gemini (新版 google-genai SDK)
|
| 421 |
+
"""
|
| 422 |
+
|
| 423 |
+
# --- Client Init ---
|
| 424 |
+
is_gemini = "gemini" in model.lower()
|
| 425 |
+
client = None
|
| 426 |
+
|
| 427 |
+
if is_gemini:
|
| 428 |
+
api_key = config['api_keys'].get('gemini_api_key')
|
| 429 |
+
|
| 430 |
+
client = genai.Client(api_key=api_key)
|
| 431 |
+
else:
|
| 432 |
+
api_key = config['api_keys'].get('openai_api_key')
|
| 433 |
+
|
| 434 |
+
client = OpenAI(api_key=api_key)
|
| 435 |
+
|
| 436 |
+
# 读取 outline.json
|
| 437 |
+
with open(outline_path, "r", encoding="utf-8") as f:
|
| 438 |
+
outline: OutlineType = json.load(f)
|
| 439 |
+
|
| 440 |
+
def is_null_template(value: Any) -> bool:
|
| 441 |
+
"""
|
| 442 |
+
Treat Python None or explicit string 'NULL' / 'null' / ''
|
| 443 |
+
as empty template that needs to be filled.
|
| 444 |
+
"""
|
| 445 |
+
if value is None:
|
| 446 |
+
return True
|
| 447 |
+
if isinstance(value, str) and value.strip().lower() in {"null", ""}:
|
| 448 |
+
return True
|
| 449 |
+
return False
|
| 450 |
+
|
| 451 |
+
def select_template_for_slide(slide: SlideType, index: int) -> None:
|
| 452 |
+
"""
|
| 453 |
+
If slide['template'] is NULL/None, call LLM to select a template.
|
| 454 |
+
"""
|
| 455 |
+
if not is_null_template(slide.get("template")):
|
| 456 |
+
return # already has a template, skip
|
| 457 |
+
|
| 458 |
+
# 整个 slide 作为 JSON 发给 GPT
|
| 459 |
+
slide_json_str = json.dumps(slide, ensure_ascii=False, indent=2)
|
| 460 |
+
|
| 461 |
+
# 统计信息
|
| 462 |
+
figures = slide.get("figure", []) or []
|
| 463 |
+
formulas = slide.get("formula", []) or []
|
| 464 |
+
|
| 465 |
+
summary_info = {
|
| 466 |
+
"slide_index": index,
|
| 467 |
+
"num_figures": len(figures),
|
| 468 |
+
"num_formulas": len(formulas),
|
| 469 |
+
}
|
| 470 |
+
summary_json_str = json.dumps(summary_info, ensure_ascii=False, indent=2)
|
| 471 |
+
|
| 472 |
+
# 构造 User Content
|
| 473 |
+
user_content = (
|
| 474 |
+
"Below is one slide node from outline.json.\n"
|
| 475 |
+
"First, read the raw slide JSON.\n"
|
| 476 |
+
"Then, use the template selection rules in the system message to choose "
|
| 477 |
+
"exactly one template for this slide.\n\n"
|
| 478 |
+
"A small auto-generated summary is also provided to help you:\n"
|
| 479 |
+
f"Summary:\n```json\n{summary_json_str}\n```\n\n"
|
| 480 |
+
"Full slide node (JSON):\n```json\n"
|
| 481 |
+
+ slide_json_str
|
| 482 |
+
+ "\n```"
|
| 483 |
+
)
|
| 484 |
+
|
| 485 |
+
content = ""
|
| 486 |
+
|
| 487 |
+
try:
|
| 488 |
+
if is_gemini:
|
| 489 |
+
# --- Gemini Call ---
|
| 490 |
+
response = client.models.generate_content(
|
| 491 |
+
model=model,
|
| 492 |
+
contents=user_content,
|
| 493 |
+
config=types.GenerateContentConfig(
|
| 494 |
+
system_instruction=arrange_template_prompt,
|
| 495 |
+
temperature=0.0,
|
| 496 |
+
response_mime_type="application/json"
|
| 497 |
+
)
|
| 498 |
+
)
|
| 499 |
+
content = response.text
|
| 500 |
+
else:
|
| 501 |
+
# --- OpenAI Call ---
|
| 502 |
+
messages = [
|
| 503 |
+
{
|
| 504 |
+
"role": "system",
|
| 505 |
+
"content": arrange_template_prompt,
|
| 506 |
+
},
|
| 507 |
+
{
|
| 508 |
+
"role": "user",
|
| 509 |
+
"content": user_content,
|
| 510 |
+
},
|
| 511 |
+
]
|
| 512 |
+
response = client.chat.completions.create(
|
| 513 |
+
model=model,
|
| 514 |
+
messages=messages,
|
| 515 |
+
temperature=0.0,
|
| 516 |
+
)
|
| 517 |
+
content = (response.choices[0].message.content or "").strip()
|
| 518 |
+
|
| 519 |
+
except Exception as e:
|
| 520 |
+
print(f"[WARN] Failed to call LLM for slide {index}: {e}")
|
| 521 |
+
return
|
| 522 |
+
|
| 523 |
+
# 期望 GPT 返回 JSON:{"template": "T2_ImageRight.html"}
|
| 524 |
+
template_name: Union[str, None] = None
|
| 525 |
+
|
| 526 |
+
# 1) 尝试直接解析为 JSON
|
| 527 |
+
try:
|
| 528 |
+
# 去掉可能的代码块包装 ```json ... ```
|
| 529 |
+
content_for_json = content
|
| 530 |
+
if "```" in content:
|
| 531 |
+
parts = content.split("```")
|
| 532 |
+
# 寻找包含 json 的部分或直接取第二部分
|
| 533 |
+
if len(parts) > 1:
|
| 534 |
+
candidate = parts[1]
|
| 535 |
+
if candidate.lstrip().startswith("json"):
|
| 536 |
+
candidate = candidate.split("\n", 1)[-1]
|
| 537 |
+
content_for_json = candidate
|
| 538 |
+
|
| 539 |
+
parsed = json.loads(content_for_json)
|
| 540 |
+
|
| 541 |
+
if isinstance(parsed, dict) and "template" in parsed:
|
| 542 |
+
template_name = parsed["template"]
|
| 543 |
+
elif isinstance(parsed, str):
|
| 544 |
+
template_name = parsed
|
| 545 |
+
except Exception:
|
| 546 |
+
# 2) 如果 JSON 解析失败,当作纯文本处理
|
| 547 |
+
cleaned = content.strip()
|
| 548 |
+
if cleaned.startswith('"') and cleaned.endswith('"'):
|
| 549 |
+
cleaned = cleaned[1:-1].strip()
|
| 550 |
+
template_name = cleaned or None
|
| 551 |
+
|
| 552 |
+
if isinstance(template_name, str) and template_name:
|
| 553 |
+
slide["template"] = template_name
|
| 554 |
+
else:
|
| 555 |
+
print(
|
| 556 |
+
f"[WARN] Could not parse template from model output for slide {index}, "
|
| 557 |
+
"leaving 'template' unchanged."
|
| 558 |
+
)
|
| 559 |
+
|
| 560 |
+
# 顶层是一个列表,每个元素是一张 slide
|
| 561 |
+
if not isinstance(outline, list):
|
| 562 |
+
raise ValueError("outline.json must be a list of slide nodes at top level.")
|
| 563 |
+
|
| 564 |
+
for idx, slide in enumerate(outline):
|
| 565 |
+
if isinstance(slide, dict):
|
| 566 |
+
select_template_for_slide(slide, idx)
|
| 567 |
+
|
| 568 |
+
# 写回文件
|
| 569 |
+
with open(outline_path, "w", encoding="utf-8") as f:
|
| 570 |
+
json.dump(outline, f, ensure_ascii=False, indent=2)
|
| 571 |
+
|
| 572 |
+
return outline
|
| 573 |
+
|
| 574 |
+
|
| 575 |
+
# ========== 生成最终的PPT ==========
|
| 576 |
+
_MD_IMAGE_RE = re.compile(r"!\[\s*.*?\s*\]\(\s*([^)]+?)\s*\)")
|
| 577 |
+
def _extract_md_image_path(name_field: str) -> str:
|
| 578 |
+
"""
|
| 579 |
+
Extracts relative image path from a markdown image string like:
|
| 580 |
+
'' -> 'images/abc.jpg'
|
| 581 |
+
If not markdown format, returns the original string stripped.
|
| 582 |
+
"""
|
| 583 |
+
if not isinstance(name_field, str):
|
| 584 |
+
return ""
|
| 585 |
+
s = name_field.strip()
|
| 586 |
+
m = _MD_IMAGE_RE.search(s)
|
| 587 |
+
if m:
|
| 588 |
+
return m.group(1).strip()
|
| 589 |
+
return s
|
| 590 |
+
|
| 591 |
+
|
| 592 |
+
def _normalize_node(node: Dict[str, Any]) -> Dict[str, Any]:
|
| 593 |
+
"""
|
| 594 |
+
Normalize node fields and extract clean image paths for figure/formula name fields.
|
| 595 |
+
"""
|
| 596 |
+
text = node.get("text", "")
|
| 597 |
+
template = node.get("template", "")
|
| 598 |
+
figure = node.get("figure", []) or []
|
| 599 |
+
formula = node.get("formula", []) or []
|
| 600 |
+
|
| 601 |
+
def norm_imgs(imgs: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
| 602 |
+
out = []
|
| 603 |
+
for it in imgs:
|
| 604 |
+
if not isinstance(it, dict):
|
| 605 |
+
continue
|
| 606 |
+
name = it.get("name", "")
|
| 607 |
+
out.append({
|
| 608 |
+
"name": name,
|
| 609 |
+
"path": _extract_md_image_path(name),
|
| 610 |
+
"caption": it.get("caption", ""),
|
| 611 |
+
"resolution": it.get("resolution", "")
|
| 612 |
+
})
|
| 613 |
+
return out
|
| 614 |
+
|
| 615 |
+
return {
|
| 616 |
+
"text": text if isinstance(text, str) else str(text),
|
| 617 |
+
"template": template if isinstance(template, str) else str(template),
|
| 618 |
+
"figure": norm_imgs(figure if isinstance(figure, list) else []),
|
| 619 |
+
"formula": norm_imgs(formula if isinstance(formula, list) else [])
|
| 620 |
+
}
|
| 621 |
+
|
| 622 |
+
def generate_ppt(
|
| 623 |
+
outline_path: str,
|
| 624 |
+
ppt_template_path: str,
|
| 625 |
+
generate_ppt_with_gemini_prompt: Union[Dict[str, str], List[Dict[str, str]]],
|
| 626 |
+
model: str,
|
| 627 |
+
config: Dict[str, Any]
|
| 628 |
+
) -> List[str]:
|
| 629 |
+
"""
|
| 630 |
+
Traverse outline JSON nodes, load corresponding HTML templates, send (prompt + node + template)
|
| 631 |
+
to LLM (Gemini or OpenAI), then save revised HTML to the outline.json directory.
|
| 632 |
+
|
| 633 |
+
Args:
|
| 634 |
+
outline_path: path to outline json file.
|
| 635 |
+
ppt_template_path: folder containing html templates.
|
| 636 |
+
generate_ppt_with_gemini_prompt: JSON-like prompt (dict or list of messages).
|
| 637 |
+
model: model name (e.g., 'gemini-2.0-flash', 'gpt-4o').
|
| 638 |
+
config: config dict containing api_keys.
|
| 639 |
+
|
| 640 |
+
Returns:
|
| 641 |
+
List of saved HTML file paths (one per node).
|
| 642 |
+
"""
|
| 643 |
+
|
| 644 |
+
# --- Client Init ---
|
| 645 |
+
is_gemini = "gemini" in model.lower()
|
| 646 |
+
client = None
|
| 647 |
+
|
| 648 |
+
if is_gemini:
|
| 649 |
+
api_key = config['api_keys'].get('gemini_api_key')
|
| 650 |
+
|
| 651 |
+
client = genai.Client(api_key=api_key)
|
| 652 |
+
else:
|
| 653 |
+
api_key = config['api_keys'].get('openai_api_key')
|
| 654 |
+
|
| 655 |
+
client = OpenAI(api_key=api_key)
|
| 656 |
+
|
| 657 |
+
outline_path = os.path.abspath(outline_path)
|
| 658 |
+
ppt_template_path = os.path.abspath(ppt_template_path)
|
| 659 |
+
|
| 660 |
+
if not os.path.isfile(outline_path):
|
| 661 |
+
raise FileNotFoundError(f"outline_path 不存在或不是文件: {outline_path}")
|
| 662 |
+
if not os.path.isdir(ppt_template_path):
|
| 663 |
+
raise NotADirectoryError(f"ppt_template_path 不存在或不是文件夹: {ppt_template_path}")
|
| 664 |
+
|
| 665 |
+
with open(outline_path, "r", encoding="utf-8") as f:
|
| 666 |
+
outline = json.load(f)
|
| 667 |
+
|
| 668 |
+
if not isinstance(outline, list):
|
| 669 |
+
raise ValueError("outline_path 的 JSON 顶层必须是 list(每个元素代表一页 PPT 结点)")
|
| 670 |
+
|
| 671 |
+
out_dir = os.path.dirname(outline_path)
|
| 672 |
+
saved_files: List[str] = []
|
| 673 |
+
|
| 674 |
+
# Allow prompt to be either a single message dict or a list of messages.
|
| 675 |
+
base_messages = []
|
| 676 |
+
if isinstance(generate_ppt_with_gemini_prompt, dict):
|
| 677 |
+
base_messages = [generate_ppt_with_gemini_prompt]
|
| 678 |
+
elif isinstance(generate_ppt_with_gemini_prompt, list):
|
| 679 |
+
base_messages = generate_ppt_with_gemini_prompt
|
| 680 |
+
else:
|
| 681 |
+
raise TypeError("generate_ppt_with_gemini_prompt 必须是 dict 或 list[dict] 的 JSON 形式")
|
| 682 |
+
|
| 683 |
+
# Helper to clean node (normalize) - assuming simple dict copy if function missing
|
| 684 |
+
def _normalize_node(n): return n
|
| 685 |
+
|
| 686 |
+
for idx, node in enumerate(outline, start=1):
|
| 687 |
+
if not isinstance(node, dict):
|
| 688 |
+
continue
|
| 689 |
+
|
| 690 |
+
norm_node = _normalize_node(node)
|
| 691 |
+
template_file = norm_node.get("template", "").strip()
|
| 692 |
+
|
| 693 |
+
# Skip if no template or explicitly null/empty
|
| 694 |
+
if not template_file or template_file.lower() == "null":
|
| 695 |
+
continue
|
| 696 |
+
|
| 697 |
+
template_full_path = os.path.join(ppt_template_path, template_file)
|
| 698 |
+
if not os.path.isfile(template_full_path):
|
| 699 |
+
# raise FileNotFoundError(f"找不到模板文件: {template_full_path}")
|
| 700 |
+
print(f"⚠️ Template not found: {template_file}, skipping slide {idx}")
|
| 701 |
+
continue
|
| 702 |
+
|
| 703 |
+
with open(template_full_path, "r", encoding="utf-8") as tf:
|
| 704 |
+
template_html = tf.read()
|
| 705 |
+
|
| 706 |
+
user_payload = {
|
| 707 |
+
"ppt_index": idx,
|
| 708 |
+
"node": norm_node,
|
| 709 |
+
"template_html": template_html,
|
| 710 |
+
}
|
| 711 |
+
|
| 712 |
+
# Construct OpenAI-style messages list
|
| 713 |
+
current_messages = list(base_messages) + [
|
| 714 |
+
{
|
| 715 |
+
"role": "user",
|
| 716 |
+
"content": (
|
| 717 |
+
"Here is the slide node JSON and the HTML template. "
|
| 718 |
+
"Revise the HTML per instructions and return ONLY the final HTML code.\n"
|
| 719 |
+
"Do NOT include markdown fences like ```html ... ```.\n\n"
|
| 720 |
+
f"{json.dumps(user_payload, ensure_ascii=False)}"
|
| 721 |
+
),
|
| 722 |
+
}
|
| 723 |
+
]
|
| 724 |
+
|
| 725 |
+
revised_html = ""
|
| 726 |
+
|
| 727 |
+
try:
|
| 728 |
+
if is_gemini:
|
| 729 |
+
# --- Gemini Call ---
|
| 730 |
+
# Convert messages list to a single string prompt for Gemini
|
| 731 |
+
# (or pass list if using chat interface, but generate_content with string is often simpler for 1-turn)
|
| 732 |
+
prompt_parts = []
|
| 733 |
+
for m in current_messages:
|
| 734 |
+
prompt_parts.append(str(m.get("content", "")))
|
| 735 |
+
final_prompt = "\n\n".join(prompt_parts)
|
| 736 |
+
|
| 737 |
+
resp = client.models.generate_content(
|
| 738 |
+
model=model,
|
| 739 |
+
contents=final_prompt
|
| 740 |
+
)
|
| 741 |
+
revised_html = getattr(resp, "text", str(resp))
|
| 742 |
+
else:
|
| 743 |
+
# --- OpenAI Call ---
|
| 744 |
+
resp = client.chat.completions.create(
|
| 745 |
+
model=model,
|
| 746 |
+
messages=current_messages,
|
| 747 |
+
temperature=0.0
|
| 748 |
+
)
|
| 749 |
+
revised_html = resp.choices[0].message.content
|
| 750 |
+
|
| 751 |
+
except Exception as e:
|
| 752 |
+
print(f"⚠️ API Call failed for slide {idx}: {e}")
|
| 753 |
+
continue
|
| 754 |
+
|
| 755 |
+
# Clean output
|
| 756 |
+
if revised_html:
|
| 757 |
+
revised_html = revised_html.strip()
|
| 758 |
+
# Remove markdown fences if present
|
| 759 |
+
if revised_html.startswith("```"):
|
| 760 |
+
revised_html = revised_html.strip("`")
|
| 761 |
+
if revised_html.lstrip().startswith("html"):
|
| 762 |
+
revised_html = revised_html.split("\n", 1)[1]
|
| 763 |
+
|
| 764 |
+
# Save
|
| 765 |
+
out_name = f"{idx}_ppt.html"
|
| 766 |
+
out_path = os.path.join(out_dir, out_name)
|
| 767 |
+
with open(out_path, "w", encoding="utf-8") as wf:
|
| 768 |
+
wf.write(revised_html)
|
| 769 |
+
|
| 770 |
+
saved_files.append(out_path)
|
| 771 |
+
print(f"✅ Generated: {out_path}")
|
| 772 |
+
|
| 773 |
+
return saved_files
|
src/DAG2pr.py
ADDED
|
@@ -0,0 +1,995 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import os
|
| 3 |
+
import re
|
| 4 |
+
import time
|
| 5 |
+
import shutil
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
from typing import Optional, List, Tuple, Any, Dict
|
| 8 |
+
from google import genai
|
| 9 |
+
from google.genai import types
|
| 10 |
+
from openai import OpenAI
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
# ========== Extract basic information for PR Generation ==========
|
| 14 |
+
def extract_basic_information(
|
| 15 |
+
dag_path: str,
|
| 16 |
+
extract_basic_information_prompt: str,
|
| 17 |
+
model: str,
|
| 18 |
+
auto_path: str,
|
| 19 |
+
output_filename: str = "basic_information.txt",
|
| 20 |
+
api_key: Optional[str] = None,
|
| 21 |
+
base_url: Optional[str] = None,
|
| 22 |
+
config: dict = None
|
| 23 |
+
) -> str:
|
| 24 |
+
"""
|
| 25 |
+
读取 dag.json 的第一个 node(root),将其完整信息发给 LLM,提取并输出:
|
| 26 |
+
Title / Author / Institution / Github
|
| 27 |
+
然后把 LLM 输出写入 auto_path/basic_information.txt(不存在则创建)。
|
| 28 |
+
|
| 29 |
+
返回:写入的 txt 的绝对路径(str)
|
| 30 |
+
"""
|
| 31 |
+
dag_file = Path(dag_path).expanduser().resolve()
|
| 32 |
+
auto_dir = Path(auto_path).expanduser().resolve()
|
| 33 |
+
out_path = auto_dir / output_filename
|
| 34 |
+
|
| 35 |
+
if not dag_file.exists() or not dag_file.is_file():
|
| 36 |
+
raise FileNotFoundError(f"dag_path not found or not a file: {dag_file}")
|
| 37 |
+
|
| 38 |
+
auto_dir.mkdir(parents=True, exist_ok=True)
|
| 39 |
+
|
| 40 |
+
# 1) load dag.json
|
| 41 |
+
with dag_file.open("r", encoding="utf-8") as f:
|
| 42 |
+
dag = json.load(f)
|
| 43 |
+
|
| 44 |
+
nodes = dag.get("nodes", [])
|
| 45 |
+
if not isinstance(nodes, list) or len(nodes) == 0 or not isinstance(nodes[0], dict):
|
| 46 |
+
raise ValueError("Invalid dag.json: missing or invalid 'nodes[0]' root node.")
|
| 47 |
+
|
| 48 |
+
root_node = nodes[0]
|
| 49 |
+
|
| 50 |
+
# 2) build LLM input (send the entire root node)
|
| 51 |
+
root_payload = {
|
| 52 |
+
"name": root_node.get("name", ""),
|
| 53 |
+
"content": root_node.get("content", ""),
|
| 54 |
+
"github": root_node.get("github", ""),
|
| 55 |
+
"edge": root_node.get("edge", []),
|
| 56 |
+
"level": root_node.get("level", 0),
|
| 57 |
+
"visual_node": root_node.get("visual_node", []),
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
user_message = (
|
| 61 |
+
"ROOT_NODE_JSON:\n"
|
| 62 |
+
+ json.dumps(root_payload, ensure_ascii=False, indent=2)
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
# 3) call LLM
|
| 66 |
+
llm_text = ""
|
| 67 |
+
api_keys_config = config.get("api_keys", {}) if config else {}
|
| 68 |
+
|
| 69 |
+
# 判别平台
|
| 70 |
+
is_gemini = "gemini" in model.lower()
|
| 71 |
+
|
| 72 |
+
if is_gemini:
|
| 73 |
+
# === Gemini Client Setup ===
|
| 74 |
+
api_key = api_keys_config.get("gemini_api_key") or os.getenv("GOOGLE_API_KEY")
|
| 75 |
+
|
| 76 |
+
client = genai.Client(api_key=api_key)
|
| 77 |
+
|
| 78 |
+
# Gemini Call
|
| 79 |
+
resp = client.models.generate_content(
|
| 80 |
+
model=model,
|
| 81 |
+
contents=user_message,
|
| 82 |
+
config={
|
| 83 |
+
"system_instruction": extract_basic_information_prompt,
|
| 84 |
+
"temperature": 0,
|
| 85 |
+
}
|
| 86 |
+
)
|
| 87 |
+
if resp.text:
|
| 88 |
+
llm_text = resp.text
|
| 89 |
+
|
| 90 |
+
else:
|
| 91 |
+
# === OpenAI Client Setup ===
|
| 92 |
+
api_key = api_keys_config.get("openai_api_key") or os.getenv("OPENAI_API_KEY")
|
| 93 |
+
|
| 94 |
+
client = OpenAI(api_key=api_key)
|
| 95 |
+
|
| 96 |
+
# OpenAI Call
|
| 97 |
+
resp = client.chat.completions.create(
|
| 98 |
+
model=model,
|
| 99 |
+
messages=[
|
| 100 |
+
{"role": "system", "content": extract_basic_information_prompt},
|
| 101 |
+
{"role": "user", "content": user_message},
|
| 102 |
+
],
|
| 103 |
+
temperature=0,
|
| 104 |
+
)
|
| 105 |
+
llm_text = resp.choices[0].message.content or ""
|
| 106 |
+
|
| 107 |
+
if not llm_text:
|
| 108 |
+
raise RuntimeError("LLM returned empty content for basic information extraction.")
|
| 109 |
+
|
| 110 |
+
# 4) write to auto/basic_information.txt
|
| 111 |
+
with out_path.open("w", encoding="utf-8") as f:
|
| 112 |
+
f.write(llm_text.strip() + "\n")
|
| 113 |
+
|
| 114 |
+
return str(out_path)
|
| 115 |
+
|
| 116 |
+
def initialize_pr_markdown(
|
| 117 |
+
basic_information_path: str,
|
| 118 |
+
auto_path: str,
|
| 119 |
+
pr_template_path: str
|
| 120 |
+
) -> str:
|
| 121 |
+
"""
|
| 122 |
+
basic_information_path: txt 文件路径(包含 Title/Author/Institution/Github)
|
| 123 |
+
auto_path: 输出目录
|
| 124 |
+
pr_template_path: PR markdown 模板路径
|
| 125 |
+
输出:auto_path/markdown.md
|
| 126 |
+
"""
|
| 127 |
+
|
| 128 |
+
info_txt_path = Path(basic_information_path)
|
| 129 |
+
auto_dir = Path(auto_path)
|
| 130 |
+
template_md = Path(pr_template_path)
|
| 131 |
+
|
| 132 |
+
if not info_txt_path.exists():
|
| 133 |
+
raise FileNotFoundError(f"basic_information_path not found: {basic_information_path}")
|
| 134 |
+
if info_txt_path.suffix.lower() != ".txt":
|
| 135 |
+
raise ValueError(f"basic_information_path must be a .txt file, got: {basic_information_path}")
|
| 136 |
+
if not template_md.exists():
|
| 137 |
+
raise FileNotFoundError(f"pr_template_path not found: {pr_template_path}")
|
| 138 |
+
|
| 139 |
+
auto_dir.mkdir(parents=True, exist_ok=True)
|
| 140 |
+
|
| 141 |
+
# -------- 1) 读取并解析 txt --------
|
| 142 |
+
txt = info_txt_path.read_text(encoding="utf-8", errors="ignore")
|
| 143 |
+
|
| 144 |
+
def _extract_value(key: str) -> str:
|
| 145 |
+
pattern = re.compile(
|
| 146 |
+
rf"^\s*{re.escape(key)}\s*:\s*(.*?)\s*$",
|
| 147 |
+
re.IGNORECASE | re.MULTILINE
|
| 148 |
+
)
|
| 149 |
+
m = pattern.search(txt)
|
| 150 |
+
return m.group(1).strip() if m else ""
|
| 151 |
+
|
| 152 |
+
title = _extract_value("Title")
|
| 153 |
+
authors = _extract_value("Author") or _extract_value("Authors")
|
| 154 |
+
institution = _extract_value("Institution")
|
| 155 |
+
github = _extract_value("Github") or _extract_value("GitHub") or _extract_value("Direct Link")
|
| 156 |
+
|
| 157 |
+
# -------- 2) 复制模板到 auto_path/markdown.md --------
|
| 158 |
+
out_md_path = auto_dir / "markdown.md"
|
| 159 |
+
shutil.copyfile(template_md, out_md_path)
|
| 160 |
+
|
| 161 |
+
md = out_md_path.read_text(encoding="utf-8", errors="ignore")
|
| 162 |
+
|
| 163 |
+
# 关键:统一换行,避免 \r\n 导致整行匹配失败
|
| 164 |
+
md = md.replace("\r\n", "\n").replace("\r", "\n")
|
| 165 |
+
|
| 166 |
+
# -------- 3) 按行替换(更鲁棒)--------
|
| 167 |
+
def _fill_line_by_anchor(md_text: str, anchor_label: str, value: str) -> str:
|
| 168 |
+
"""
|
| 169 |
+
anchor_label: 例如 "Authors",用于匹配 **Authors**
|
| 170 |
+
将包含 **anchor_label** 的那一行,改写为:
|
| 171 |
+
<该行中 **anchor_label** 及其之前部分>: <value>
|
| 172 |
+
例如:
|
| 173 |
+
✍️ **Authors** -> ✍️ **Authors:** xxx
|
| 174 |
+
🏛️**Institution** -> 🏛️**Institution:** yyy
|
| 175 |
+
"""
|
| 176 |
+
if not value:
|
| 177 |
+
return md_text
|
| 178 |
+
|
| 179 |
+
anchor = f"**{anchor_label}**"
|
| 180 |
+
lines = md_text.split("\n")
|
| 181 |
+
replaced = False
|
| 182 |
+
|
| 183 |
+
for i, line in enumerate(lines):
|
| 184 |
+
if anchor in line:
|
| 185 |
+
# 保留锚点之前的所有内容 + 锚点本身
|
| 186 |
+
left = line.split(anchor, 1)[0] + anchor
|
| 187 |
+
lines[i] = f"{left}: {value}"
|
| 188 |
+
replaced = True
|
| 189 |
+
break
|
| 190 |
+
|
| 191 |
+
return "\n".join(lines) if replaced else md_text
|
| 192 |
+
|
| 193 |
+
md = _fill_line_by_anchor(md, "Authors", authors)
|
| 194 |
+
md = _fill_line_by_anchor(md, "Direct Link", github)
|
| 195 |
+
md = _fill_line_by_anchor(md, "Paper Title", title)
|
| 196 |
+
md = _fill_line_by_anchor(md, "Institution", institution)
|
| 197 |
+
|
| 198 |
+
out_md_path.write_text(md, encoding="utf-8")
|
| 199 |
+
|
| 200 |
+
return str(out_md_path)
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
def generate_pr_from_dag(
|
| 204 |
+
dag_path: str,
|
| 205 |
+
pr_path: str,
|
| 206 |
+
generate_pr_prompt: str,
|
| 207 |
+
model: str = "gpt-4o-mini",
|
| 208 |
+
timeout: int = 120,
|
| 209 |
+
debug: bool = True,
|
| 210 |
+
max_retries: int = 5,
|
| 211 |
+
backoff_base: float = 1.5,
|
| 212 |
+
max_content_chars: int = 12000,
|
| 213 |
+
max_visuals: int = 20,
|
| 214 |
+
config: dict = None
|
| 215 |
+
) -> None:
|
| 216 |
+
"""
|
| 217 |
+
Generate a PR markdown from dag.json by iterating section nodes and querying an LLM.
|
| 218 |
+
Supports both OpenAI and Google Gemini APIs using official SDKs.
|
| 219 |
+
"""
|
| 220 |
+
|
| 221 |
+
def log(msg: str) -> None:
|
| 222 |
+
if debug:
|
| 223 |
+
print(msg)
|
| 224 |
+
|
| 225 |
+
# -------------------------
|
| 226 |
+
# 0) Env: API key & Client Setup
|
| 227 |
+
# -------------------------
|
| 228 |
+
if config is None:
|
| 229 |
+
config = {}
|
| 230 |
+
|
| 231 |
+
api_keys_conf = config.get("api_keys", {})
|
| 232 |
+
|
| 233 |
+
# Simple heuristic to determine provider based on model name
|
| 234 |
+
is_gemini = "gemini" in model.lower()
|
| 235 |
+
|
| 236 |
+
client = None
|
| 237 |
+
|
| 238 |
+
if is_gemini:
|
| 239 |
+
# Gemini Configuration (New SDK)
|
| 240 |
+
if genai is None:
|
| 241 |
+
raise ImportError("Google GenAI SDK not installed. Please run `pip install google-genai`.")
|
| 242 |
+
|
| 243 |
+
api_key = api_keys_conf.get("gemini_api_key") or os.getenv("GEMINI_API_KEY", "").strip()
|
| 244 |
+
if not api_key:
|
| 245 |
+
raise RuntimeError("API Key not found for Gemini.")
|
| 246 |
+
|
| 247 |
+
client = genai.Client(api_key=api_key)
|
| 248 |
+
|
| 249 |
+
else:
|
| 250 |
+
# OpenAI Configuration
|
| 251 |
+
if OpenAI is None:
|
| 252 |
+
raise ImportError("OpenAI SDK not installed. Please run `pip install openai`.")
|
| 253 |
+
|
| 254 |
+
api_key = api_keys_conf.get("openai_api_key") or os.getenv("OPENAI_API_KEY", "").strip()
|
| 255 |
+
|
| 256 |
+
if not api_key:
|
| 257 |
+
raise RuntimeError("API Key not found for OpenAI.")
|
| 258 |
+
|
| 259 |
+
client = OpenAI(
|
| 260 |
+
api_key=api_key,
|
| 261 |
+
timeout=timeout,
|
| 262 |
+
max_retries=0 # We handle retries manually below
|
| 263 |
+
)
|
| 264 |
+
|
| 265 |
+
log(f"[INFO] Using provider = {'Gemini' if is_gemini else 'OpenAI'}")
|
| 266 |
+
log(f"[INFO] Using model = {model}")
|
| 267 |
+
|
| 268 |
+
# -------------------------
|
| 269 |
+
# 1) Load DAG
|
| 270 |
+
# -------------------------
|
| 271 |
+
dag_obj = json.loads(Path(dag_path).read_text(encoding="utf-8"))
|
| 272 |
+
if isinstance(dag_obj, list):
|
| 273 |
+
nodes = dag_obj
|
| 274 |
+
elif isinstance(dag_obj, dict) and isinstance(dag_obj.get("nodes"), list):
|
| 275 |
+
nodes = dag_obj["nodes"]
|
| 276 |
+
else:
|
| 277 |
+
raise ValueError("Unsupported dag.json format (expect list or dict with 'nodes').")
|
| 278 |
+
|
| 279 |
+
if not nodes:
|
| 280 |
+
log("[WARN] dag.json has no nodes; exiting.")
|
| 281 |
+
return
|
| 282 |
+
|
| 283 |
+
root = nodes[0]
|
| 284 |
+
root_edges = root.get("edge", [])
|
| 285 |
+
if not isinstance(root_edges, list):
|
| 286 |
+
log("[WARN] Root node edge is not a list; exiting.")
|
| 287 |
+
return
|
| 288 |
+
|
| 289 |
+
log(f"[INFO] Root node name = {root.get('name')}")
|
| 290 |
+
log(f"[INFO] Root edges (section names) = {root_edges}")
|
| 291 |
+
|
| 292 |
+
name2node: Dict[str, Dict[str, Any]] = {}
|
| 293 |
+
for n in nodes:
|
| 294 |
+
nm = n.get("name")
|
| 295 |
+
if isinstance(nm, str) and nm:
|
| 296 |
+
name2node[nm] = n
|
| 297 |
+
|
| 298 |
+
section_nodes: List[Dict[str, Any]] = []
|
| 299 |
+
for sec_name in root_edges:
|
| 300 |
+
if sec_name in name2node:
|
| 301 |
+
section_nodes.append(name2node[sec_name])
|
| 302 |
+
else:
|
| 303 |
+
log(f"[WARN] Section node '{sec_name}' not found in DAG; skipped.")
|
| 304 |
+
|
| 305 |
+
log(f"[INFO] Resolved {len(section_nodes)} section nodes.")
|
| 306 |
+
if not section_nodes:
|
| 307 |
+
log("[WARN] No section nodes to process; exiting.")
|
| 308 |
+
return
|
| 309 |
+
|
| 310 |
+
# -------------------------
|
| 311 |
+
# 2) Load PR markdown
|
| 312 |
+
# -------------------------
|
| 313 |
+
pr_file = Path(pr_path)
|
| 314 |
+
pr_text = pr_file.read_text(encoding="utf-8")
|
| 315 |
+
|
| 316 |
+
KNOWN_LABELS = ["Key Question", "Brilliant Idea", "Core Methods", "Core Results", "Significance/Impact"]
|
| 317 |
+
|
| 318 |
+
if debug:
|
| 319 |
+
log("[INFO] PR template header scan:")
|
| 320 |
+
for lab in KNOWN_LABELS:
|
| 321 |
+
found = bool(re.search(rf"(?mi)^.*\*\*{re.escape(lab)}\*\*.*$", pr_text))
|
| 322 |
+
log(f" - {lab}: found={found}")
|
| 323 |
+
|
| 324 |
+
filled_key_question = False
|
| 325 |
+
filled_brilliant_idea = False
|
| 326 |
+
filled_significance = False
|
| 327 |
+
core_methods_inlined = False
|
| 328 |
+
core_results_inlined = False
|
| 329 |
+
|
| 330 |
+
# -------------------------
|
| 331 |
+
# 3) LLM call (OpenAI & Gemini SDKs)
|
| 332 |
+
# -------------------------
|
| 333 |
+
def chat_complete(prompt: str, payload_meta: str = "") -> str:
|
| 334 |
+
system_msg = "You are a precise scientific writing assistant."
|
| 335 |
+
|
| 336 |
+
last_err: Optional[Exception] = None
|
| 337 |
+
|
| 338 |
+
for attempt in range(1, max_retries + 1):
|
| 339 |
+
try:
|
| 340 |
+
if is_gemini:
|
| 341 |
+
# Gemini (Google GenAI SDK)
|
| 342 |
+
response = client.models.generate_content(
|
| 343 |
+
model=model,
|
| 344 |
+
contents=prompt,
|
| 345 |
+
config=types.GenerateContentConfig(
|
| 346 |
+
system_instruction=system_msg,
|
| 347 |
+
temperature=0.4,
|
| 348 |
+
)
|
| 349 |
+
)
|
| 350 |
+
# 检查是否因为安全原因被拦截
|
| 351 |
+
if not response.text:
|
| 352 |
+
log(f"[WARN] Gemini response empty (possibly safety blocked) {payload_meta}")
|
| 353 |
+
return ""
|
| 354 |
+
return response.text.strip()
|
| 355 |
+
|
| 356 |
+
else:
|
| 357 |
+
# OpenAI (Official SDK)
|
| 358 |
+
response = client.chat.completions.create(
|
| 359 |
+
model=model,
|
| 360 |
+
messages=[
|
| 361 |
+
{"role": "system", "content": system_msg},
|
| 362 |
+
{"role": "user", "content": prompt},
|
| 363 |
+
],
|
| 364 |
+
temperature=0.4,
|
| 365 |
+
)
|
| 366 |
+
content = response.choices[0].message.content
|
| 367 |
+
return content.strip() if content else ""
|
| 368 |
+
|
| 369 |
+
except Exception as e:
|
| 370 |
+
# 捕获 SDK 抛出的各类异常 (RateLimit, APIError, ConnectionError 等)
|
| 371 |
+
last_err = e
|
| 372 |
+
sleep_s = backoff_base ** (attempt - 1)
|
| 373 |
+
log(f"[LLM-RETRY] attempt {attempt}/{max_retries} error: {repr(e)}; sleep {sleep_s:.2f}s {payload_meta}")
|
| 374 |
+
time.sleep(sleep_s)
|
| 375 |
+
|
| 376 |
+
raise RuntimeError(f"LLM request failed after {max_retries} retries. Last error: {repr(last_err)}")
|
| 377 |
+
|
| 378 |
+
# -------------------------
|
| 379 |
+
# 4) Parse LLM output
|
| 380 |
+
# -------------------------
|
| 381 |
+
def parse_llm_output(text: str) -> Dict[str, Any]:
|
| 382 |
+
out: Dict[str, Any] = {
|
| 383 |
+
"type": "unknown",
|
| 384 |
+
"key_question": None,
|
| 385 |
+
"brilliant_idea": None,
|
| 386 |
+
"core_methods": None,
|
| 387 |
+
"core_results": None,
|
| 388 |
+
"significance": None,
|
| 389 |
+
"image": None,
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
img = re.search(r'!\[\]\(([^)]+)\)', text)
|
| 393 |
+
if img:
|
| 394 |
+
out["image"] = f".strip()})"
|
| 395 |
+
|
| 396 |
+
def grab(label: str) -> Optional[str]:
|
| 397 |
+
m = re.search(
|
| 398 |
+
rf"(?is)(?:^{re.escape(label)}\s*[::]\s*)(.*?)(?=^\w[\w /-]*\s*[::]|\Z)",
|
| 399 |
+
text,
|
| 400 |
+
flags=re.MULTILINE,
|
| 401 |
+
)
|
| 402 |
+
return m.group(1).strip() if m else None
|
| 403 |
+
|
| 404 |
+
out["key_question"] = grab("Key Question")
|
| 405 |
+
out["brilliant_idea"] = grab("Brilliant Idea")
|
| 406 |
+
out["core_methods"] = grab("Core Methods")
|
| 407 |
+
out["core_results"] = grab("Core Results")
|
| 408 |
+
out["significance"] = grab("Significance/Impact")
|
| 409 |
+
|
| 410 |
+
if out["key_question"] or out["brilliant_idea"]:
|
| 411 |
+
out["type"] = "intro"
|
| 412 |
+
elif out["core_methods"]:
|
| 413 |
+
out["type"] = "methods"
|
| 414 |
+
elif out["core_results"]:
|
| 415 |
+
out["type"] = "results"
|
| 416 |
+
elif out["significance"]:
|
| 417 |
+
out["type"] = "impact"
|
| 418 |
+
|
| 419 |
+
return out
|
| 420 |
+
|
| 421 |
+
# -------------------------
|
| 422 |
+
# 5) PR template helpers (emoji-safe + APPEND inside block)
|
| 423 |
+
# -------------------------
|
| 424 |
+
def _find_header_line(md: str, label: str) -> Optional[re.Match]:
|
| 425 |
+
return re.search(rf"(?mi)^(?P<line>.*\*\*{re.escape(label)}\*\*.*)$", md)
|
| 426 |
+
|
| 427 |
+
def has_header(md: str, label: str) -> bool:
|
| 428 |
+
found = _find_header_line(md, label) is not None
|
| 429 |
+
log(f"[CHECK] Header '{label}' found = {found}")
|
| 430 |
+
return found
|
| 431 |
+
|
| 432 |
+
def set_inline(md: str, label: str, text: str) -> str:
|
| 433 |
+
m = _find_header_line(md, label)
|
| 434 |
+
if not m:
|
| 435 |
+
log(f"[SKIP] set_inline: header '{label}' not found")
|
| 436 |
+
return md
|
| 437 |
+
|
| 438 |
+
line = m.group("line")
|
| 439 |
+
token_pat = re.compile(rf"\*\*{re.escape(label)}\*\*", re.I)
|
| 440 |
+
tm = token_pat.search(line)
|
| 441 |
+
if not tm:
|
| 442 |
+
log(f"[SKIP] set_inline: token '**{label}**' not found in line")
|
| 443 |
+
return md
|
| 444 |
+
|
| 445 |
+
prefix = line[:tm.end()] # includes **Label**
|
| 446 |
+
new_line = f"{prefix}: {text}".rstrip()
|
| 447 |
+
|
| 448 |
+
start, end = m.start("line"), m.end("line")
|
| 449 |
+
return md[:start] + new_line + md[end:]
|
| 450 |
+
|
| 451 |
+
def _next_header_pos(md: str, start_pos: int) -> int:
|
| 452 |
+
tail = md[start_pos:]
|
| 453 |
+
next_pos = None
|
| 454 |
+
for lab in KNOWN_LABELS:
|
| 455 |
+
mm = re.search(rf"(?mi)^\s*.*\*\*{re.escape(lab)}\*\*.*$", tail)
|
| 456 |
+
if mm:
|
| 457 |
+
cand = start_pos + mm.start()
|
| 458 |
+
if next_pos is None or cand < next_pos:
|
| 459 |
+
next_pos = cand
|
| 460 |
+
return next_pos if next_pos is not None else len(md)
|
| 461 |
+
|
| 462 |
+
def append_to_label_block(md: str, label: str, insertion_lines: List[str]) -> str:
|
| 463 |
+
m = _find_header_line(md, label)
|
| 464 |
+
if not m:
|
| 465 |
+
log(f"[SKIP] append_to_label_block: header '{label}' not found")
|
| 466 |
+
return md
|
| 467 |
+
|
| 468 |
+
insertion = "\n".join([ln for ln in insertion_lines if ln and ln.strip()]).rstrip()
|
| 469 |
+
if not insertion:
|
| 470 |
+
log(f"[SKIP] append_to_label_block: empty insertion for '{label}'")
|
| 471 |
+
return md
|
| 472 |
+
|
| 473 |
+
hdr_end = m.end("line")
|
| 474 |
+
block_end = _next_header_pos(md, hdr_end)
|
| 475 |
+
|
| 476 |
+
before = md[:hdr_end]
|
| 477 |
+
middle = md[hdr_end:block_end]
|
| 478 |
+
after = md[block_end:]
|
| 479 |
+
|
| 480 |
+
if not before.endswith("\n"):
|
| 481 |
+
before += "\n"
|
| 482 |
+
if middle and not middle.startswith("\n"):
|
| 483 |
+
middle = "\n" + middle
|
| 484 |
+
|
| 485 |
+
middle_stripped_right = middle.rstrip("\n")
|
| 486 |
+
if middle_stripped_right.strip() == "":
|
| 487 |
+
new_middle = "\n" + insertion + "\n"
|
| 488 |
+
else:
|
| 489 |
+
new_middle = middle_stripped_right + "\n\n" + insertion + "\n"
|
| 490 |
+
|
| 491 |
+
return before + new_middle + after
|
| 492 |
+
|
| 493 |
+
# -------------------------
|
| 494 |
+
# 6) Main loop over sections
|
| 495 |
+
# -------------------------
|
| 496 |
+
for idx, sec in enumerate(section_nodes):
|
| 497 |
+
log("\n" + "=" * 90)
|
| 498 |
+
log(f"[SECTION {idx}] name = {sec.get('name')}")
|
| 499 |
+
|
| 500 |
+
content = sec.get("content", "")
|
| 501 |
+
if not isinstance(content, str):
|
| 502 |
+
content = ""
|
| 503 |
+
|
| 504 |
+
visuals = sec.get("visual_node", [])
|
| 505 |
+
if not isinstance(visuals, list):
|
| 506 |
+
visuals = []
|
| 507 |
+
|
| 508 |
+
visuals_norm: List[str] = []
|
| 509 |
+
for v in visuals:
|
| 510 |
+
if isinstance(v, str):
|
| 511 |
+
visuals_norm.append(v)
|
| 512 |
+
elif isinstance(v, dict):
|
| 513 |
+
for k in ("path", "src", "url", "md", "markdown"):
|
| 514 |
+
if k in v and isinstance(v[k], str):
|
| 515 |
+
visuals_norm.append(v[k])
|
| 516 |
+
break
|
| 517 |
+
|
| 518 |
+
if len(content) > max_content_chars:
|
| 519 |
+
content = content[:max_content_chars] + "\n...(truncated)"
|
| 520 |
+
|
| 521 |
+
if len(visuals_norm) > max_visuals:
|
| 522 |
+
visuals_norm = visuals_norm[:max_visuals]
|
| 523 |
+
|
| 524 |
+
node_obj = {
|
| 525 |
+
"name": sec.get("name", ""),
|
| 526 |
+
"content": content,
|
| 527 |
+
"visual_node": visuals_norm,
|
| 528 |
+
}
|
| 529 |
+
|
| 530 |
+
if debug:
|
| 531 |
+
log(f"[PAYLOAD] content_chars={len(node_obj['content'])} visuals={len(node_obj['visual_node'])}")
|
| 532 |
+
preview = dict(node_obj)
|
| 533 |
+
if len(preview["content"]) > 800:
|
| 534 |
+
preview["content"] = preview["content"][:800] + "...(truncated)"
|
| 535 |
+
log("[SEND TO LLM] Node payload preview:")
|
| 536 |
+
print(json.dumps(preview, indent=2, ensure_ascii=False))
|
| 537 |
+
|
| 538 |
+
prompt = generate_pr_prompt.replace("{NODE_JSON}", json.dumps(node_obj, ensure_ascii=False))
|
| 539 |
+
llm_text = chat_complete(prompt, payload_meta=f"(section_idx={idx}, section_name={node_obj['name']})")
|
| 540 |
+
|
| 541 |
+
log("\n[LLM RAW OUTPUT]")
|
| 542 |
+
print(llm_text)
|
| 543 |
+
|
| 544 |
+
parsed = parse_llm_output(llm_text)
|
| 545 |
+
log("\n[PARSED OUTPUT]")
|
| 546 |
+
print(json.dumps(parsed, indent=2, ensure_ascii=False))
|
| 547 |
+
|
| 548 |
+
if parsed["type"] == "intro":
|
| 549 |
+
log("[TYPE] Introduction-like")
|
| 550 |
+
kq = parsed.get("key_question")
|
| 551 |
+
bi = parsed.get("brilliant_idea")
|
| 552 |
+
img = parsed.get("image")
|
| 553 |
+
|
| 554 |
+
if kq and not filled_key_question:
|
| 555 |
+
if has_header(pr_text, "Key Question"):
|
| 556 |
+
pr_text = set_inline(pr_text, "Key Question", kq)
|
| 557 |
+
filled_key_question = True
|
| 558 |
+
log("[WRITE] Key Question filled (first time).")
|
| 559 |
+
else:
|
| 560 |
+
log("[MISS] PR has no Key Question header.")
|
| 561 |
+
else:
|
| 562 |
+
log("[SKIP] Key Question ignored (empty or already filled).")
|
| 563 |
+
|
| 564 |
+
if bi and not filled_brilliant_idea:
|
| 565 |
+
if has_header(pr_text, "Brilliant Idea"):
|
| 566 |
+
pr_text = set_inline(pr_text, "Brilliant Idea", bi)
|
| 567 |
+
if img:
|
| 568 |
+
pr_text = append_to_label_block(pr_text, "Brilliant Idea", [img])
|
| 569 |
+
filled_brilliant_idea = True
|
| 570 |
+
log("[WRITE] Brilliant Idea filled (first time).")
|
| 571 |
+
else:
|
| 572 |
+
log("[MISS] PR has no Brilliant Idea header.")
|
| 573 |
+
else:
|
| 574 |
+
log("[SKIP] Brilliant Idea ignored (empty or already filled).")
|
| 575 |
+
|
| 576 |
+
elif parsed["type"] == "methods":
|
| 577 |
+
log("[TYPE] Methods-like")
|
| 578 |
+
cm = parsed.get("core_methods")
|
| 579 |
+
img = parsed.get("image")
|
| 580 |
+
|
| 581 |
+
if not cm:
|
| 582 |
+
log("[SKIP] Core Methods empty.")
|
| 583 |
+
continue
|
| 584 |
+
if not has_header(pr_text, "Core Methods"):
|
| 585 |
+
log("[MISS] PR has no Core Methods header.")
|
| 586 |
+
continue
|
| 587 |
+
|
| 588 |
+
if not core_methods_inlined:
|
| 589 |
+
pr_text = set_inline(pr_text, "Core Methods", cm)
|
| 590 |
+
core_methods_inlined = True
|
| 591 |
+
log("[WRITE] Core Methods inlined (first time).")
|
| 592 |
+
if img:
|
| 593 |
+
pr_text = append_to_label_block(pr_text, "Core Methods", [img])
|
| 594 |
+
log("[WRITE] Core Methods image appended.")
|
| 595 |
+
else:
|
| 596 |
+
lines = [cm] + ([img] if img else [])
|
| 597 |
+
pr_text = append_to_label_block(pr_text, "Core Methods", lines)
|
| 598 |
+
log("[WRITE] Core Methods appended as (text, image) pair.")
|
| 599 |
+
|
| 600 |
+
elif parsed["type"] == "results":
|
| 601 |
+
log("[TYPE] Results-like")
|
| 602 |
+
cr = parsed.get("core_results")
|
| 603 |
+
img = parsed.get("image")
|
| 604 |
+
|
| 605 |
+
if not cr:
|
| 606 |
+
log("[SKIP] Core Results empty.")
|
| 607 |
+
continue
|
| 608 |
+
if not has_header(pr_text, "Core Results"):
|
| 609 |
+
log("[MISS] PR has no Core Results header.")
|
| 610 |
+
continue
|
| 611 |
+
|
| 612 |
+
if not core_results_inlined:
|
| 613 |
+
pr_text = set_inline(pr_text, "Core Results", cr)
|
| 614 |
+
core_results_inlined = True
|
| 615 |
+
log("[WRITE] Core Results inlined (first time).")
|
| 616 |
+
if img:
|
| 617 |
+
pr_text = append_to_label_block(pr_text, "Core Results", [img])
|
| 618 |
+
log("[WRITE] Core Results image appended.")
|
| 619 |
+
else:
|
| 620 |
+
lines = [cr] + ([img] if img else [])
|
| 621 |
+
pr_text = append_to_label_block(pr_text, "Core Results", lines)
|
| 622 |
+
log("[WRITE] Core Results appended as (text, image) pair.")
|
| 623 |
+
|
| 624 |
+
elif parsed["type"] == "impact":
|
| 625 |
+
log("[TYPE] Impact-like")
|
| 626 |
+
si = parsed.get("significance")
|
| 627 |
+
if not si:
|
| 628 |
+
log("[SKIP] Significance/Impact empty.")
|
| 629 |
+
continue
|
| 630 |
+
if filled_significance:
|
| 631 |
+
log("[SKIP] Significance/Impact ignored (already filled).")
|
| 632 |
+
continue
|
| 633 |
+
if has_header(pr_text, "Significance/Impact"):
|
| 634 |
+
pr_text = set_inline(pr_text, "Significance/Impact", si)
|
| 635 |
+
filled_significance = True
|
| 636 |
+
log("[WRITE] Significance/Impact filled (first time).")
|
| 637 |
+
else:
|
| 638 |
+
log("[MISS] PR has no Significance/Impact header.")
|
| 639 |
+
|
| 640 |
+
else:
|
| 641 |
+
log("[WARN] Unknown section type; ignored.")
|
| 642 |
+
|
| 643 |
+
# -------------------------
|
| 644 |
+
# 7) Save
|
| 645 |
+
# -------------------------
|
| 646 |
+
pr_file.write_text(pr_text, encoding="utf-8")
|
| 647 |
+
log("\n[SAVED] PR markdown updated in-place.")
|
| 648 |
+
|
| 649 |
+
|
| 650 |
+
# ================================增加标题和hashtag=================================
|
| 651 |
+
def add_title_and_hashtag(pr_path: str, add_title_and_hashtag_prompt: str, model: str = "gpt-4o-mini", config: dict = None) -> None:
|
| 652 |
+
"""
|
| 653 |
+
1) Read markdown from pr_path.
|
| 654 |
+
2) Send it to LLM using add_title_and_hashtag_prompt (expects {MD_TEXT} placeholder).
|
| 655 |
+
3) Parse LLM output.
|
| 656 |
+
4) Update file in-place.
|
| 657 |
+
"""
|
| 658 |
+
|
| 659 |
+
# 确保 config 不为空
|
| 660 |
+
if config is None:
|
| 661 |
+
config = {}
|
| 662 |
+
api_keys = config.get('api_keys', {})
|
| 663 |
+
|
| 664 |
+
# -------------------------
|
| 665 |
+
# 0) Read markdown
|
| 666 |
+
# -------------------------
|
| 667 |
+
pr_file = Path(pr_path)
|
| 668 |
+
if not pr_file.exists():
|
| 669 |
+
raise FileNotFoundError(f"pr_path not found: {pr_path}")
|
| 670 |
+
|
| 671 |
+
md_text = pr_file.read_text(encoding="utf-8")
|
| 672 |
+
|
| 673 |
+
# -------------------------
|
| 674 |
+
# 1) Call LLM (Modified for Dual Support)
|
| 675 |
+
# -------------------------
|
| 676 |
+
prompt_content = add_title_and_hashtag_prompt.replace("{MD_TEXT}", md_text)
|
| 677 |
+
system_instruction = "You are a precise scientific social media copywriter."
|
| 678 |
+
llm_out = ""
|
| 679 |
+
|
| 680 |
+
# >>> 分支判断逻辑 >>>
|
| 681 |
+
if "gemini" in model.lower():
|
| 682 |
+
# --- Google Gemini (New SDK) ---
|
| 683 |
+
api_key = api_keys.get("gemini_api_key", "").strip()
|
| 684 |
+
|
| 685 |
+
if not api_key:
|
| 686 |
+
raise ValueError("Missing config['api_keys']['gemini_api_key']")
|
| 687 |
+
|
| 688 |
+
try:
|
| 689 |
+
from google import genai
|
| 690 |
+
from google.genai import types
|
| 691 |
+
except ImportError as e:
|
| 692 |
+
raise ImportError("google-genai package is required. Install with: pip install google-genai") from e
|
| 693 |
+
|
| 694 |
+
# 配置 client
|
| 695 |
+
client = genai.Client(api_key=api_key)
|
| 696 |
+
|
| 697 |
+
try:
|
| 698 |
+
response = client.models.generate_content(
|
| 699 |
+
model=model,
|
| 700 |
+
contents=prompt_content,
|
| 701 |
+
config=types.GenerateContentConfig(
|
| 702 |
+
system_instruction=system_instruction,
|
| 703 |
+
temperature=0.6
|
| 704 |
+
)
|
| 705 |
+
)
|
| 706 |
+
llm_out = response.text
|
| 707 |
+
except Exception as e:
|
| 708 |
+
raise RuntimeError(f"Gemini API call failed: {e}")
|
| 709 |
+
|
| 710 |
+
else:
|
| 711 |
+
# --- OpenAI (Existing) ---
|
| 712 |
+
api_key = api_keys.get("openai_api_key", "").strip()
|
| 713 |
+
|
| 714 |
+
if not api_key:
|
| 715 |
+
# 兼容旧逻辑,如果没有传 config,尝试读环境变量(可选,视你需求而定)
|
| 716 |
+
api_key = os.getenv("OPENAI_API_KEY", "").strip()
|
| 717 |
+
|
| 718 |
+
if not api_key:
|
| 719 |
+
raise ValueError("Missing config['api_keys']['openai_api_key']")
|
| 720 |
+
|
| 721 |
+
try:
|
| 722 |
+
from openai import OpenAI
|
| 723 |
+
except ImportError as e:
|
| 724 |
+
raise ImportError("openai package is required. Install with: pip install openai") from e
|
| 725 |
+
|
| 726 |
+
client = OpenAI(api_key=api_key)
|
| 727 |
+
|
| 728 |
+
try:
|
| 729 |
+
resp = client.chat.completions.create(
|
| 730 |
+
model=model,
|
| 731 |
+
messages=[
|
| 732 |
+
{"role": "system", "content": system_instruction},
|
| 733 |
+
{"role": "user", "content": prompt_content},
|
| 734 |
+
],
|
| 735 |
+
temperature=0.6,
|
| 736 |
+
)
|
| 737 |
+
llm_out = (resp.choices[0].message.content or "").strip()
|
| 738 |
+
except Exception as e:
|
| 739 |
+
raise RuntimeError(f"OpenAI API call failed: {e}")
|
| 740 |
+
|
| 741 |
+
if not llm_out:
|
| 742 |
+
raise ValueError("LLM returned empty content.")
|
| 743 |
+
|
| 744 |
+
# -------------------------
|
| 745 |
+
# 2) Parse LLM output (Remaining logic unchanged)
|
| 746 |
+
# -------------------------
|
| 747 |
+
# 注意:这里假设 _parse_title_and_tags 和 _line_ending 已经在外部定义或在此作用域内可用
|
| 748 |
+
title, specific_tags, community_tag = _parse_title_and_tags(llm_out)
|
| 749 |
+
|
| 750 |
+
# -------------------------
|
| 751 |
+
# 3) Update first line: "# {Title}"
|
| 752 |
+
# -------------------------
|
| 753 |
+
lines = md_text.splitlines(True)
|
| 754 |
+
if not lines:
|
| 755 |
+
raise ValueError("Markdown file is empty.")
|
| 756 |
+
|
| 757 |
+
first_line = lines[0].rstrip("\r\n")
|
| 758 |
+
# 辅助函数:如果原代码中 _line_ending 未定义,需自行补充。此处沿用原逻辑。
|
| 759 |
+
# 假设 _line_ending(s) 返回 s 的换行符
|
| 760 |
+
|
| 761 |
+
def _local_line_ending(s):
|
| 762 |
+
if s.endswith("\r\n"): return "\r\n"
|
| 763 |
+
if s.endswith("\n"): return "\n"
|
| 764 |
+
return "\n" # default
|
| 765 |
+
|
| 766 |
+
current_ending = _local_line_ending(lines[0])
|
| 767 |
+
|
| 768 |
+
if re.fullmatch(r"#\s*", first_line):
|
| 769 |
+
lines[0] = f"# 🔥{title}😯{current_ending}"
|
| 770 |
+
else:
|
| 771 |
+
if first_line.startswith("#"):
|
| 772 |
+
lines[0] = re.sub(r"^#\s*.*$", f"# 🔥{title}😯", first_line) + current_ending
|
| 773 |
+
else:
|
| 774 |
+
lines.insert(0, f"# 🔥{title}😯\n")
|
| 775 |
+
|
| 776 |
+
updated = "".join(lines)
|
| 777 |
+
|
| 778 |
+
# -------------------------
|
| 779 |
+
# 4) Replace "Specific:" line
|
| 780 |
+
# -------------------------
|
| 781 |
+
def _replace_specific_line(match: re.Match) -> str:
|
| 782 |
+
prefix = match.group(1)
|
| 783 |
+
tail = match.group(2) or ""
|
| 784 |
+
has_semicolon = ";" in tail
|
| 785 |
+
end = ";" if has_semicolon else ""
|
| 786 |
+
return f"{prefix}{specific_tags[0]} {specific_tags[1]} {specific_tags[2]}{end}"
|
| 787 |
+
|
| 788 |
+
updated, n1 = re.subn(
|
| 789 |
+
r"(?mi)^(Specific:\s*)(.*)$",
|
| 790 |
+
lambda m: _replace_specific_line(m),
|
| 791 |
+
updated,
|
| 792 |
+
count=1,
|
| 793 |
+
)
|
| 794 |
+
|
| 795 |
+
# -------------------------
|
| 796 |
+
# 5) Replace "Community:" line
|
| 797 |
+
# -------------------------
|
| 798 |
+
updated, n2 = re.subn(
|
| 799 |
+
r"(Community:\s*)(#[^\s;]+)",
|
| 800 |
+
lambda m: f"{m.group(1)}{community_tag}",
|
| 801 |
+
updated,
|
| 802 |
+
count=1,
|
| 803 |
+
flags=re.IGNORECASE,
|
| 804 |
+
)
|
| 805 |
+
|
| 806 |
+
if n1 == 0:
|
| 807 |
+
raise ValueError("Could not find a line starting with 'Specific:' to replace.")
|
| 808 |
+
if n2 == 0:
|
| 809 |
+
raise ValueError("Could not find the 'Community: #Tag1' pattern to replace.")
|
| 810 |
+
|
| 811 |
+
# -------------------------
|
| 812 |
+
# 6) Write back
|
| 813 |
+
# -------------------------
|
| 814 |
+
pr_file.write_text(updated, encoding="utf-8")
|
| 815 |
+
|
| 816 |
+
|
| 817 |
+
def _parse_title_and_tags(llm_out: str) -> Tuple[str, List[str], str]:
|
| 818 |
+
"""
|
| 819 |
+
Parse:
|
| 820 |
+
Title: ...
|
| 821 |
+
Specific Tag: #A #B #C
|
| 822 |
+
Community Tag: #X
|
| 823 |
+
"""
|
| 824 |
+
def pick_line(prefix: str) -> str:
|
| 825 |
+
m = re.search(rf"^{re.escape(prefix)}\s*(.+)$", llm_out, flags=re.MULTILINE)
|
| 826 |
+
if not m:
|
| 827 |
+
raise ValueError(f"LLM output missing line: '{prefix} ...'")
|
| 828 |
+
return m.group(1).strip()
|
| 829 |
+
|
| 830 |
+
title = pick_line("Title:")
|
| 831 |
+
spec = pick_line("Specific Tag:")
|
| 832 |
+
comm = pick_line("Community Tag:")
|
| 833 |
+
|
| 834 |
+
spec_tags = re.findall(r"#[A-Za-z0-9_]+", spec)
|
| 835 |
+
comm_tags = re.findall(r"#[A-Za-z0-9_]+", comm)
|
| 836 |
+
|
| 837 |
+
if len(spec_tags) != 3:
|
| 838 |
+
raise ValueError(f"Expected exactly 3 specific tags, got {len(spec_tags)}. Raw: {spec}")
|
| 839 |
+
if len(comm_tags) != 1:
|
| 840 |
+
raise ValueError(f"Expected exactly 1 community tag, got {len(comm_tags)}. Raw: {comm}")
|
| 841 |
+
|
| 842 |
+
title = title.strip().strip('"').strip("'")
|
| 843 |
+
if not title:
|
| 844 |
+
raise ValueError("Parsed title is empty.")
|
| 845 |
+
|
| 846 |
+
return title, spec_tags, comm_tags[0]
|
| 847 |
+
|
| 848 |
+
|
| 849 |
+
def _line_ending(original_line: str) -> str:
|
| 850 |
+
if original_line.endswith("\r\n"):
|
| 851 |
+
return "\r\n"
|
| 852 |
+
if original_line.endswith("\n"):
|
| 853 |
+
return "\n"
|
| 854 |
+
return "\n"
|
| 855 |
+
|
| 856 |
+
|
| 857 |
+
|
| 858 |
+
|
| 859 |
+
# ===========================增加机构的tag===============================
|
| 860 |
+
def add_institution_tag(pr_path: str) -> None:
|
| 861 |
+
"""
|
| 862 |
+
读取 markdown 中 🏛️**Institution**: 后的所有机构名(鲁棒分割),然后:
|
| 863 |
+
1) 将所有机构名拼成一行,写入 Strategic Mentions:# 后面,例如:
|
| 864 |
+
Strategic Mentions:# NVIDIA, Tel Aviv University
|
| 865 |
+
2) 在 Strategic Mentions 这一行的下一行追加一行:
|
| 866 |
+
@NVIDIA, Tel Aviv University
|
| 867 |
+
原地修改文件。
|
| 868 |
+
"""
|
| 869 |
+
|
| 870 |
+
md_path = Path(pr_path)
|
| 871 |
+
if not md_path.exists():
|
| 872 |
+
raise FileNotFoundError(f"Markdown file not found: {pr_path}")
|
| 873 |
+
|
| 874 |
+
text = md_path.read_text(encoding="utf-8")
|
| 875 |
+
|
| 876 |
+
# -------------------------------------------------
|
| 877 |
+
# 1) 提取 Institution 行内容
|
| 878 |
+
# -------------------------------------------------
|
| 879 |
+
institution_pattern = re.compile(r"🏛️\s*\*\*Institution\*\*\s*:\s*(.+)")
|
| 880 |
+
m = institution_pattern.search(text)
|
| 881 |
+
if not m:
|
| 882 |
+
raise ValueError("Institution section not found in markdown.")
|
| 883 |
+
|
| 884 |
+
institution_raw = m.group(1).strip()
|
| 885 |
+
|
| 886 |
+
# -------------------------------------------------
|
| 887 |
+
# 2) 鲁棒切分:提取所有机构名
|
| 888 |
+
# 支持中英文分号/逗号/顿号/竖线/斜杠/换行/制表符等
|
| 889 |
+
# -------------------------------------------------
|
| 890 |
+
split_pattern = re.compile(r"\s*(?:;|;|,|,|、|\||||/|\n|\t)\s*")
|
| 891 |
+
parts = [p.strip() for p in split_pattern.split(institution_raw) if p.strip()]
|
| 892 |
+
if not parts:
|
| 893 |
+
raise ValueError("Institution content is empty after parsing.")
|
| 894 |
+
|
| 895 |
+
# 去除常见尾部标点噪声,并保持原顺序去重
|
| 896 |
+
seen = set()
|
| 897 |
+
institutions = []
|
| 898 |
+
for p in parts:
|
| 899 |
+
p = p.strip(" .。")
|
| 900 |
+
if p and p not in seen:
|
| 901 |
+
institutions.append(p)
|
| 902 |
+
seen.add(p)
|
| 903 |
+
|
| 904 |
+
if not institutions:
|
| 905 |
+
raise ValueError("No valid institution names parsed.")
|
| 906 |
+
|
| 907 |
+
institutions_str = ", ".join(institutions)
|
| 908 |
+
|
| 909 |
+
# -------------------------------------------------
|
| 910 |
+
# 3) 替换 Strategic Mentions:# 行,并在其下一行插入 @...
|
| 911 |
+
# 仅处理第一次出现
|
| 912 |
+
# -------------------------------------------------
|
| 913 |
+
strategic_line_pattern = re.compile(r"^(Strategic Mentions:\s*#).*$", re.MULTILINE)
|
| 914 |
+
|
| 915 |
+
def repl(mm: re.Match) -> str:
|
| 916 |
+
prefix = mm.group(1)
|
| 917 |
+
return f"{prefix} {institutions_str}\n@{institutions_str}"
|
| 918 |
+
|
| 919 |
+
new_text, n = strategic_line_pattern.subn(repl, text, count=1)
|
| 920 |
+
if n == 0:
|
| 921 |
+
raise ValueError("Strategic Mentions section not found in markdown.")
|
| 922 |
+
|
| 923 |
+
md_path.write_text(new_text, encoding="utf-8")
|
| 924 |
+
|
| 925 |
+
|
| 926 |
+
# =======================删除重复图片引用======================
|
| 927 |
+
def dedup_consecutive_markdown_images(md_path: str, inplace: bool = True) -> Tuple[str, int]:
|
| 928 |
+
"""
|
| 929 |
+
去除 Markdown 中“连续出现”的相同图片引用(按 src 判重),只保留一个。
|
| 930 |
+
连续的定义:两张图片之间只要是空白字符(空格/Tab/换行)也视为连续;
|
| 931 |
+
若中间出现任何非空白内容(文字、代码、列表符号等),则不算连续。
|
| 932 |
+
|
| 933 |
+
支持:
|
| 934 |
+

|
| 935 |
+

|
| 936 |
+

|
| 937 |
+
|
| 938 |
+
返回:
|
| 939 |
+
(new_text, removed_count)
|
| 940 |
+
"""
|
| 941 |
+
|
| 942 |
+
p = Path(md_path)
|
| 943 |
+
text = p.read_text(encoding="utf-8")
|
| 944 |
+
|
| 945 |
+
img_pat = re.compile(
|
| 946 |
+
r'!\[(?P<alt>[^\]]*)\]\((?P<src>[^)\s]+)(?:\s+"[^"]*")?\)',
|
| 947 |
+
flags=re.MULTILINE
|
| 948 |
+
)
|
| 949 |
+
|
| 950 |
+
parts = []
|
| 951 |
+
last = 0
|
| 952 |
+
for m in img_pat.finditer(text):
|
| 953 |
+
if m.start() > last:
|
| 954 |
+
parts.append(("text", text[last:m.start()]))
|
| 955 |
+
parts.append(("img", m.group(0), m.group("src")))
|
| 956 |
+
last = m.end()
|
| 957 |
+
if last < len(text):
|
| 958 |
+
parts.append(("text", text[last:]))
|
| 959 |
+
|
| 960 |
+
removed = 0
|
| 961 |
+
new_parts = []
|
| 962 |
+
|
| 963 |
+
prev_img_src = None
|
| 964 |
+
# 只有遇到“非空白文本”才会真正打断连续性
|
| 965 |
+
saw_non_whitespace_since_prev_img = True # 初始视为打断状态
|
| 966 |
+
|
| 967 |
+
for part in parts:
|
| 968 |
+
if part[0] == "img":
|
| 969 |
+
_, raw_img, src = part
|
| 970 |
+
|
| 971 |
+
# 连续重复判定:上一张图存在 + 中间没有非空白内容 + src 相同
|
| 972 |
+
if prev_img_src is not None and (not saw_non_whitespace_since_prev_img) and prev_img_src == src:
|
| 973 |
+
removed += 1
|
| 974 |
+
# 删除该图片(不追加)
|
| 975 |
+
continue
|
| 976 |
+
|
| 977 |
+
# 保留该图片
|
| 978 |
+
new_parts.append(raw_img)
|
| 979 |
+
prev_img_src = src
|
| 980 |
+
saw_non_whitespace_since_prev_img = False
|
| 981 |
+
|
| 982 |
+
else:
|
| 983 |
+
_, raw_text = part
|
| 984 |
+
new_parts.append(raw_text)
|
| 985 |
+
|
| 986 |
+
# 只有出现非空白,才视为打断连续图片序列
|
| 987 |
+
if raw_text.strip() != "":
|
| 988 |
+
saw_non_whitespace_since_prev_img = True
|
| 989 |
+
|
| 990 |
+
new_text = "".join(new_parts)
|
| 991 |
+
|
| 992 |
+
if inplace and removed > 0:
|
| 993 |
+
p.write_text(new_text, encoding="utf-8")
|
| 994 |
+
|
| 995 |
+
return new_text, removed
|
src/__init__.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .paper2DAG import clean_paper
|
| 2 |
+
from .paper2DAG import split_paper
|
| 3 |
+
from .paper2DAG import initialize_dag
|
| 4 |
+
from .paper2DAG import extract_and_generate_visual_dag
|
| 5 |
+
from .paper2DAG import add_resolution_to_visual_dag
|
| 6 |
+
from .paper2DAG import build_section_dags
|
| 7 |
+
from .paper2DAG import add_section_dag
|
| 8 |
+
from .paper2DAG import add_visual_dag
|
| 9 |
+
from .paper2DAG import add_section_dag
|
| 10 |
+
from .paper2DAG import refine_visual_node
|
| 11 |
+
|
| 12 |
+
from .DAG2ppt import generate_selected_nodes
|
| 13 |
+
from .DAG2ppt import outline_initialize
|
| 14 |
+
from .DAG2ppt import generate_complete_outline
|
| 15 |
+
from .DAG2ppt import arrange_template
|
| 16 |
+
from .DAG2ppt import generate_ppt
|
| 17 |
+
|
| 18 |
+
from .DAG2poster import generate_poster_outline_txt
|
| 19 |
+
from .DAG2poster import modify_poster_outline
|
| 20 |
+
from .DAG2poster import build_poster_from_outline
|
| 21 |
+
from .DAG2poster import modify_title_and_author
|
| 22 |
+
from .DAG2poster import inject_img_section_to_poster
|
| 23 |
+
from .DAG2poster import modified_poster_logic
|
| 24 |
+
|
| 25 |
+
from .DAG2pr import extract_basic_information
|
| 26 |
+
from .DAG2pr import initialize_pr_markdown
|
| 27 |
+
from .DAG2pr import generate_pr_from_dag
|
| 28 |
+
from .DAG2pr import add_title_and_hashtag
|
| 29 |
+
from .DAG2pr import add_institution_tag
|
| 30 |
+
from .DAG2pr import dedup_consecutive_markdown_images
|
| 31 |
+
|
| 32 |
+
from .refinement.refinement import refinement_ppt
|
| 33 |
+
from .refinement.refinement import refinement_poster
|
| 34 |
+
from .refinement.refinement import refinement_pr
|
src/__pycache__/DAG2poster.cpython-310.pyc
ADDED
|
Binary file (21.8 kB). View file
|
|
|
src/__pycache__/DAG2ppt.cpython-310.pyc
ADDED
|
Binary file (16 kB). View file
|
|
|
src/__pycache__/DAG2pr.cpython-310.pyc
ADDED
|
Binary file (24 kB). View file
|
|
|
src/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (1.47 kB). View file
|
|
|
src/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (1.64 kB). View file
|
|
|