mirror of
https://github.com/OpenBMB/ChatDev.git
synced 2024-11-07 18:40:13 +03:00
add git function
This commit is contained in:
parent
de203ee41e
commit
75fbb9a590
15
README.md
15
README.md
@ -27,9 +27,15 @@
|
||||
|
||||
## 📰 News
|
||||
|
||||
* **September 25th, 2023: The **Git** feature is now available**, enabling the programmer < img src='online_log/static/figures/programmer.png' height=20> to utilize GitHub for version control. To enable this feature, simply set ``"git_management"`` to ``"True"`` in ``ChatChainConfig.json``.
|
||||
<p align="center">
|
||||
<img src='./misc/github.png' width=600>
|
||||
</p>
|
||||
* September 20th, 2023: The **Human-Agent-Interaction** mode is now available! You can get involved with the ChatDev team by playing the role of reviewer <img src='online_log/static/figures/reviewer.png' height=20> and making suggestions to the programmer <img src='online_log/static/figures/programmer.png' height=20>;
|
||||
try ``python3 run.py --task [description_of_your_idea] --config "Human"``. See [guide](wiki.md#human-agent-interaction) and [example](WareHouse/Gomoku_HumanAgentInteraction_20230920135038).
|
||||
<center><img src='misc/Human_intro.png' width=800></center>
|
||||
<p align="center">
|
||||
<img src='./misc/Human_intro.png' width=600>
|
||||
</p>
|
||||
* September 1st, 2023: The **Art** mode is available now! You can activate the designer agent <img src='online_log/static/figures/designer.png' height=20> to generate images used in the software;
|
||||
try ``python3 run.py --task [description_of_your_idea] --config "Art"``. See [guide](wiki.md#art) and [example](WareHouse/gomokugameArtExample_THUNLP_20230831122822).
|
||||
* August 28th, 2023: The system is publicly available.
|
||||
@ -165,10 +171,9 @@ create a software package and generate a folder named ``/WareHouse/2048_THUNLP_t
|
||||
|
||||
## ⚖️ License
|
||||
|
||||
- The purpose of ChatDev is exclusively for research purposes.
|
||||
- The source code is licensed under Apache 2.0.
|
||||
- The datasets are licensed under CC BY NC 4.0, which allows for non-commercial use only. It is important to note that
|
||||
any models trained using these datasets should not be employed for purposes other than research.
|
||||
- Source Code Licensing: Our project's source code is licensed under the Apache 2.0 License. This license permits the use, modification, and distribution of the code, subject to certain conditions outlined in the Apache 2.0 License.
|
||||
- Project Open-Source Status: The project is indeed open-source; however, this designation is primarily intended for non-commercial purposes. While we encourage collaboration and contributions from the community for research and non-commercial applications, it is important to note that any utilization of the project's components for commercial purposes necessitates separate licensing agreements.
|
||||
- Data Licensing: The related data utilized in our project is licensed under CC BY-NC 4.0. This license explicitly permits non-commercial use of the data. We would like to emphasize that any models trained using these datasets should strictly adhere to the non-commercial usage restriction and should be employed exclusively for research purposes.
|
||||
|
||||
## Star History
|
||||
|
||||
|
@ -60,7 +60,6 @@ class PhaseType(Enum):
|
||||
RECRUITING_CPO = "recruiting CPO"
|
||||
RECRUITING_CTO = "recruiting CTO"
|
||||
DEMAND_ANALYSIS = "demand analysis"
|
||||
BRAINSTORMING = "brainstorming"
|
||||
CHOOSING_LANGUAGE = "choosing language"
|
||||
RECRUITING_PROGRAMMER = "recruiting programmer"
|
||||
RECRUITING_REVIEWER = "recruiting reviewer"
|
||||
|
@ -1,10 +1,10 @@
|
||||
import importlib
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from camel.agents import RolePlaying
|
||||
from camel.configs import ChatGPTConfig
|
||||
@ -63,7 +63,6 @@ class ChatChain:
|
||||
|
||||
# init ChatEnv
|
||||
self.chat_env_config = ChatEnvConfig(clear_structure=check_bool(self.config["clear_structure"]),
|
||||
brainstorming=check_bool(self.config["brainstorming"]),
|
||||
gui_design=check_bool(self.config["gui_design"]),
|
||||
git_management=check_bool(self.config["git_management"]))
|
||||
self.chat_env = ChatEnv(self.chat_env_config)
|
||||
@ -102,8 +101,6 @@ class ChatChain:
|
||||
log_filepath=self.log_filepath)
|
||||
self.phases[phase] = phase_instance
|
||||
|
||||
|
||||
|
||||
def make_recruitment(self):
|
||||
"""
|
||||
recruit all employees
|
||||
@ -176,7 +173,8 @@ class ChatChain:
|
||||
root = os.path.dirname(filepath)
|
||||
# directory = root + "/WareHouse/"
|
||||
directory = os.path.join(root, "WareHouse")
|
||||
log_filepath = os.path.join(directory, "{}.log".format("_".join([self.project_name, self.org_name,start_time])))
|
||||
log_filepath = os.path.join(directory,
|
||||
"{}.log".format("_".join([self.project_name, self.org_name, start_time])))
|
||||
return start_time, log_filepath
|
||||
|
||||
def pre_processing(self):
|
||||
@ -187,9 +185,7 @@ class ChatChain:
|
||||
"""
|
||||
if self.chat_env.config.clear_structure:
|
||||
filepath = os.path.dirname(__file__)
|
||||
# root = "/".join(filepath.split("/")[:-1])
|
||||
root = os.path.dirname(filepath)
|
||||
# directory = root + "/WareHouse"
|
||||
directory = os.path.join(root, "WareHouse")
|
||||
for filename in os.listdir(directory):
|
||||
file_path = os.path.join(directory, filename)
|
||||
@ -221,8 +217,8 @@ class ChatChain:
|
||||
preprocess_msg += "**task_prompt**: {}\n\n".format(self.task_prompt_raw)
|
||||
preprocess_msg += "**project_name**: {}\n\n".format(self.project_name)
|
||||
preprocess_msg += "**Log File**: {}\n\n".format(self.log_filepath)
|
||||
preprocess_msg += "**ChatDevConfig**:\n {}\n\n".format(self.chat_env.config.__str__())
|
||||
preprocess_msg += "**ChatGPTConfig**:\n {}\n\n".format(chat_gpt_config)
|
||||
preprocess_msg += "**ChatDevConfig**:\n{}\n\n".format(self.chat_env.config.__str__())
|
||||
preprocess_msg += "**ChatGPTConfig**:\n{}\n\n".format(chat_gpt_config)
|
||||
log_and_print_online(preprocess_msg)
|
||||
|
||||
# init task prompt
|
||||
@ -240,9 +236,33 @@ class ChatChain:
|
||||
|
||||
self.chat_env.write_meta()
|
||||
filepath = os.path.dirname(__file__)
|
||||
# root = "/".join(filepath.split("/")[:-1])
|
||||
root = os.path.dirname(filepath)
|
||||
|
||||
if self.chat_env_config.git_management:
|
||||
git_online_log = "**[Git Information]**\n\n"
|
||||
|
||||
self.chat_env.codes.version += 1
|
||||
os.system("cd {}; git add .".format(self.chat_env.env_dict["directory"]))
|
||||
git_online_log += "cd {}; git add .\n".format(self.chat_env.env_dict["directory"])
|
||||
os.system("cd {}; git commit -m \"v{} Final Version\"".format(self.chat_env.env_dict["directory"], self.chat_env.codes.version))
|
||||
git_online_log += "cd {}; git commit -m \"v{} Final Version\"\n".format(self.chat_env.env_dict["directory"], self.chat_env.codes.version)
|
||||
log_and_print_online(git_online_log)
|
||||
|
||||
git_info = "**[Git Log]**\n\n"
|
||||
import subprocess
|
||||
|
||||
# 执行git log命令
|
||||
command = "cd {}; git log".format(self.chat_env.env_dict["directory"])
|
||||
completed_process = subprocess.run(command, shell=True, text=True, stdout=subprocess.PIPE)
|
||||
|
||||
if completed_process.returncode == 0:
|
||||
log_output = completed_process.stdout
|
||||
else:
|
||||
log_output = "Error when executing " + command
|
||||
|
||||
git_info += log_output
|
||||
log_and_print_online(git_info)
|
||||
|
||||
post_info = "**[Post Info]**\n\n"
|
||||
now_time = now()
|
||||
time_format = "%Y%m%d%H%M%S"
|
||||
@ -251,7 +271,8 @@ class ChatChain:
|
||||
duration = (datetime2 - datetime1).total_seconds()
|
||||
|
||||
post_info += "Software Info: {}".format(
|
||||
get_info(self.chat_env.env_dict['directory'], self.log_filepath) + "\n\n🕑**duration**={:.2f}s\n\n".format(duration))
|
||||
get_info(self.chat_env.env_dict['directory'], self.log_filepath) + "\n\n🕑**duration**={:.2f}s\n\n".format(
|
||||
duration))
|
||||
|
||||
post_info += "ChatDev Starts ({})".format(self.start_time) + "\n\n"
|
||||
post_info += "ChatDev Ends ({})".format(now_time) + "\n\n"
|
||||
|
@ -17,18 +17,17 @@ from chatdev.utils import log_and_print_online
|
||||
|
||||
class ChatEnvConfig:
|
||||
def __init__(self, clear_structure,
|
||||
brainstorming,
|
||||
gui_design,
|
||||
git_management):
|
||||
self.clear_structure = clear_structure
|
||||
self.brainstorming = brainstorming
|
||||
self.gui_design = gui_design
|
||||
self.git_management = git_management
|
||||
|
||||
def __str__(self):
|
||||
string = ""
|
||||
string += "ChatEnvConfig.clear_structure: {}\n".format(self.clear_structure)
|
||||
string += "ChatEnvConfig.brainstorming: {}\n".format(self.brainstorming)
|
||||
string += "ChatEnvConfig.git_management: {}\n".format(self.git_management)
|
||||
string += "ChatEnvConfig.gui_design: {}\n".format(self.gui_design)
|
||||
return string
|
||||
|
||||
|
||||
@ -112,7 +111,7 @@ class ChatEnv:
|
||||
else:
|
||||
os.kill(process.pid, signal.SIGTERM)
|
||||
if process.poll() is None:
|
||||
os.kill(process.pid,signal.CTRL_BREAK_EVENT)
|
||||
os.kill(process.pid, signal.CTRL_BREAK_EVENT)
|
||||
|
||||
if return_code == 0:
|
||||
return False, success_info
|
||||
@ -143,8 +142,8 @@ class ChatEnv:
|
||||
def update_codes(self, generated_content):
|
||||
self.codes._update_codes(generated_content)
|
||||
|
||||
def rewrite_codes(self) -> None:
|
||||
self.codes._rewrite_codes(self.config.git_management)
|
||||
def rewrite_codes(self, phase_info=None) -> None:
|
||||
self.codes._rewrite_codes(self.config.git_management, phase_info)
|
||||
|
||||
def get_codes(self) -> str:
|
||||
return self.codes._get_codes()
|
||||
|
@ -1,13 +1,15 @@
|
||||
import difflib
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from chatdev.utils import log_and_print_online
|
||||
import difflib
|
||||
|
||||
|
||||
class Codes:
|
||||
def __init__(self, generated_content=""):
|
||||
self.directory: str = None
|
||||
self.version: float = 1.0
|
||||
self.version: float = 0.0
|
||||
self.generated_content: str = generated_content
|
||||
self.codebooks = {}
|
||||
|
||||
@ -71,7 +73,7 @@ class Codes:
|
||||
log_and_print_online(update_codes_content)
|
||||
self.codebooks[key] = new_codes.codebooks[key]
|
||||
|
||||
def _rewrite_codes(self, git_management) -> None:
|
||||
def _rewrite_codes(self, git_management, phase_info=None) -> None:
|
||||
directory = self.directory
|
||||
rewrite_codes_content = "**[Rewrite Codes]**\n\n"
|
||||
if os.path.exists(directory) and len(os.listdir(directory)) > 0:
|
||||
@ -87,12 +89,35 @@ class Codes:
|
||||
rewrite_codes_content += os.path.join(directory, filename) + " Wrote\n"
|
||||
|
||||
if git_management:
|
||||
if not phase_info:
|
||||
phase_info = ""
|
||||
git_online_log = "**[Git Information]**\n\n"
|
||||
if self.version == 1.0:
|
||||
os.system("cd {}; git init".format(self.directory))
|
||||
git_online_log += "cd {}; git init\n".format(self.directory)
|
||||
os.system("cd {}; git add .".format(self.directory))
|
||||
os.system("cd {}; git commit -m \"{}\"".format(self.directory, self.version))
|
||||
git_online_log += "cd {}; git add .\n".format(self.directory)
|
||||
|
||||
log_and_print_online(rewrite_codes_content)
|
||||
# check if there exist diff
|
||||
completed_process = subprocess.run("cd {}; git status".format(self.directory), shell=True, text=True,
|
||||
stdout=subprocess.PIPE)
|
||||
if "nothing to commit" in completed_process.stdout:
|
||||
self.version -= 1.0
|
||||
return
|
||||
|
||||
os.system("cd {}; git commit -m \"v{}\"".format(self.directory, str(self.version) + " " + phase_info))
|
||||
git_online_log += "cd {}; git commit -m \"v{}\"\n".format(self.directory,
|
||||
str(self.version) + " " + phase_info)
|
||||
if self.version == 1.0:
|
||||
os.system("cd {}; git submodule add ./{} {}".format(os.path.dirname(os.path.dirname(self.directory)),
|
||||
"WareHouse/" + os.path.basename(self.directory),
|
||||
"WareHouse/" + os.path.basename(self.directory)))
|
||||
git_online_log += "cd {}; git submodule add ./{} {}\n".format(
|
||||
os.path.dirname(os.path.dirname(self.directory)),
|
||||
"WareHouse/" + os.path.basename(self.directory),
|
||||
"WareHouse/" + os.path.basename(self.directory))
|
||||
log_and_print_online(rewrite_codes_content)
|
||||
log_and_print_online(git_online_log)
|
||||
|
||||
def _get_codes(self) -> str:
|
||||
content = ""
|
||||
|
@ -135,7 +135,7 @@ class ComposedPhase(ABC):
|
||||
|
||||
"""
|
||||
self.update_phase_env(chat_env)
|
||||
for cycle_index in range(self.cycle_num):
|
||||
for cycle_index in range(1, self.cycle_num + 1):
|
||||
for phase_item in self.composition:
|
||||
assert phase_item["phaseType"] == "SimplePhase" # right now we do not support nested composition
|
||||
phase = phase_item['phase']
|
||||
|
@ -207,8 +207,6 @@ class Phase(ABC):
|
||||
question = """Answer their final discussed conclusion (Yes or No) in the discussion without any other words, e.g., "Yes" """
|
||||
elif phase_name == "DemandAnalysis":
|
||||
question = """Answer their final product modality in the discussion without any other words, e.g., "PowerPoint" """
|
||||
# elif phase_name in [PhaseType.BRAINSTORMING]:
|
||||
# question = """Conclude three most creative and imaginative brainstorm ideas from the whole discussion, in the format: "1) *; 2) *; 3) *; where '*' represents a suggestion." """
|
||||
elif phase_name == "LanguageChoose":
|
||||
question = """Conclude the programming language being discussed for software development, in the format: "*" where '*' represents a programming language." """
|
||||
elif phase_name == "EnvironmentDoc":
|
||||
@ -356,7 +354,7 @@ class Coding(Phase):
|
||||
chat_env.update_codes(self.seminar_conclusion)
|
||||
if len(chat_env.codes.codebooks.keys()) == 0:
|
||||
raise ValueError("No Valid Codes.")
|
||||
chat_env.rewrite_codes()
|
||||
chat_env.rewrite_codes("Finish Coding")
|
||||
log_and_print_online(
|
||||
"**[Software Info]**:\n\n {}".format(get_info(chat_env.env_dict['directory'], self.log_filepath)))
|
||||
return chat_env
|
||||
@ -392,7 +390,7 @@ class ArtIntegration(Phase):
|
||||
|
||||
def update_chat_env(self, chat_env) -> ChatEnv:
|
||||
chat_env.update_codes(self.seminar_conclusion)
|
||||
chat_env.rewrite_codes()
|
||||
chat_env.rewrite_codes("Finish Art Integration")
|
||||
# chat_env.generate_images_from_codes()
|
||||
log_and_print_online(
|
||||
"**[Software Info]**:\n\n {}".format(get_info(chat_env.env_dict['directory'], self.log_filepath)))
|
||||
@ -424,7 +422,7 @@ class CodeComplete(Phase):
|
||||
chat_env.update_codes(self.seminar_conclusion)
|
||||
if len(chat_env.codes.codebooks.keys()) == 0:
|
||||
raise ValueError("No Valid Codes.")
|
||||
chat_env.rewrite_codes()
|
||||
chat_env.rewrite_codes("Code Complete #" + str(self.phase_env["cycle_index"]) + " Finished")
|
||||
log_and_print_online(
|
||||
"**[Software Info]**:\n\n {}".format(get_info(chat_env.env_dict['directory'], self.log_filepath)))
|
||||
return chat_env
|
||||
@ -463,7 +461,7 @@ class CodeReviewModification(Phase):
|
||||
def update_chat_env(self, chat_env) -> ChatEnv:
|
||||
if "```".lower() in self.seminar_conclusion.lower():
|
||||
chat_env.update_codes(self.seminar_conclusion)
|
||||
chat_env.rewrite_codes()
|
||||
chat_env.rewrite_codes("Review #" + str(self.phase_env["cycle_index"]) + " Finished")
|
||||
log_and_print_online(
|
||||
"**[Software Info]**:\n\n {}".format(get_info(chat_env.env_dict['directory'], self.log_filepath)))
|
||||
self.phase_env['modification_conclusion'] = self.seminar_conclusion
|
||||
@ -484,7 +482,7 @@ class CodeReviewHuman(Phase):
|
||||
def update_chat_env(self, chat_env) -> ChatEnv:
|
||||
if "```".lower() in self.seminar_conclusion.lower():
|
||||
chat_env.update_codes(self.seminar_conclusion)
|
||||
chat_env.rewrite_codes()
|
||||
chat_env.rewrite_codes("Human Review #" + str(self.phase_env["cycle_index"]) + " Finished")
|
||||
log_and_print_online(
|
||||
"**[Software Info]**:\n\n {}".format(get_info(chat_env.env_dict['directory'], self.log_filepath)))
|
||||
return chat_env
|
||||
@ -496,14 +494,14 @@ class CodeReviewHuman(Phase):
|
||||
f"Now you can participate in the development of the software!\n"
|
||||
f"The task is: {chat_env.env_dict['task_prompt']}\n"
|
||||
f"Please input your feedback (in one line). It can be bug report or new feature requirement.\n"
|
||||
f"You are currently in the #{self.phase_env['cycle_index'] + 1} human feedback with a total of {self.phase_env['cycle_num']} feedbacks\n"
|
||||
f"You are currently in the #{self.phase_env['cycle_index']} human feedback with a total of {self.phase_env['cycle_num']} feedbacks\n"
|
||||
f"Press [Enter] to submit.\n"
|
||||
f"You can type \"End\" to quit this mode at any time.\n"
|
||||
)
|
||||
provided_comments = input(">>> ")
|
||||
self.phase_env["comments"] = provided_comments
|
||||
log_and_print_online(
|
||||
f"**[User Provided Comments]**\n\n In the #{self.phase_env['cycle_index'] + 1} of total {self.phase_env['cycle_num']} comments: \n\n" + provided_comments)
|
||||
f"**[User Provided Comments]**\n\n In the #{self.phase_env['cycle_index']} of total {self.phase_env['cycle_num']} comments: \n\n" + provided_comments)
|
||||
if provided_comments.lower() == "end":
|
||||
return chat_env
|
||||
|
||||
@ -592,7 +590,7 @@ class TestModification(Phase):
|
||||
def update_chat_env(self, chat_env) -> ChatEnv:
|
||||
if "```".lower() in self.seminar_conclusion.lower():
|
||||
chat_env.update_codes(self.seminar_conclusion)
|
||||
chat_env.rewrite_codes()
|
||||
chat_env.rewrite_codes("Test #" + str(self.phase_env["cycle_index"]) + " Finished")
|
||||
log_and_print_online(
|
||||
"**[Software Info]**:\n\n {}".format(get_info(chat_env.env_dict['directory'], self.log_filepath)))
|
||||
return chat_env
|
||||
|
BIN
misc/github.png
Normal file
BIN
misc/github.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
Loading…
Reference in New Issue
Block a user