Skip to content

Commit

Permalink
Improve flow for -i flag (AntonOsika#652)
Browse files Browse the repository at this point in the history
* Update readme and docs

* Update docs

* Update docs

* Improve the way improve command is used

* Fix missing fstring
  • Loading branch information
AntonOsika authored and 70ziko committed Oct 25, 2023
1 parent 98a1ba2 commit bb420af
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 65 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

GPT Engineer is made to be easy to adapt, extend, and make your agent learn how you want your code to look. It generates an entire codebase based on a prompt.

- [Demo](https://twitter.com/antonosika/status/1667641038104674306)
- [Demo](https://twitter.com/antonosika/status/1667641038104674306)

## Project philosophy

Expand Down
15 changes: 7 additions & 8 deletions gpt_engineer/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,17 +365,16 @@ def create_chat_model(self, model: str, temperature) -> BaseChatModel:
)
# Fetch available models from OpenAI API
supported = [model["id"] for model in openai.Model.list()["data"]]
if model in supported:
return ChatOpenAI(
model=model,
temperature=temperature,
streaming=True,
client=openai.ChatCompletion,
)
else:
if model not in supported:
raise ValueError(
f"Model {model} is not supported, supported models are: {supported}"
)
return ChatOpenAI(
model=model,
temperature=temperature,
streaming=True,
client=openai.ChatCompletion,
)


def get_tokenizer(model: str):
Expand Down
10 changes: 4 additions & 6 deletions gpt_engineer/chat_to_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,10 @@ def overwrite_files(chat, dbs):

files = parse_chat(chat)
for file_name, file_content in files:
if file_name.find("../") > -1:
raise Exception(f"File name {file_name} attempted to access parent path.")
elif file_name == "README.md":
dbs.workspace["ExistingCodeModificationsREADME.md"] = file_content
if file_name == "README.md":
dbs.workspace["LAST_MODIFICATION_README.md"] = file_content
else:
full_path = os.path.join(dbs.input.path, file_name)
dbs.workspace[full_path] = file_content
dbs.workspace[file_name] = file_content


def get_code_strings(input) -> dict[str, str]:
Expand All @@ -115,6 +112,7 @@ def get_code_strings(input) -> dict[str, str]:
with open(full_file_path, "r") as file:
file_data = file.read()
if file_data:
# TODO: Should below be the full path?
file_name = os.path.relpath(full_file_path, input.path)
files_dict[file_name] = file_data
return files_dict
Expand Down
7 changes: 5 additions & 2 deletions gpt_engineer/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def get(self, key, default=None):
except KeyError:
return default

def __setitem__(self, key, val):
def __setitem__(self, key: str | Path, val: str):
"""
Set the content of a file in the database.
Expand All @@ -101,14 +101,17 @@ def __setitem__(self, key, val):
TypeError
If val is not string.
"""
if str(key).startswith("../"):
raise ValueError(f"File name {key} attempted to access parent path.")

full_path = self.path / key
full_path.parent.mkdir(parents=True, exist_ok=True)

if isinstance(val, str):
full_path.write_text(val, encoding="utf-8")
else:
# If val is not string, raise an error.
raise TypeError("val must be either a str or bytes")
raise TypeError("val must be str")


# dataclass for all dbs:
Expand Down
48 changes: 22 additions & 26 deletions gpt_engineer/file_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from pathlib import Path
from typing import List, Union

IGNORE_FOLDERS = {"site-packages", "node_modules"}
IGNORE_FOLDERS = {"site-packages", "node_modules", "venv"}
FILE_LIST_NAME = "file_list.txt"


class DisplayablePath(object):
Expand Down Expand Up @@ -235,23 +236,25 @@ def ask_for_files(db_input) -> None:
dict[str, str]: Dictionary where key = file name and value = file path
"""
use_last_string = ""
is_valid_selection = False
can_use_last = False
if "file_list.txt" in db_input:
can_use_last = True
use_last_string = (
"3. Use previous file list (available at "
+ f"{os.path.join(db_input.path, 'file_list.txt')})\n"
)
selection_number = 3
else:
selection_number = 1
selection_str = f"""How do you want to select the files?
selection_str = "\n".join(
[
"How do you want to select the files?",
"",
"1. Use File explorer.",
"2. Use Command-Line.",
use_last_string if len(use_last_string) > 1 else "",
f"Select option and press Enter (default={selection_number}): ",
]
)

1. Use Command-Line.
2. Use File explorer.
{use_last_string if len(use_last_string) > 1 else ""}
Select option and press Enter (default={selection_number}): """
file_path_list = []
selected_number_str = input(selection_str)
if selected_number_str:
Expand All @@ -260,30 +263,23 @@ def ask_for_files(db_input) -> None:
except ValueError:
print("Invalid number. Select a number from the list above.\n")
sys.exit(1)

if selection_number == 1:
# Open terminal selection
file_path_list = terminal_file_selector()
is_valid_selection = True
elif selection_number == 2:
# Open GUI selection
file_path_list = gui_file_selector()
is_valid_selection = True
else:
if can_use_last and selection_number == 3:
# Use previous file list
is_valid_selection = True
if not is_valid_selection:
elif selection_number == 2:
# Open terminal selection
file_path_list = terminal_file_selector()
if (
selection_number <= 0
or selection_number > 3
or (selection_number == 3 and not use_last_string)
):
print("Invalid number. Select a number from the list above.\n")
sys.exit(1)

file_list_string = ""
if not selection_number == 3:
# New files
for file_path in file_path_list:
file_list_string += str(file_path) + "\n"

# Write in file_list so the user can edit and remember what was done
db_input["file_list.txt"] = file_list_string
db_input["file_list.txt"] = "\n".join(file_path_list)


def gui_file_selector() -> List[str]:
Expand Down
18 changes: 15 additions & 3 deletions gpt_engineer/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ def main(
logging.basicConfig(level=logging.DEBUG if verbose else logging.INFO)

# For the improve option take current project as path and add .gpteng folder
# By now, ignoring the 'project_path' argument
if improve_option:
# The default option for the --improve is the IMPROVE_CODE, not DEFAULT
if steps_config == StepsConfig.DEFAULT:
Expand Down Expand Up @@ -80,8 +79,21 @@ def main(
archive=DB(archive_path),
)

steps_used = STEPS[steps_config]
for step in steps_used:
if steps_config not in [
StepsConfig.EXECUTE_ONLY,
StepsConfig.USE_FEEDBACK,
StepsConfig.EVALUATE,
StepsConfig.IMPROVE_CODE,
]:
archive(dbs)

if not dbs.input.get("prompt"):
dbs.input["prompt"] = input(
"\nWhat application do you want gpt-engineer to generate?\n"
)

steps = STEPS[steps_config]
for step in steps:
messages = step(ai, dbs)
dbs.logs[step.__name__] = AI.serialize_messages(messages)

Expand Down
41 changes: 22 additions & 19 deletions gpt_engineer/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
to_files,
)
from gpt_engineer.db import DBs
from gpt_engineer.file_selector import ask_for_files
from gpt_engineer.file_selector import FILE_LIST_NAME, ask_for_files
from gpt_engineer.learning import human_review_input

Message = Union[AIMessage, HumanMessage, SystemMessage]
Expand Down Expand Up @@ -336,25 +336,28 @@ def get_improve_prompt(ai: AI, dbs: DBs):
Asks the user what they would like to fix.
"""

dbs.input["prompt"] = input(
"\nWhat do you need to improve with the selected files?\n"
)

confirm_str = f"""
-----------------------------
The following files will be used in the improvement process:
{dbs.input["file_list.txt"]}
The inserted prompt is the following:
'{dbs.input['prompt']}'
-----------------------------
You can change these files in .gpteng folder ({dbs.input.path}) in your project
before proceeding.
Press enter to proceed with modifications.
if not dbs.input.get("prompt"):
dbs.input["prompt"] = input(
"\nWhat do you need to improve with the selected files?\n"
)

"""
confirm_str = "\n".join(
[
"-----------------------------",
"The following files will be used in the improvement process:",
f"{FILE_LIST_NAME}:",
str(dbs.input["file_list.txt"]),
"",
"The inserted prompt is the following:",
f"'{dbs.input['prompt']}'",
"-----------------------------",
"",
"You can change these files in your project before proceeding.",
"",
"Press enter to proceed with modifications.",
"",
]
)
input(confirm_str)
return []

Expand Down

0 comments on commit bb420af

Please sign in to comment.