自動開発ツール、GPT Engineer の入門記3。生成ルールを自分色に染める。

この記事はLLMアドベントカレンダーの8日目です。過去日が空いていたので、頂きました 🙏

https://qiita.com/advent-calendar/2023/llm

LLM アドベントカレンダーは LLM そのものや評価に関して書かれる方が多いですが、LLM を適用したアプリケーションを研究するという文脈で投稿させて頂いています。🙏

また、こちらの記事に関しては続きものです。以下も適宜ご参照ください。

https://qiita.com/nassy20/items/963cd41e968f5840d7d9

https://qiita.com/nassy20/items/257c831aed10bdbeba09

# はじめに

GPT Engineer は、ほとんどのコード生成ルールをカスタマイズ可能な仕組みを備えています。ほとんどケースではこのカスタマイズの仕組みを使わずとも、生成の起点となる`prompt` ファイルに生成のルールを詳細に記述することで、生成を制御できます。しかし、パッケージマネージャーの情報に関しては制御できないという問題がありました。`prompt` ファイルに `requirements.txt` が不要であると記載しても、それは常に生成されてしまいます。そこで今回はコード生成ルールを書き換えて、`requirements.txt`を生成せず、`pyproject.toml`を生成することに挑戦しました。

- 利用したGPT Engineerのバージョン
    - gpt-engineer 0.1.0
    - model: gpt-4-1106-preview

# 目次

1. `requirements.txt` の生成が `prompt` 制御できない理由
2. カスタマイズ🛠️
3. 生成
4. 結果
5. 付録:今回の生成に利用した `prompt`

# `requirements.txt` の生成が `prompt` 制御できない理由

[前回の記事](https://qiita.com/nassy20/items/257c831aed10bdbeba09)で紹介したように、preprompt の `philosophy` ファイルにパッケージマネージャーに関する以下のような知識が組み込まれていたため、`prompt` ファイルに書いた要求とコンフリクトを引き起こしたと考えられます。

`For Python, you always create an appropriate requirements.txt file.`

# カスタマイズ🛠️

### preprompt の用意
基になる preprompt は [こちら](https://github.com/gpt-engineer-org/gpt-engineer/tree/main/gpt_engineer/preprompts) からコピーしました。

カスタマイズするファイルのみを配置すれば良いです。  
存在しないファイルは、GPT Engineer のパッケージからコピーされます。  

時点でプロジェクは以下のようになっています。

```
. (プロジェクトディレクトリ)
├── preprompts
│   └── philosophy
└── prompt
```

preprompts ディレクトリに、コピーした `philosophy` ファイルが配置されます。
`prompt` にも生成したいアプリの要求を記載しておきましょう。  
(付録に今回の生成に利用した`prompt`を記載しておきます。)


### カスタムの内容

`philosophy` ファイルを以下のようにカスタマイズしました。

```diff
Almost always put different classes in different files.
Always use the programming language the user asks for.
- For Python, you always create an appropriate requirements.txt file.
+ Prepare a `pyproject.toml` file assuming the use of Poetry for a Python project, and do not prepare a requirements.txt file.
+ The package name in `pyproject.toml` should be the same as the project name.
+ Set the version in `pyproject.toml` to 0.1.0.
+ Set the compatible Python versions in `pyproject.toml` to `^3.11`.
+ List the necessary libraries in `[tool.poetry.dependencies]` of `pyproject.toml`.
For NodeJS, you always create an appropriate package.json file.
Always add a comment briefly describing the purpose of the function definition.
Add comments explaining very complex bits of logic.
Always follow the best practices for the requested languages for folder/file structure and how to package the project.
```



# 生成

以下のコマンドを実行します。

`gpt-engineer todoapp gpt-4-1106-preview --use-custom-preprompts`

ここで `todoapp` はプロジェクトディレクトリ名です。
フィードバックの可否を聞かれますが、そこは任意です。

# 結果

`pyproject.toml` は生成され、`requirements.txt`は生成されませんでした。🎉🎉
`poetry install` と FastAPI の起動もエラーなく行うことができました。🎉🎉

生成した結果、プロジェクトディレクトリの構成は以下のようになりました。

```
.(プロジェクトディレクトリ)
├── README.md
├── api
│   ├── app
│   │   ├── __init__.py
│   │   ├── database.py
│   │   ├── main.py
│   │   ├── models.py
│   │   └── schemas.py
│   ├── main.py
│   └── pyproject.toml
├── preprompts
│   ├── clarify
│   ├── file_format
│   ├── generate
│   ├── improve
│   ├── philosophy
│   └── roadmap
├── prompt
└── run.sh
```

生成された`pyproject.toml` の内容は以下の通りです。

```pyproject.toml
[tool.poetry]
name = "todo_api"
version = "0.1.0"
description = ""
authors = []

[tool.poetry.dependencies]
python = "^3.11"
fastapi = "*"
uvicorn = "*"
sqlalchemy = "*"
pydantic = "*"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
```

# 付録:今回の生成に利用した `prompt`

```
Todo を SPA の構成で作成してください。

# アプリケーションの仕様
## Todo 画面
- Todo の一覧を表示する。
- Todo の一覧は、タイトル、内容、期限、完了フラグを表示する。
- Todoの作成もできる。

# バックエンド構成
- バックエンドは FastAPI を利用する。
- api/app フォルダー下にアプリの実装をする。
- api フォルダ下に pyproject.toml を用意してください。
- pyproject.toml の [tool.poetry.dependencies] にはパッケージ名のみを書いて、バージョンは書かないでください。
- api の起動は api フォルダ下で `uvicorn app.main:app --reload` で起動するようにしてください。
- api/app/main.py に リクエストのハンドラー(@router.getなど) を定義してください。
- api/app/schemas.py に api のレスポンスモデルを定義してください。
- api/app/database.py に sqlite の接続情報を定義してください。
- api/app/database.py に get_db 関数を定義してください。

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

- __init__.py には "# This is __init__.py" とコメントを入れてください。
- API 起動時に、sqliteのテーブルを作成する。
- sqlite は標準ライブラリなので、install は不要です。
- cors で全てを許可してください

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # すべてのオリジンを許可
    allow_credentials=True,
    allow_methods=["*"],  # すべての HTTP メソッドを許可
    allow_headers=["*"],  # すべてのヘッダーを許可
)

# フロントエンド構成
- フロントエンドは現時点ではまだ実装しなくて良いです。
```


# 最後に
今後もGPT EngineerやLLM関連の記事を書いていくので、良かったらフォローといいね 👍 をお願い致します。