add git function

This commit is contained in:
thinkwee 2023-09-25 16:43:01 +08:00
parent de203ee41e
commit 75fbb9a590
8 changed files with 87 additions and 40 deletions

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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()

View File

@ -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 = ""

View File

@ -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']

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB