diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..df82b804c89f42dd0e2768b30ad3d804ec7435ba 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +poster_template/expore_our_work_in_detail.jpg filter=lfs diff=lfs merge=lfs -text +ppt_template/images/2.png filter=lfs diff=lfs merge=lfs -text +ppt_template/images/4.png filter=lfs diff=lfs merge=lfs -text +ppt_template/images/7.png filter=lfs diff=lfs merge=lfs -text +ppt_template/images/t_2.png filter=lfs diff=lfs merge=lfs -text diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..980ab8d30727e81e6b31e01317e0d1d13967f129 --- /dev/null +++ b/config.yaml @@ -0,0 +1,12 @@ +# 项目基础设置 +path: + root_folder: "./mineru_outputs" + +# 模型相关设置 +model_settings: + generation_model: "gemini-3-pro-preview" + +# 敏感信息(建议通过环境变量读取,或仅在本地调试时填写) +api_keys: + gemini_api_key: "" + openai_api_key: "" diff --git a/main.py b/main.py new file mode 100644 index 0000000000000000000000000000000000000000..55bd6f401660c5de17bcaba982a776ad1559f6b4 --- /dev/null +++ b/main.py @@ -0,0 +1,250 @@ +import json +import os +from pathlib import Path + +from src import * + +import yaml +import os + +# ============= 读取配置 =============== +def load_config(config_path="config.yaml"): + with open(config_path, "r", encoding="utf-8") as f: + config = yaml.safe_load(f) + return config + +# ========== 读取 prompt 模板 ========== +def load_prompt(prompt_path="prompt.json", prompt_name="poster_prompt"): + with open(prompt_path, "r", encoding="utf-8") as f: + data = json.load(f) + return data.get(prompt_name, "") + +# 应用配置 +config = load_config() + +model_name = config['model_settings']['generation_model'] + +# ========== 主流程 ========== +def main(): + # 输入总文件夹路径(包含多个论文子文件夹) + root_folder = config['path']['root_folder'] # ⚠️ 修改为你的实际路径 + prompt_path = "prompt.json" + + + print("📘 Loading prompts...") + # dag prompt: + section_split_prompt = load_prompt(prompt_path, prompt_name="section_split_prompt") + clean_prompt = load_prompt(prompt_path, prompt_name="clean_prompt") + initialize_dag_prompt = load_prompt(prompt_path, prompt_name="initialize_dag_prompt") + visual_dag_prompt = load_prompt(prompt_path, prompt_name="visual_dag_prompt") + section_dag_generation_prompt = load_prompt(prompt_path, prompt_name="section_dag_generation_prompt") + + # ppt prompt: + outline_initialize_prompt = load_prompt(prompt_path, prompt_name="outline_initialize_prompt") + generate_complete_outline_prompt = load_prompt(prompt_path, prompt_name="generate_complete_outline_prompt") + arrange_template_prompt= load_prompt(prompt_path, prompt_name="arrange_template_prompt") + commenter_prompt= load_prompt(prompt_path, prompt_name="commenter_prompt") + reviser_prompt= load_prompt(prompt_path, prompt_name="reviser_prompt") + + # poster prompt: + poster_outline_prompt= load_prompt(prompt_path, prompt_name="poster_outline_prompt") + poster_refinement_prompt= load_prompt(prompt_path, prompt_name="poster_refinement_prompt") + modified_poster_logic_prompt=load_prompt(prompt_path, prompt_name="modified_poster_logic_prompt") + + # pr prompt: + extract_basic_information_prompt = load_prompt("prompt.json", "extract_basic_information_prompt") + generate_pr_prompt = load_prompt(prompt_path, prompt_name="generate_pr_prompt") + add_title_and_hashtag_prompt = load_prompt(prompt_path, prompt_name="add_title_and_hashtag_prompt") + pr_refinement_prompt = load_prompt(prompt_path, prompt_name="pr_refinement_prompt") + + + + + # === 遍历每个子文件夹 === + for subdir in os.listdir(root_folder): + subdir_path = os.path.join(root_folder, subdir) + auto_path = os.path.join(subdir_path, "auto") # ✅ 进入 auto 子文件夹 + + if not os.path.isdir(auto_path): + print(f"⚠️ No 'auto' folder found in {subdir_path}, skipping...") + continue # 只处理存在 auto 文件夹的目录 + + # ✅ 如果 success.txt 已存在,跳过该目录 + success_flag = os.path.join(auto_path, "success.txt") + if os.path.isfile(success_flag): + print(f"✅ success.txt exists in {auto_path}, skipping...") + continue + + print(f"\n🚀 Processing paper folder: {auto_path}") + + # === 根据子文件夹名精确匹配文件 === + target_pdf = f"{subdir}_origin.pdf" + target_md = f"{subdir}.md" + + pdf_path = os.path.join(auto_path, target_pdf) + md_path = os.path.join(auto_path, target_md) + + # === 检查文件是否存在 === + if not os.path.exists(pdf_path): + print(f"⚠️ Missing expected PDF: {target_pdf} in {auto_path}, skipping...") + continue + if not os.path.exists(md_path): + print(f"⚠️ Missing expected Markdown: {target_md} in {auto_path}, skipping...") + continue + + print(f"📄 Matched files:\n PDF: {target_pdf}\n MD: {target_md}") + + # === 输出文件路径 === + output_html = os.path.join(auto_path, "poster.html") + graph_json_path = os.path.join(auto_path, "graph.json") + + # === 清理 markdown === 去除无意义的段落,如relative work,reference,appendix等等 + print("🧹 Cleaning markdown before splitting...") + cleaned_md_path = clean_paper(md_path, clean_prompt, model="gemini-3-pro-preview", config=config) + + # === 利用gpt将论文分段 === + paths = split_paper(cleaned_md_path, section_split_prompt, model="gemini-3-pro-preview" ,config=config) + + # === 利用gpt初始化dag === + dag = initialize_dag(markdown_path=cleaned_md_path,initialize_dag_prompt=initialize_dag_prompt,model="gemini-3-pro-preview", config=config) + dag_path = os.path.join(auto_path, "dag.json") + + + # === 生成visual_dag === + visual_dag_path=os.path.join(auto_path, "visual_dag.json") + 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) + add_resolution_to_visual_dag(auto_path, visual_dag_path) + + # === 生成section_dag === + section_split_output_path=os.path.join(subdir_path, "section_split_output") + build_section_dags(folder_path=section_split_output_path,base_prompt=section_dag_generation_prompt,model="gemini-3-pro-preview", config=config) + + + # === 向dag.json添加section_dag === + section_dag_path=os.path.join(subdir_path, "section_dag") + merged_path = add_section_dag(section_dag_folder=section_dag_path,main_dag_path=dag_path,output_path=None) + + # === 向dag.json添加visual_dag === + add_visual_dag(dag_path=dag_path,visual_dag_path=visual_dag_path) + + # === 完善dag中每一个结点的visual_node === + refine_visual_node(dag_path) + + + + + # ============================= PPT部分 ================================ + + # === 按照算法选出结点,以便后续生成outline === + selected_node_path=os.path.join(auto_path, "selected_node.json") + generate_selected_nodes(dag_json_path=dag_path, max_len=15,output_path=selected_node_path) + + # === 初始化ouline === + outline_path= os.path.join(auto_path, "outline.json") + outline = outline_initialize(dag_json_path=dag_path,outline_initialize_prompt=outline_initialize_prompt,model=model_name, config=config) + + # === 生成完整ouline === + outline_data=generate_complete_outline(selected_node_path,outline_path,generate_complete_outline_prompt,model=model_name, config=config) + + # === 配模板 === + arrange_template(outline_path,arrange_template_prompt,model=model_name, config=config) + + # === 生成最终的PPT === + ppt_template_path="./ppt_template" + 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 . 2) For 'Subjects' sections: replace the placeholder title with ONE concise summary sentence for this slide. 3) For 'Image' sections (): replace src with the relative path extracted from node.figure/formula[i].name; the node image name may be markdown like '![](images/abc.jpg)', 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

,