import json import os from tqdm import tqdm import sys import copy from utils import extract_planning, content_to_json, extract_code_from_content,extract_code_from_content2, print_response, print_log_cost, load_accumulated_cost, save_accumulated_cost from transformers import AutoTokenizer from vllm import LLM, SamplingParams import argparse parser = argparse.ArgumentParser() parser.add_argument('--paper_name',type=str) parser.add_argument('--model_name',type=str, default="deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct") parser.add_argument('--tp_size',type=int, default=2) parser.add_argument('--temperature',type=float, default=1.0) parser.add_argument('--max_model_len',type=int, default=128000) parser.add_argument('--paper_format',type=str, default="JSON", choices=["JSON", "LaTeX"]) parser.add_argument('--pdf_json_path', type=str) # json format parser.add_argument('--pdf_latex_path', type=str) # latex format parser.add_argument('--output_dir',type=str, default="") parser.add_argument('--output_repo_dir',type=str, default="") args = parser.parse_args() paper_name = args.paper_name model_name = args.model_name tp_size = args.tp_size max_model_len = args.max_model_len temperature = args.temperature paper_format = args.paper_format pdf_json_path = args.pdf_json_path pdf_latex_path = args.pdf_latex_path output_dir = args.output_dir output_repo_dir = args.output_repo_dir if paper_format == "JSON": with open(f'{pdf_json_path}') as f: paper_content = json.load(f) elif paper_format == "LaTeX": with open(f'{pdf_latex_path}') as f: paper_content = f.read() else: print(f"[ERROR] Invalid paper format. Please select either 'JSON' or 'LaTeX.") sys.exit(0) with open(f'{output_dir}/planning_config.yaml') as f: config_yaml = f.read() context_lst = extract_planning(f'{output_dir}/planning_trajectories.json') # 0: overview, 1: detailed, 2: PRD # file_list = content_to_json(context_lst[1]) task_list = content_to_json(context_lst[2]) if 'Task list' in task_list: todo_file_lst = task_list['Task list'] elif 'task_list' in task_list: todo_file_lst = task_list['task_list'] elif 'task list' in task_list: todo_file_lst = task_list['task list'] else: print(f"[ERROR] 'Task list' does not exist. Please re-generate the planning.") sys.exit(0) done_file_lst = ['config.yaml'] done_file_dict = {} code_msg = [ {"role": "system", "content": f"""You are an expert researcher and software engineer with a deep understanding of experimental design and reproducibility in scientific research. You will receive a research paper in {paper_format} format, an overview of the plan, a Design in JSON format consisting of "Implementation approach", "File list", "Data structures and interfaces", and "Program call flow", followed by a Task in JSON format that includes "Required packages", "Required other language third-party packages", "Logic Analysis", and "Task list", along with a configuration file named "config.yaml". Your task is to write code to reproduce the experiments and methodologies described in the paper. The code you write must be elegant, modular, and maintainable, adhering to Google-style guidelines. The code must strictly align with the paper's methodology, experimental setup, and evaluation metrics. Write code with triple quoto."""}] def get_write_msg(todo_file_name, detailed_logic_analysis, done_file_lst): code_files = "" for done_file in done_file_lst: if done_file.endswith(".yaml"): continue code_files += f""" ```python {done_file_dict[done_file]} ``` """ write_msg=[ {'role': 'user', "content": f"""# Context ## Paper {paper_content} ----- ## Overview of the plan {context_lst[0]} ----- ## Design {context_lst[1]} ----- ## Task {context_lst[2]} ----- ## Configuration file ```yaml {config_yaml} ``` ----- ## Code Files {code_files} ----- # Format example ## Code: {todo_file_name} ```python ## {todo_file_name} ... ``` ----- # Instruction Based on the paper, plan, design, task and configuration file(config.yaml) specified previously, follow "Format example", write the code. We have {done_file_lst}. Next, you must write only the "{todo_file_name}". 1. Only One file: do your best to implement THIS ONLY ONE FILE. 2. COMPLETE CODE: Your code will be part of the entire project, so please implement complete, reliable, reusable code snippets. 3. Set default value: If there is any setting, ALWAYS SET A DEFAULT VALUE, ALWAYS USE STRONG TYPE AND EXPLICIT VARIABLE. AVOID circular import. 4. Follow design: YOU MUST FOLLOW "Data structures and interfaces". DONT CHANGE ANY DESIGN. Do not use public member functions that do not exist in your design. 5. CAREFULLY CHECK THAT YOU DONT MISS ANY NECESSARY CLASS/FUNCTION IN THIS FILE. 6. Before using a external variable/module, make sure you import it first. 7. Write out EVERY CODE DETAIL, DON'T LEAVE TODO. 8. REFER TO CONFIGURATION: you must use configuration from "config.yaml". DO NOT FABRICATE any configuration values. {detailed_logic_analysis} ## Code: {todo_file_name}"""}] return write_msg model_name = args.model_name tokenizer = AutoTokenizer.from_pretrained(model_name) if "Qwen" in model_name: llm = LLM(model=model_name, tensor_parallel_size=tp_size, max_model_len=max_model_len, gpu_memory_utilization=0.95, trust_remote_code=True, enforce_eager=True, rope_scaling={"factor": 4.0, "original_max_position_embeddings": 32768, "type": "yarn"}) sampling_params = SamplingParams(temperature=temperature, max_tokens=131072) elif "deepseek" in model_name: llm = LLM(model=model_name, tensor_parallel_size=tp_size, max_model_len=max_model_len, gpu_memory_utilization=0.95, trust_remote_code=True, enforce_eager=True) sampling_params = SamplingParams(temperature=temperature, max_tokens=128000, stop_token_ids=[tokenizer.eos_token_id]) def run_llm(msg): # vllm prompt_token_ids = [tokenizer.apply_chat_template(messages, add_generation_prompt=True) for messages in [msg]] outputs = llm.generate(prompt_token_ids=prompt_token_ids, sampling_params=sampling_params) completion = [output.outputs[0].text for output in outputs] return completion[0] # testing for checking detailed_logic_analysis_dict = {} retrieved_section_dict = {} for todo_file_name in todo_file_lst: # simple analysis save_todo_file_name = todo_file_name.replace("/", "_") if todo_file_name == "config.yaml": continue with open(f"{output_dir}/{save_todo_file_name}_simple_analysis_trajectories.json", encoding='utf8') as f: detailed_logic_analysis_trajectories = json.load(f) detailed_logic_analysis_dict[todo_file_name] = detailed_logic_analysis_trajectories[0]['content'] artifact_output_dir=f'{output_dir}/coding_artifacts' os.makedirs(artifact_output_dir, exist_ok=True) for todo_idx, todo_file_name in enumerate(tqdm(todo_file_lst)): responses = [] trajectories = copy.deepcopy(code_msg) current_stage = f"[CODING] {todo_file_name}" print(current_stage) if todo_file_name == "config.yaml": continue instruction_msg = get_write_msg(todo_file_name, detailed_logic_analysis_dict[todo_file_name], done_file_lst) trajectories.extend(instruction_msg) completion = run_llm(trajectories) # response completion_json = { 'text': completion } responses.append(completion_json) # trajectories trajectories.append({'role': 'assistant', 'content': completion}) done_file_lst.append(todo_file_name) # save # save_dir_name = f"{paper_name}_repo" os.makedirs(f'{output_repo_dir}', exist_ok=True) save_todo_file_name = todo_file_name.replace("/", "_") # print and logging print_response(completion_json, is_llm=True) # save artifacts with open(f'{artifact_output_dir}/{save_todo_file_name}_coding.txt', 'w', encoding='utf-8') as f: f.write(completion) # extract code save try: code = extract_code_from_content(completion) except Exception as e: code = extract_code_from_content2(completion) if len(code) == 0: code = completion done_file_dict[todo_file_name] = code if save_todo_file_name != todo_file_name: todo_file_dir = '/'.join(todo_file_name.split("/")[:-1]) os.makedirs(f"{output_repo_dir}/{todo_file_dir}", exist_ok=True) with open(f"{output_repo_dir}/{todo_file_name}", 'w', encoding='utf-8') as f: f.write(code)