|
import argparse |
|
import json |
|
import os |
|
import os.path as osp |
|
import re |
|
import shutil |
|
import subprocess |
|
from typing import Optional, Tuple |
|
|
|
from strictjson import strict_json |
|
|
|
from ai_scientist.generate_ideas import search_for_papers |
|
from ai_scientist.llm import ( |
|
allchoices, |
|
extract_json_between_markers, |
|
get_response_from_llm, |
|
llm_json_auto_correct, |
|
) |
|
|
|
|
|
def format_citation_first_json(text): |
|
res = strict_json( |
|
system_prompt="You are a JSON formatter", |
|
user_prompt=text, |
|
return_as_json=True, |
|
output_format={ |
|
"Description": "A precise description of the required edit, along with the proposed text and location where it should be made", |
|
"Query": "The search query to find the paper (e.g. attention is all you need)", |
|
}, |
|
llm=llm_json_auto_correct, |
|
) |
|
text = json.loads(res) |
|
return text |
|
|
|
|
|
def format_citation_second_json(text): |
|
res = strict_json( |
|
system_prompt="You are a JSON formatter", |
|
user_prompt=text, |
|
return_as_json=True, |
|
output_format={ |
|
"Selected": "A list of the indices of the selected papers to be cited, e.g. '[0, 1]'. Can be '[]' if no papers are selected. This must be a string", |
|
"Description": "Update the previous description of the required edit if needed. Ensure that any cites precisely match the name in the bibtex", |
|
}, |
|
llm=llm_json_auto_correct, |
|
) |
|
text = json.loads(res) |
|
return text |
|
|
|
|
|
|
|
def generate_latex(coder, folder_name, pdf_file, timeout=30, num_error_corrections=5): |
|
folder = osp.abspath(folder_name) |
|
cwd = osp.join(folder, "latex") |
|
writeup_file = osp.join(cwd, "template.tex") |
|
|
|
|
|
with open(writeup_file, "r") as f: |
|
tex_text = f.read() |
|
cites = re.findall(r"\\cite[a-z]*{([^}]*)}", tex_text) |
|
references_bib = re.search( |
|
r"\\begin{filecontents}{references.bib}(.*?)\\end{filecontents}", |
|
tex_text, |
|
re.DOTALL, |
|
) |
|
if references_bib is None: |
|
print("No references.bib found in template.tex") |
|
return |
|
bib_text = references_bib.group(1) |
|
cites = [cite.strip() for item in cites for cite in item.split(",")] |
|
for cite in cites: |
|
if cite not in bib_text: |
|
print(f"Reference {cite} not found in references.") |
|
prompt = f"""Reference {cite} not found in references.bib. Is this included under a different name? |
|
If so, please modify the citation in template.tex to match the name in references.bib at the top. Otherwise, remove the cite.""" |
|
coder.run(prompt) |
|
|
|
|
|
with open(writeup_file, "r") as f: |
|
tex_text = f.read() |
|
referenced_figs = re.findall(r"\\includegraphics.*?{(.*?)}", tex_text) |
|
all_figs = [f for f in os.listdir(folder) if f.endswith(".png")] |
|
for figure in referenced_figs: |
|
if figure not in all_figs: |
|
print(f"Figure {figure} not found in directory.") |
|
prompt = f"""The image {figure} not found in the directory. The images in the directory are: {all_figs}. |
|
Please ensure that the figure is in the directory and that the filename is correct. Check the notes to see what each figure contains.""" |
|
coder.run(prompt) |
|
|
|
|
|
with open(writeup_file, "r") as f: |
|
tex_text = f.read() |
|
referenced_figs = re.findall(r"\\includegraphics.*?{(.*?)}", tex_text) |
|
duplicates = {x for x in referenced_figs if referenced_figs.count(x) > 1} |
|
if duplicates: |
|
for dup in duplicates: |
|
print(f"Duplicate figure found: {dup}.") |
|
prompt = f"""Duplicate figures found: {dup}. Ensure any figure is only included once. |
|
If duplicated, identify the best location for the figure and remove any other.""" |
|
coder.run(prompt) |
|
|
|
|
|
with open(writeup_file, "r") as f: |
|
tex_text = f.read() |
|
sections = re.findall(r"\\section{([^}]*)}", tex_text) |
|
duplicates = {x for x in sections if sections.count(x) > 1} |
|
if duplicates: |
|
for dup in duplicates: |
|
print(f"Duplicate section header found: {dup}") |
|
prompt = f"""Duplicate section header found: {dup}. Ensure any section header is declared once. |
|
If duplicated, identify the best location for the section header and remove any other.""" |
|
coder.run(prompt) |
|
|
|
|
|
for i in range(num_error_corrections): |
|
|
|
check_output = os.popen(f"chktex {writeup_file} -q -n2 -n24 -n13 -n1").read() |
|
if check_output: |
|
prompt = f"""Please fix the following LaTeX errors in `template.tex` guided by the output of `chktek`: |
|
{check_output}. |
|
|
|
Make the minimal fix required and do not remove or change any packages. |
|
Pay attention to any accidental uses of HTML syntax, e.g. </end instead of \\end. |
|
""" |
|
coder.run(prompt) |
|
else: |
|
break |
|
compile_latex(cwd, pdf_file, timeout=timeout) |
|
|
|
|
|
def compile_latex(cwd, pdf_file, timeout=30): |
|
print("GENERATING LATEX") |
|
|
|
commands = [ |
|
["pdflatex", "-interaction=nonstopmode", "template.tex"], |
|
["bibtex", "template"], |
|
["pdflatex", "-interaction=nonstopmode", "template.tex"], |
|
["pdflatex", "-interaction=nonstopmode", "template.tex"], |
|
] |
|
|
|
for command in commands: |
|
try: |
|
result = subprocess.run( |
|
command, |
|
cwd=cwd, |
|
stdout=subprocess.PIPE, |
|
stderr=subprocess.PIPE, |
|
text=True, |
|
timeout=timeout, |
|
) |
|
print("Standard Output:\n", result.stdout) |
|
print("Standard Error:\n", result.stderr) |
|
except subprocess.TimeoutExpired: |
|
print(f"Latex timed out after {timeout} seconds") |
|
except subprocess.CalledProcessError as e: |
|
print(f"Error running command {' '.join(command)}: {e}") |
|
|
|
print("FINISHED GENERATING LATEX") |
|
|
|
|
|
try: |
|
shutil.move(osp.join(cwd, "template.pdf"), pdf_file) |
|
except FileNotFoundError: |
|
print("Failed to rename PDF.") |
|
|
|
|
|
per_section_tips = { |
|
"Abstract": """ |
|
- TL;DR of the paper |
|
- What are we trying to do and why is it relevant? |
|
- Why is this hard? |
|
- How do we solve it (i.e. our contribution!) |
|
- How do we verify that we solved it (e.g. Experiments and results) |
|
|
|
Please make sure the abstract reads smoothly and is well-motivated. This should be one continuous paragraph with no breaks between the lines. |
|
""", |
|
"Introduction": """ |
|
- Longer version of the Abstract, i.e. of the entire paper |
|
- What are we trying to do and why is it relevant? |
|
- Why is this hard? |
|
- How do we solve it (i.e. our contribution!) |
|
- How do we verify that we solved it (e.g. Experiments and results) |
|
- New trend: specifically list your contributions as bullet points |
|
- Extra space? Future work! |
|
""", |
|
"Related Work": """ |
|
- Academic siblings of our work, i.e. alternative attempts in literature at trying to solve the same problem. |
|
- Goal is to “Compare and contrast” - how does their approach differ in either assumptions or method? If their method is applicable to our Problem Setting I expect a comparison in the experimental section. If not, there needs to be a clear statement why a given method is not applicable. |
|
- Note: Just describing what another paper is doing is not enough. We need to compare and contrast. |
|
""", |
|
"Background": """ |
|
- Academic Ancestors of our work, i.e. all concepts and prior work that are required for understanding our method. |
|
- Usually includes a subsection, Problem Setting, which formally introduces the problem setting and notation (Formalism) for our method. Highlights any specific assumptions that are made that are unusual. |
|
- Note: If our paper introduces a novel problem setting as part of its contributions, it's best to have a separate Section. |
|
""", |
|
"Method": """ |
|
- What we do. Why we do it. All described using the general Formalism introduced in the Problem Setting and building on top of the concepts / foundations introduced in Background. |
|
""", |
|
"Experimental Setup": """ |
|
- How do we test that our stuff works? Introduces a specific instantiation of the Problem Setting and specific implementation details of our Method for this Problem Setting. |
|
- Do not imagine unknown hardware details. |
|
- Includes a description of the dataset, evaluation metrics, important hyperparameters, and implementation details. |
|
""", |
|
"Results": """ |
|
- Shows the results of running Method on our problem described in Experimental Setup. |
|
- Includes statements on hyperparameters and other potential issues of fairness. |
|
- Only includes results that have actually been run and saved in the logs. Do not hallucinate results that don't exist. |
|
- If results exist: compares to baselines and includes statistics and confidence intervals. |
|
- If results exist: includes ablation studies to show that specific parts of the method are relevant. |
|
- Discusses limitations of the method. |
|
- Make sure to include all the results from the experiments, and include all relevant figures. |
|
""", |
|
"Conclusion": """ |
|
- Brief recap of the entire paper. |
|
- To keep going with the analogy, you can think of future work as (potential) academic offspring. |
|
""", |
|
} |
|
|
|
error_list = """- Unenclosed math symbols |
|
- Only reference figures that exist in our directory |
|
- LaTeX syntax errors |
|
- Numerical results that do not come from explicit experiments and logs |
|
- Repeatedly defined figure labels |
|
- References to papers that are not in the .bib file, DO NOT ADD ANY NEW CITATIONS! |
|
- Unnecessary verbosity or repetition, unclear text |
|
- Results or insights in the `notes.txt` that have not yet need included |
|
- Any relevant figures that have not yet been included in the text |
|
- Closing any \\begin{{figure}} with a \\end{{figure}} and \\begin{{table}} with a \\end{{table}}, etc. |
|
- Duplicate headers, e.g. duplicated \\section{{Introduction}} or \\end{{document}} |
|
- Unescaped symbols, e.g. shakespeare_char should be shakespeare\\_char in text |
|
- Incorrect closing of environments, e.g. </end{{figure}}> instead of \\end{{figure}} |
|
""" |
|
|
|
refinement_prompt = ( |
|
"""Great job! Now criticize and refine only the {section} that you just wrote. |
|
Make this complete in this pass, do not leave any placeholders. |
|
|
|
Pay particular attention to fixing any errors such as: |
|
""" |
|
+ error_list |
|
) |
|
|
|
second_refinement_prompt = ( |
|
"""Criticize and refine the {section} only. Recall the advice: |
|
{tips} |
|
Make this complete in this pass, do not leave any placeholders. |
|
|
|
Pay attention to how it fits in with the rest of the paper. |
|
Identify any redundancies (e.g. repeated figures or repeated text), if there are any, decide where in the paper things should be cut. |
|
Identify where we can save space, and be more concise without weakening the message of the text. |
|
Fix any remaining errors as before: |
|
""" |
|
+ error_list |
|
) |
|
|
|
|
|
citation_system_msg = """You are an ambitious AI PhD student who is looking to publish a paper that will contribute significantly to the field. |
|
You have already written an initial draft of the paper and now you are looking to add missing citations to related papers throughout the paper. |
|
The related work section already has some initial comments on which papers to add and discuss. |
|
|
|
Focus on completing the existing write-up and do not add entirely new elements unless necessary. |
|
Ensure every point in the paper is substantiated with sufficient evidence. |
|
Feel free to add more cites to a particular point if there is only one or two references. |
|
Ensure no paper is cited without a corresponding reference in the `references.bib` file. |
|
Ensure each paragraph of the related work has sufficient background, e.g. a few papers cited. |
|
You will be given access to the Semantic Scholar API, only add citations that you have found using the API. |
|
Aim to discuss a broad range of relevant papers, not just the most popular ones. |
|
Make sure not to copy verbatim from prior literature to avoid plagiarism. |
|
|
|
You will be prompted to give a precise description of where and how to add the cite, and a search query for the paper to be cited. |
|
Finally, you will select the most relevant cite from the search results (top 10 results will be shown). |
|
You will have {total_rounds} rounds to add to the references, but do not need to use them all. |
|
|
|
DO NOT ADD A CITATION THAT ALREADY EXISTS!""" |
|
|
|
citation_first_prompt = '''Round {current_round}/{total_rounds}: |
|
|
|
You have written this LaTeX draft so far: |
|
|
|
""" |
|
{draft} |
|
""" |
|
|
|
Identify the most important citation that you still need to add, and the query to find the paper. |
|
|
|
Respond in the following format: |
|
|
|
THOUGHT: |
|
<THOUGHT> |
|
|
|
RESPONSE: |
|
```json |
|
<JSON> |
|
``` |
|
|
|
In <THOUGHT>, first briefly reason over the paper and identify where citations should be added. |
|
If no more citations are needed, add "No more citations needed" to your thoughts. |
|
Do not add "No more citations needed" if you are adding citations this round. |
|
|
|
In <JSON>, respond in JSON format with the following fields: |
|
- "Description": A precise description of the required edit, along with the proposed text and location where it should be made. |
|
- "Query": The search query to find the paper (e.g. attention is all you need). |
|
|
|
Ensure the description is sufficient to make the change without further context. Someone else will make the change. |
|
The query will work best if you are able to recall the exact name of the paper you are looking for, or the authors. |
|
This JSON will be automatically parsed, so ensure the format is precise.''' |
|
|
|
citation_second_prompt = """Search has recovered the following articles: |
|
|
|
{papers} |
|
|
|
Respond in the following format: |
|
|
|
THOUGHT: |
|
<THOUGHT> |
|
|
|
RESPONSE: |
|
```json |
|
<JSON> |
|
``` |
|
|
|
In <THOUGHT>, first briefly reason over the search results and identify which citation best fits your paper and the location is to be added at. |
|
If none are appropriate, add "Do not add any" to your thoughts. |
|
|
|
In <JSON>, respond in JSON format with the following fields: |
|
- "Selected": A list of the indices of the selected papers to be cited, e.g. "[0, 1]". Can be "[]" if no papers are selected. This must be a string. |
|
- "Description": Update the previous description of the required edit if needed. Ensure that any cites precisely match the name in the bibtex!!! |
|
|
|
Do not select papers that are already in the `references.bib` file at the top of the draft, or if the same citation exists under a different name. |
|
This JSON will be automatically parsed, so ensure the format is precise.""" |
|
|
|
|
|
def get_citation_aider_prompt( |
|
client, model, draft, current_round, total_rounds |
|
) -> Tuple[Optional[str], bool]: |
|
msg_history = [] |
|
try: |
|
text, msg_history = get_response_from_llm( |
|
citation_first_prompt.format( |
|
draft=draft, current_round=current_round, total_rounds=total_rounds |
|
), |
|
client=client, |
|
model=model, |
|
system_message=citation_system_msg.format(total_rounds=total_rounds), |
|
msg_history=msg_history, |
|
) |
|
if "No more citations needed" in text: |
|
print("No more citations needed.") |
|
return None, True |
|
|
|
|
|
json_output = format_citation_first_json(text) |
|
assert json_output is not None, "Failed to extract JSON from LLM output" |
|
query = json_output["Query"] |
|
papers = search_for_papers(query) |
|
except Exception as e: |
|
print(f"Error: {e}") |
|
return None, False |
|
|
|
if papers is None: |
|
print("No papers found.") |
|
return None, False |
|
|
|
paper_strings = [] |
|
for i, paper in enumerate(papers): |
|
paper_strings.append( |
|
"""{i}: {title}. {authors}. {venue}, {year}.\nAbstract: {abstract}""".format( |
|
i=i, |
|
title=paper["title"], |
|
authors=paper["authors"], |
|
venue=paper["venue"], |
|
year=paper["year"], |
|
abstract=paper["abstract"], |
|
) |
|
) |
|
papers_str = "\n\n".join(paper_strings) |
|
|
|
try: |
|
text, msg_history = get_response_from_llm( |
|
citation_second_prompt.format( |
|
papers=papers_str, |
|
current_round=current_round, |
|
total_rounds=total_rounds, |
|
), |
|
client=client, |
|
model=model, |
|
system_message=citation_system_msg.format(total_rounds=total_rounds), |
|
msg_history=msg_history, |
|
) |
|
if "Do not add any" in text: |
|
print("Do not add any.") |
|
return None, False |
|
|
|
json_output = format_citation_second_json(text) |
|
assert json_output is not None, "Failed to extract JSON from LLM output" |
|
desc = json_output["Description"] |
|
selected_papers = json_output["Selected"] |
|
selected_papers = str(selected_papers) |
|
|
|
|
|
if selected_papers != "[]": |
|
selected_papers = list(map(int, selected_papers.strip("[]").split(","))) |
|
assert all( |
|
[0 <= i < len(papers) for i in selected_papers] |
|
), "Invalid paper index" |
|
bibtexs = [papers[i]["citationStyles"]["bibtex"] for i in selected_papers] |
|
bibtex_string = "\n".join(bibtexs) |
|
else: |
|
return None, False |
|
|
|
except Exception as e: |
|
print(f"Error: {e}") |
|
return None, False |
|
|
|
|
|
aider_format = '''The following citations have just been added to the end of the `references.bib` file definition at the top of the file: |
|
""" |
|
{bibtex} |
|
""" |
|
You do not need to add them yourself. |
|
ABSOLUTELY DO NOT ADD IT AGAIN!!! |
|
|
|
Make the proposed change to the draft incorporating these new cites: |
|
{description} |
|
|
|
Use your judgment for whether these should be cited anywhere else. |
|
Make sure that any citation precisely matches the name in `references.bib`. Change its name to the correct name in the bibtex if needed. |
|
Ensure the citation is well-integrated into the text.''' |
|
|
|
aider_prompt = ( |
|
aider_format.format(bibtex=bibtex_string, description=desc) |
|
+ """\n You must use \cite or \citet to reference papers, do not manually type out author names.""" |
|
) |
|
return aider_prompt, False |
|
|
|
|
|
|
|
def perform_writeup( |
|
idea, folder_name, coder, cite_client, cite_model, num_cite_rounds=20 |
|
): |
|
|
|
abstract_prompt = f"""We've provided the `latex/template.tex` file to the project. We will be filling it in section by section. |
|
|
|
First, please fill in the "Title" and "Abstract" sections of the writeup. |
|
|
|
Some tips are provided below: |
|
{per_section_tips["Abstract"]} |
|
|
|
Before every paragraph, please include a brief description of what you plan to write in that paragraph in a comment. |
|
|
|
Be sure to first name the file and use *SEARCH/REPLACE* blocks to perform these edits. |
|
""" |
|
coder_out = coder.run(abstract_prompt) |
|
coder_out = coder.run( |
|
refinement_prompt.format(section="Abstract") |
|
.replace(r"{{", "{") |
|
.replace(r"}}", "}") |
|
) |
|
for section in [ |
|
"Introduction", |
|
"Background", |
|
"Method", |
|
"Experimental Setup", |
|
"Results", |
|
"Conclusion", |
|
]: |
|
section_prompt = f"""Please fill in the {section} of the writeup. Some tips are provided below: |
|
{per_section_tips[section]} |
|
|
|
Be sure to use \cite or \citet where relevant, referring to the works provided in the file. |
|
Do not cite anything that is not already in `references.bib`. Do not add any new entries to this. |
|
|
|
Keep the experimental results (figures and tables) only in the Results section, and make sure that any captions are filled in. |
|
In this pass, do not reference anything in later sections of the paper. |
|
|
|
Before every paragraph, please include a brief description of what you plan to write in that paragraph in a comment. |
|
|
|
Be sure to first name the file and use *SEARCH/REPLACE* blocks to perform these edits. |
|
""" |
|
coder_out = coder.run(section_prompt) |
|
coder_out = coder.run( |
|
refinement_prompt.format(section=section) |
|
.replace(r"{{", "{") |
|
.replace(r"}}", "}") |
|
) |
|
|
|
|
|
section_prompt = f"""Please fill in the Related Work of the writeup. Some tips are provided below: |
|
|
|
{per_section_tips["Related Work"]} |
|
|
|
For this section, very briefly sketch out the structure of the section, and clearly indicate what papers you intend to include. |
|
Do this all in LaTeX comments using %. |
|
The related work should be concise, only plan to discuss the most relevant work. |
|
Do not modify `references.bib` to add any new citations, this will be filled in at a later stage. |
|
|
|
Be sure to first name the file and use *SEARCH/REPLACE* blocks to perform these edits. |
|
""" |
|
coder_out = coder.run(section_prompt) |
|
|
|
|
|
for _ in range(num_cite_rounds): |
|
with open(osp.join(folder_name, "latex", "template.tex"), "r") as f: |
|
draft = f.read() |
|
prompt, done = get_citation_aider_prompt( |
|
cite_client, cite_model, draft, _, num_cite_rounds |
|
) |
|
if done: |
|
break |
|
if prompt is not None: |
|
|
|
bibtex_string = prompt.split('"""')[1] |
|
|
|
search_str = r"\end{filecontents}" |
|
draft = draft.replace(search_str, f"{bibtex_string}{search_str}") |
|
with open(osp.join(folder_name, "latex", "template.tex"), "w") as f: |
|
f.write(draft) |
|
coder_out = coder.run(prompt) |
|
|
|
coder_out = coder.run( |
|
refinement_prompt.format(section="Related Work") |
|
.replace(r"{{", "{") |
|
.replace(r"}}", "}") |
|
) |
|
|
|
|
|
coder.run( |
|
"""Great job! Now that there is a complete draft of the entire paper, let's refine each section again. |
|
First, re-think the Title if necessary. Keep this concise and descriptive of the paper's concept, but try by creative with it.""" |
|
) |
|
for section in [ |
|
"Abstract", |
|
"Related Work", |
|
"Introduction", |
|
"Background", |
|
"Method", |
|
"Experimental Setup", |
|
"Results", |
|
"Conclusion", |
|
]: |
|
coder_out = coder.run( |
|
second_refinement_prompt.format( |
|
section=section, tips=per_section_tips[section] |
|
) |
|
.replace(r"{{", "{") |
|
.replace(r"}}", "}") |
|
) |
|
|
|
generate_latex(coder, folder_name, f"{folder_name}/{idea['Name']}.pdf") |
|
|
|
|
|
if __name__ == "__main__": |
|
import json |
|
|
|
from aider.coders import Coder |
|
from aider.io import InputOutput |
|
from aider.models import Model |
|
|
|
parser = argparse.ArgumentParser(description="Perform writeup for a project") |
|
parser.add_argument("--folder", type=str) |
|
parser.add_argument("--no-writing", action="store_true", help="Only generate") |
|
parser.add_argument( |
|
"--model", |
|
type=str, |
|
default="gpt-4o-2024-05-13", |
|
choices=allchoices, |
|
help="Model to use for AI Scientist.", |
|
) |
|
args = parser.parse_args() |
|
if args.model == "claude-3-5-sonnet-20240620": |
|
import anthropic |
|
|
|
print(f"Using Anthropic API with model {args.model}.") |
|
client_model = "claude-3-5-sonnet-20240620" |
|
client = anthropic.Anthropic() |
|
elif args.model.startswith("bedrock") and "claude" in args.model: |
|
import anthropic |
|
|
|
|
|
client_model = args.model.split("/")[-1] |
|
|
|
print(f"Using Amazon Bedrock with model {client_model}.") |
|
client = anthropic.AnthropicBedrock() |
|
elif args.model.startswith("vertex_ai") and "claude" in args.model: |
|
import anthropic |
|
|
|
|
|
client_model = args.model.split("/")[-1] |
|
|
|
print(f"Using Vertex AI with model {client_model}.") |
|
client = anthropic.AnthropicVertex() |
|
elif args.model == "gpt-4o-2024-05-13": |
|
import openai |
|
|
|
print(f"Using OpenAI API with model {args.model}.") |
|
client_model = "gpt-4o-2024-05-13" |
|
client = openai.OpenAI() |
|
elif args.model == "deepseek-coder-v2-0724": |
|
import openai |
|
|
|
print(f"Using OpenAI API with {args.model}.") |
|
client_model = "deepseek-coder-v2-0724" |
|
client = openai.OpenAI( |
|
api_key=os.environ["DEEPSEEK_API_KEY"], base_url="https://api.deepseek.com" |
|
) |
|
|
|
|
|
|
|
elif args.model == "Qwen/Qwen2.5-72B-Instruct": |
|
|
|
print(f"Welcome to the PARADISE of debug <launch_scientist.py> {args.model}.") |
|
|
|
import openai |
|
import os |
|
|
|
client_model = args.model |
|
client = openai.OpenAI( |
|
api_key=os.environ["OPENAI_API_KEY"], base_url="https://api.hyperbolic.xyz/v1" |
|
) |
|
|
|
elif args.model == "llama3.1-405b": |
|
import openai |
|
|
|
print(f"Using OpenAI API with {args.model}.") |
|
client_model = "meta-llama/llama-3.1-405b-instruct" |
|
client = openai.OpenAI( |
|
api_key=os.environ["OPENROUTER_API_KEY"], |
|
base_url="https://openrouter.ai/api/v1", |
|
) |
|
|
|
elif args.model.startswith("ollama"): |
|
import openai |
|
|
|
print(f"Using Ollama with {args.model}.") |
|
client_model = args.model.split("/")[-1] |
|
client = openai.OpenAI(api_key="ollama", base_url="http://localhost:11434/v1") |
|
else: |
|
raise ValueError(f"Model {args.model} not recognized.") |
|
|
|
|
|
print("Make sure you cleaned the Aider logs if re-generating the writeup!") |
|
folder_name = args.folder |
|
idea_name = osp.basename(folder_name) |
|
exp_file = osp.join(folder_name, "experiment.py") |
|
vis_file = osp.join(folder_name, "plot.py") |
|
notes = osp.join(folder_name, "notes.txt") |
|
|
|
model = args.model |
|
|
|
writeup_file = osp.join(folder_name, "latex", "template.tex") |
|
ideas_file = osp.join(folder_name, "ideas.json") |
|
with open(ideas_file, "r") as f: |
|
ideas = json.load(f) |
|
for idea in ideas: |
|
if idea["Name"] in idea_name: |
|
print(f"Found idea: {idea['Name']}") |
|
break |
|
if idea["Name"] not in idea_name: |
|
raise ValueError(f"Idea {idea_name} not found") |
|
fnames = [exp_file, writeup_file, notes] |
|
io = InputOutput(yes=True, chat_history_file=f"{folder_name}/{idea_name}_aider.txt") |
|
|
|
|
|
|
|
|
|
|
|
if args.model == "deepseek-ai/DeepSeek-V2.5": |
|
print("aider chosen deepseek") |
|
main_model = Model("deepseek-chat") |
|
|
|
elif args.model == "deepseek-coder-v2-0724": |
|
main_model = Model("deepseek-ai/DeepSeek-V2.5") |
|
|
|
elif args.model == "llama3.1-405b": |
|
main_model = Model("openrouter/meta-llama/llama-3.1-405b-instruct") |
|
|
|
|
|
|
|
elif args.model == "hyperbolic/Qwen/Qwen2.5-72B-Instruct": |
|
print("aider model chosen") |
|
|
|
main_model = Model("hyperbolic/Qwen/Qwen2.5-72B-Instruct") |
|
|
|
elif args.model == "hyperbolic/meta-llama/Meta-Llama-3.1-70B-Instruct": |
|
main_model = Model("hyperbolic/meta-llama/Meta-Llama-3.1-70B-Instruct") |
|
|
|
|
|
|
|
else: |
|
print("hello world") |
|
main_model = Model(model) |
|
|
|
coder = Coder.create( |
|
main_model=main_model, |
|
fnames=fnames, |
|
io=io, |
|
stream=False, |
|
use_git=False, |
|
edit_format="diff", |
|
) |
|
if args.no_writing: |
|
generate_latex(coder, args.folder, f"{args.folder}/test.pdf") |
|
else: |
|
try: |
|
perform_writeup(idea, folder_name, coder, client, client_model) |
|
except Exception as e: |
|
print(f"Failed to perform writeup: {e}") |