|
""" |
|
Entrypoint for the CLI tool. |
|
|
|
Main Functionality: |
|
--------------------- |
|
- Load environment variables needed to work with OpenAI. |
|
- Allow users to specify parameters such as: |
|
- Project path |
|
- LLM |
|
- Temperature |
|
- Step configurations |
|
- Code improvement mode |
|
- Lite mode for lighter operations |
|
- Azure endpoint for Azure OpenAI services |
|
- Using project's preprompts or default ones |
|
- Verbosity level for logging |
|
- Interact with AI, databases, and archive processes based on the user-defined parameters. |
|
|
|
Notes: |
|
- Ensure the .env file has the `OPENAI_API_KEY` or provide it in the working directory. |
|
- The default project path is set to `projects/example`. |
|
- For azure_endpoint, provide the endpoint for Azure OpenAI service. |
|
|
|
""" |
|
|
|
import logging |
|
import os |
|
|
|
from pathlib import Path |
|
|
|
import openai |
|
import typer |
|
|
|
from dotenv import load_dotenv |
|
|
|
from gpt_engineer.applications.cli.cli_agent import CliAgent |
|
from gpt_engineer.applications.cli.collect import collect_and_send_human_review |
|
from gpt_engineer.applications.cli.file_selector import FileSelector |
|
from gpt_engineer.core.ai import AI |
|
from gpt_engineer.core.default.disk_execution_env import DiskExecutionEnv |
|
from gpt_engineer.core.default.disk_memory import DiskMemory |
|
from gpt_engineer.core.default.file_store import FileStore |
|
from gpt_engineer.core.default.paths import PREPROMPTS_PATH, memory_path |
|
from gpt_engineer.core.default.steps import execute_entrypoint, gen_code, improve |
|
from gpt_engineer.core.preprompts_holder import PrepromptsHolder |
|
from gpt_engineer.tools.custom_steps import clarified_gen, lite_gen, self_heal |
|
|
|
app = typer.Typer() |
|
|
|
|
|
def load_env_if_needed(): |
|
if os.getenv("OPENAI_API_KEY") is None: |
|
load_dotenv() |
|
if os.getenv("OPENAI_API_KEY") is None: |
|
|
|
load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env")) |
|
openai.api_key = os.getenv("OPENAI_API_KEY") |
|
|
|
|
|
def load_prompt(input_repo: DiskMemory, improve_mode): |
|
if input_repo.get("prompt"): |
|
return input_repo.get("prompt") |
|
|
|
if not improve_mode: |
|
input_repo["prompt"] = input( |
|
"\nWhat application do you want gpt-engineer to generate?\n" |
|
) |
|
else: |
|
input_repo["prompt"] = input("\nHow do you want to improve the application?\n") |
|
return input_repo.get("prompt") |
|
|
|
|
|
def get_preprompts_path(use_custom_preprompts: bool, input_path: Path) -> Path: |
|
original_preprompts_path = PREPROMPTS_PATH |
|
if not use_custom_preprompts: |
|
return original_preprompts_path |
|
|
|
custom_preprompts_path = input_path / "preprompts" |
|
if not custom_preprompts_path.exists(): |
|
custom_preprompts_path.mkdir() |
|
|
|
for file in original_preprompts_path.glob("*"): |
|
if not (custom_preprompts_path / file.name).exists(): |
|
(custom_preprompts_path / file.name).write_text(file.read_text()) |
|
return custom_preprompts_path |
|
|
|
|
|
@app.command() |
|
def main( |
|
project_path: str = typer.Argument("projects/example", help="path"), |
|
model: str = typer.Argument("gpt-4-1106-preview", help="model id string"), |
|
temperature: float = 0.1, |
|
improve_mode: bool = typer.Option( |
|
False, |
|
"--improve", |
|
"-i", |
|
help="Improve files_dict from existing project.", |
|
), |
|
lite_mode: bool = typer.Option( |
|
False, |
|
"--lite", |
|
"-l", |
|
help="Lite mode - run only the main prompt.", |
|
), |
|
clarify_mode: bool = typer.Option( |
|
False, |
|
"--clarify", |
|
"-c", |
|
help="Lite mode - discuss specification with AI before implementation.", |
|
), |
|
self_heal_mode: bool = typer.Option( |
|
False, |
|
"--self-heal", |
|
"-sh", |
|
help="Lite mode - discuss specification with AI before implementation.", |
|
), |
|
azure_endpoint: str = typer.Option( |
|
"", |
|
"--azure", |
|
"-a", |
|
help="""Endpoint for your Azure OpenAI Service (https://xx.openai.azure.com). |
|
In that case, the given model is the deployment name chosen in the Azure AI Studio.""", |
|
), |
|
use_custom_preprompts: bool = typer.Option( |
|
False, |
|
"--use-custom-preprompts", |
|
help="""Use your project's custom preprompts instead of the default ones. |
|
Copies all original preprompts to the project's workspace if they don't exist there.""", |
|
), |
|
verbose: bool = typer.Option(False, "--verbose", "-v"), |
|
): |
|
""" |
|
Generates a project from a prompt in PROJECT_PATH/prompt, |
|
or improves an existing project (with -i) in PROJECT_PATH. |
|
|
|
See README.md for more details. |
|
""" |
|
logging.basicConfig(level=logging.DEBUG if verbose else logging.INFO) |
|
|
|
|
|
if improve_mode: |
|
assert not ( |
|
clarify_mode or lite_mode |
|
), "Clarify and lite mode are not active for improve mode" |
|
|
|
load_env_if_needed() |
|
|
|
ai = AI( |
|
model_name=model, |
|
temperature=temperature, |
|
azure_endpoint=azure_endpoint, |
|
) |
|
|
|
path = Path(project_path) |
|
print("Running gpt-engineer in", path.absolute(), "\n") |
|
prompt = load_prompt(DiskMemory(path), improve_mode) |
|
|
|
|
|
if clarify_mode: |
|
code_gen_fn = clarified_gen |
|
elif lite_mode: |
|
code_gen_fn = lite_gen |
|
else: |
|
code_gen_fn = gen_code |
|
|
|
if self_heal_mode: |
|
execution_fn = self_heal |
|
else: |
|
execution_fn = execute_entrypoint |
|
|
|
improve_fn = improve |
|
|
|
preprompts_path = get_preprompts_path(use_custom_preprompts, Path(project_path)) |
|
preprompts_holder = PrepromptsHolder(preprompts_path) |
|
memory = DiskMemory(memory_path(project_path)) |
|
execution_env = DiskExecutionEnv() |
|
agent = CliAgent.with_default_config( |
|
memory, |
|
execution_env, |
|
ai=ai, |
|
code_gen_fn=code_gen_fn, |
|
improve_fn=improve_fn, |
|
process_code_fn=execution_fn, |
|
preprompts_holder=preprompts_holder, |
|
) |
|
|
|
store = FileStore(project_path) |
|
if improve_mode: |
|
fileselector = FileSelector(project_path) |
|
files_dict = fileselector.ask_for_files() |
|
files_dict = agent.improve(files_dict, prompt) |
|
else: |
|
files_dict = agent.init(prompt) |
|
|
|
config = (code_gen_fn.__name__, execution_fn.__name__) |
|
collect_and_send_human_review(prompt, model, temperature, config, agent.memory) |
|
|
|
store.upload(files_dict) |
|
|
|
print("Total api cost: $ ", ai.token_usage_log.usage_cost()) |
|
|
|
|
|
if __name__ == "__main__": |
|
app() |
|
|