From eb68cfe88c2a569866bc18a157e2bc147674e6b5 Mon Sep 17 00:00:00 2001 From: booboosui Date: Sun, 27 Aug 2023 23:06:06 +0800 Subject: [PATCH 1/5] feat(requirement_memory): save data 70% --- backend/app/controllers/step_api.py | 3 +- backend/app/controllers/step_code.py | 18 ++++-- backend/app/controllers/step_devops.py | 6 +- backend/app/controllers/step_requirement.py | 6 +- backend/app/controllers/step_subtask.py | 3 +- backend/app/pkgs/devops/local_tools.py | 63 ++++++++---------- backend/app/pkgs/devops/local_tools_base.py | 64 +++++++++++++++++++ .../app/pkgs/devops/local_tools_interface.py | 20 ++++++ backend/app/pkgs/prompt/api_basic.py | 2 +- backend/app/pkgs/prompt/api_interface.py | 2 +- backend/app/pkgs/prompt/code_basic.py | 14 ++-- backend/app/pkgs/prompt/code_interface.py | 12 ++-- backend/app/pkgs/prompt/prompt.py | 36 +++++------ backend/app/pkgs/prompt/requirement_basic.py | 2 +- .../app/pkgs/prompt/requirement_interface.py | 2 +- backend/app/pkgs/prompt/subtask_basic.py | 2 +- backend/app/pkgs/prompt/subtask_interface.py | 2 +- backend/config.py | 25 ++++++++ frontend/requirement.html | 2 +- frontend/static/js/coder.js | 14 ++-- 20 files changed, 204 insertions(+), 94 deletions(-) create mode 100644 backend/app/pkgs/devops/local_tools_base.py create mode 100644 backend/app/pkgs/devops/local_tools_interface.py diff --git a/backend/app/controllers/step_api.py b/backend/app/controllers/step_api.py index a49ed0774..8830c13e3 100644 --- a/backend/app/controllers/step_api.py +++ b/backend/app/controllers/step_api.py @@ -13,12 +13,13 @@ def gen_interface_doc(): _ = getI18n("controllers") userPrompt = request.json.get('user_prompt') username = session["username"] + requirementID = request.json.get('task_id') # todo Use llm to determine which interface documents to adjust appID = session[username]['memory']['task_info']['app_id'] apiDoc, success = getServiceSwagger(appID, 0) - msg, success = clarifyAPI(userPrompt, apiDoc) + msg, success = clarifyAPI(requirementID, userPrompt, apiDoc) session[username]['memory']['originalPrompt'] = userPrompt session.update() diff --git a/backend/app/controllers/step_code.py b/backend/app/controllers/step_code.py index 8dc47ccd0..d85da830b 100644 --- a/backend/app/controllers/step_code.py +++ b/backend/app/controllers/step_code.py @@ -14,8 +14,9 @@ def edit_file_task(): newTask = request.json.get('new_task') newCode = request.json.get('new_code') fileTask = request.json.get('file_task') + requirementID = request.json.get('task_id') - re, success = aiGenCode(fileTask, newTask, newCode) + re, success = aiGenCode(requirementID, fileTask, newTask, newCode) if not success: raise Exception(_("Failed to edit file with new task.")) @@ -27,8 +28,9 @@ def check_file(): _ = getI18n("controllers") code = request.json.get('code') fileTask = request.json.get('fileTask') + requirementID = request.json.get('task_id') - re, success = aiCheckCode(fileTask, code) + re, success = aiCheckCode(requirementID, fileTask, code) if not success: raise Exception(_("Failed to check file.")) @@ -43,8 +45,9 @@ def merge_file(): fileTask = request.json.get('file_task') userName = session["username"] appName = session[userName]['memory']['task_info']['app_name'] + requirementID = request.json.get('task_id') - re, success = aiMergeCode(fileTask, appName, baseCode, newCode) + re, success = aiMergeCode(requirementID, fileTask, appName, baseCode, newCode) if not success: raise Exception(_("Failed to merge old and new code.")) @@ -61,12 +64,13 @@ def reference_repair(): userName = session["username"] appName = session[userName]['memory']['task_info']['app_name'] branch = session[userName]['memory']['task_info']['source_branch'] + requirementID = request.json.get('task_id') hasGitCode, referenceCode = getFileContent(referenceFile, branch, repo) if not hasGitCode: raise Exception(_("Failed to reference repair no reference file found.")) - re, success = aiReferenceRepair(newCode, appName, referenceCode, fileTask) + re, success = aiReferenceRepair(requirementID, newCode, appName, referenceCode, fileTask) if not success: raise Exception(_("Reference repair failed for unknown reasons.")) @@ -78,8 +82,9 @@ def reference_repair(): def fix_compile(): code = request.json.get('code') solution = request.json.get('solution') + requirementID = request.json.get('task_id') - re, success = aiFixError(solution, code) + re, success = aiFixError(requirementID, solution, code) reCode = re["code"] reason = re["reasoning"] @@ -91,8 +96,9 @@ def fix_compile(): def fix_lint(): code = request.json.get('code') solution = request.json.get('solution') + requirementID = request.json.get('task_id') - re, success = aiFixError(solution, code) + re, success = aiFixError(requirementID, solution, code) reCode = re["code"] reason = re["reasoning"] diff --git a/backend/app/controllers/step_devops.py b/backend/app/controllers/step_devops.py index 0c1c1e785..5b7b84f30 100644 --- a/backend/app/controllers/step_devops.py +++ b/backend/app/controllers/step_devops.py @@ -63,13 +63,13 @@ def check_compile(): appID = session[username]['memory']['task_info']['app_id'] gitPath, success = getServiceGitPath(appID, serviceName) - success, message = compileCheck(wsPath, gitPath) + success, message = compileCheck(task_id, wsPath, gitPath) if success: reasoning = _("Compile check pass.") return {'pass': True, 'message': message, 'reasoning': reasoning} else: - reasoning, success = aiAnalyzeError(message) + reasoning, success = aiAnalyzeError(task_id, message) if success: return {'pass': False, 'message': message, 'reasoning': reasoning} else: @@ -94,7 +94,7 @@ def check_lint(): reasoning = _("Static code scan passed.") return {'pass': True, 'message': message, 'reasoning': reasoning} else: - reasoning, success = aiAnalyzeError(message) + reasoning, success = aiAnalyzeError(task_id, message) if success: return {'pass': False, 'message': message, 'reasoning': reasoning} else: diff --git a/backend/app/controllers/step_requirement.py b/backend/app/controllers/step_requirement.py index cd61496ab..699ec6dc5 100644 --- a/backend/app/controllers/step_requirement.py +++ b/backend/app/controllers/step_requirement.py @@ -16,17 +16,17 @@ def clarify(): userPrompt = request.json.get('user_prompt') globalContext = request.json.get('global_context') userName = session["username"] - taskID = request.json.get('task_id') + requirementID = request.json.get('task_id') appID = session[userName]['memory']['task_info']['app_id'] if len(appID) == 0 or not appID: raise Exception(_("Please select the application you want to develop.")) - Requirement.update_requirement(requirement_id=taskID, original_requirement=userPrompt, status=REQUIREMENT_STATUS_InProgress) + Requirement.update_requirement(requirement_id=requirementID, original_requirement=userPrompt, status=REQUIREMENT_STATUS_InProgress) appArchitecture, _ = getAppArchitecture(appID) - msg, success = clarifyRequirement(userPrompt, globalContext, appArchitecture) + msg, success = clarifyRequirement(requirementID, userPrompt, globalContext, appArchitecture) if success: return {'message': msg, 'memory': session[userName]['memory']} diff --git a/backend/app/controllers/step_subtask.py b/backend/app/controllers/step_subtask.py index e527baf13..931d40088 100644 --- a/backend/app/controllers/step_subtask.py +++ b/backend/app/controllers/step_subtask.py @@ -20,6 +20,7 @@ def analysis(): username = session['username'] requirementDoc = session[username]['memory']['originalPrompt'] sourceBranch = session[username]['memory']['task_info']['source_branch'] + requirementID = request.json.get('task_id') # todo Use llm to determine which interface documents to adjust appID = session[username]['memory']['task_info']['app_id'] @@ -41,7 +42,7 @@ def analysis(): projectLib, _ = getServiceLib(appID, serviceName) serviceStruct,_ = getServiceStruct(appID, serviceName) - filesToEdit, success = splitTask(newfeature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID) + filesToEdit, success = splitTask(requirementID, newfeature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID) if success: for index, file in enumerate(filesToEdit): diff --git a/backend/app/pkgs/devops/local_tools.py b/backend/app/pkgs/devops/local_tools.py index 456aa8325..d946e2a47 100644 --- a/backend/app/pkgs/devops/local_tools.py +++ b/backend/app/pkgs/devops/local_tools.py @@ -1,7 +1,7 @@ -import subprocess -import platform -from app.pkgs.tools.utils_tool import detect_programming_language, get_last_n_lines from app.pkgs.tools.file_tool import read_file_content +from app.pkgs.devops.local_tools_base import LocalToolsBase +from app.pkgs.devops.local_tools_pro import LocalToolsPro +from config import GRADE from config import WORKSPACE_PATH def getFileContent(file_path, branch_name, repopath): @@ -16,41 +16,34 @@ def getFileContent(file_path, branch_name, repopath): return True, content -def compileCheck(ws_path,repo_path): - print("compile_check:") - gitCwd = ws_path+'/'+repo_path - print(gitCwd) +def compileCheck(requirementID, ws_path,repo_path): + if GRADE == "base": + obj = LocalToolsBase() + else: + obj = LocalToolsPro() + + return obj.compileCheck(requirementID, ws_path,repo_path) - if platform.system() == 'Windows': - sub = ['build.cmd'] - result = subprocess.run( - sub, capture_output=True, text=True, shell=True, cwd=gitCwd) +def lintCheck(requirementID, ws_path, repo_path, file_path): + if GRADE == "base": + obj = LocalToolsBase() else: - sub = ['sh', 'build.sh'] - result = subprocess.run( - sub, capture_output=True, text=True, cwd=gitCwd) + obj = LocalToolsPro() + + return obj.lintCheck(requirementID, ws_path, repo_path, file_path) - print(result) - if result.returncode != 0: - stderr = get_last_n_lines(result.stderr, 20) - if len(stderr)<5: - stderr = get_last_n_lines(result.stdout, 20) - return False, stderr - return True, result.stdout +def unitTest(requirementID, ws_path, repo_path, file_path): + if GRADE == "base": + obj = LocalToolsBase() + else: + obj = LocalToolsPro() + + return obj.unitTest(requirementID, ws_path, repo_path, file_path) -def lintCheck(ws_path, repo_path, file_path): - if detect_programming_language(file_path) == "Python": - result = subprocess.run( - ['pylint', '--disable=all', '--enable=syntax-error', f"{repo_path}/{file_path}"], capture_output=True, text=True, cwd=ws_path) +def apiTest(requirementID, ws_path, repo_path, file_path): + if GRADE == "base": + obj = LocalToolsBase() else: - return True, "Code Scan PAAS." + obj = LocalToolsPro() - print("lint_check:") - print(ws_path) - print(result) - if result.returncode != 0: - stderr = get_last_n_lines(result.stderr, 20) - if len(stderr)<5: - stderr = get_last_n_lines(result.stdout, 20) - return False, stderr - return True, result.stdout \ No newline at end of file + return obj.apiTest(requirementID, ws_path, repo_path, file_path) \ No newline at end of file diff --git a/backend/app/pkgs/devops/local_tools_base.py b/backend/app/pkgs/devops/local_tools_base.py new file mode 100644 index 000000000..9177917ec --- /dev/null +++ b/backend/app/pkgs/devops/local_tools_base.py @@ -0,0 +1,64 @@ +import subprocess +import platform +from app.pkgs.tools.utils_tool import detect_programming_language, get_last_n_lines +from app.pkgs.devops.local_tools_interface import LocalToolsInterface +from config import WORKSPACE_PATH + +class LocalToolsBase(LocalToolsInterface): + def compileCheck(self, requirementID, ws_path, repo_path): + print("compile_check:") + gitCwd = ws_path+'/'+repo_path + script = "" + print(gitCwd) + + if platform.system() == 'Windows': + script = "build.cmd" + sub = [script] + result = subprocess.run( + sub, capture_output=True, text=True, shell=True, cwd=gitCwd) + else: + script = "build.sh" + sub = ['sh', script] + result = subprocess.run( + sub, capture_output=True, text=True, cwd=gitCwd) + + print(result) + if result.returncode != 0: + stderr = get_last_n_lines(result.stderr, 20) + if len(stderr)<5: + stderr = get_last_n_lines(result.stdout, 20) + success = False + re = stderr + else: + success = True + re = result.stdout + + return success, re + + def lintCheck(self, requirementID, ws_path, repo_path, file_path): + if detect_programming_language(file_path) == "Python": + result = subprocess.run( + ['pylint', '--disable=all', '--enable=syntax-error', f"{repo_path}/{file_path}"], capture_output=True, text=True, cwd=ws_path) + else: + return True, "Code Scan PAAS." + + print("lint_check:") + print(ws_path) + print(result) + if result.returncode != 0: + stderr = get_last_n_lines(result.stderr, 20) + if len(stderr)<5: + stderr = get_last_n_lines(result.stdout, 20) + success = False + re = stderr + else: + success = True + re = result.stdout + + return success, re + + def unitTest(self, requirementID, ws_path, repo_path, file_path): + return True, "The current version does not support this feature" + + def apiTest(self, requirementID, ws_path, repo_path, file_path): + return True, "The current version does not support this feature" \ No newline at end of file diff --git a/backend/app/pkgs/devops/local_tools_interface.py b/backend/app/pkgs/devops/local_tools_interface.py new file mode 100644 index 000000000..43dbfcf4c --- /dev/null +++ b/backend/app/pkgs/devops/local_tools_interface.py @@ -0,0 +1,20 @@ +from abc import ABC, abstractmethod + +from config import GRADE + +class LocalToolsInterface(ABC): + @abstractmethod + def compileCheck(requirementID, ws_path,repo_path): + pass + + @abstractmethod + def lintCheck(requirementID, ws_path, repo_path, file_path): + pass + + @abstractmethod + def unitTest(requirementID, ws_path, repo_path, file_path): + pass + + @abstractmethod + def apiTest(requirementID, ws_path, repo_path, file_path): + pass \ No newline at end of file diff --git a/backend/app/pkgs/prompt/api_basic.py b/backend/app/pkgs/prompt/api_basic.py index 51b02ebd3..ebc906c42 100644 --- a/backend/app/pkgs/prompt/api_basic.py +++ b/backend/app/pkgs/prompt/api_basic.py @@ -2,7 +2,7 @@ from app.pkgs.prompt.api_interface import ApiInterface class ApiBasic(ApiInterface): - def clarifyAPI(self, userPrompt, apiDoc): + def clarifyAPI(self, requirementID, userPrompt, apiDoc): message, ctx, success = step1ApiDocTasks(userPrompt, apiDoc) if success: return step2GenApiDoc(message, ctx) diff --git a/backend/app/pkgs/prompt/api_interface.py b/backend/app/pkgs/prompt/api_interface.py index 699896cca..0f0ea04fd 100644 --- a/backend/app/pkgs/prompt/api_interface.py +++ b/backend/app/pkgs/prompt/api_interface.py @@ -4,5 +4,5 @@ class ApiInterface(ABC): @abstractmethod - def clarifyAPI(self, userPrompt, apiDoc): + def clarifyAPI(self, requirementID, userPrompt, apiDoc): pass \ No newline at end of file diff --git a/backend/app/pkgs/prompt/code_basic.py b/backend/app/pkgs/prompt/code_basic.py index 7910a2113..cd695ce04 100644 --- a/backend/app/pkgs/prompt/code_basic.py +++ b/backend/app/pkgs/prompt/code_basic.py @@ -5,7 +5,7 @@ from app.pkgs.prompt.code_interface import CodeInterface class CodeBasic(CodeInterface): - def aiReferenceRepair(self, newCode, referenceCode, fileTask): + def aiReferenceRepair(self, requirementID, newCode, referenceCode, fileTask): prompt = f""" As a senior full stack developer. Your task is to analyze the following "reference code" style and specification (including but not limited to: naming conventions, coding styles, import package specifications, comment specifications, etc.) line by line, and use this to correct the "development task corresponding code" with the "reference code" style and specification is inconsistent. Ensure that the newly generated code can conform to the overall code style and specification of the program as well as the reference code without compromising the "development task". The consolidated code responds according to the response format example. @@ -35,7 +35,7 @@ def aiReferenceRepair(self, newCode, referenceCode, fileTask): return json.loads(fix_llm_json_str(data)), success - def aiAnalyzeError(self, message): + def aiAnalyzeError(self, requirementID, message): prompt = f""" As a senior full stack developer. Your task is to analyze code execution error messages, return files that may need to be modified, and analyze the solution. Follow the response format example. @@ -55,7 +55,7 @@ def aiAnalyzeError(self, message): return json.loads(fix_llm_json_str(data)), success - def aiFixError(self, solution, code): + def aiFixError(self, requirementID, solution, code): prompt = f""" As a senior full stack developer. Your task is to fix errors in the "initial code". Please fix the problems in the "initial code" according to the solution, taking care not to affect other code functions. The consolidated code responds according to the response format example. @@ -80,7 +80,7 @@ def aiFixError(self, solution, code): return json.loads(fix_llm_json_str(data)), success - def aiCheckCode(self, fileTask, code): + def aiCheckCode(self, requirementID, fileTask, code): goodCodeRe, success = self.aiReviewCode(fileTask, code) jsonData = {"reasoning": goodCodeRe, "code": code} @@ -116,7 +116,7 @@ def aiCheckCode(self, fileTask, code): return jsonData, success - def aiReviewCode(self, fileTask, code): + def aiReviewCode(self, requirementID, fileTask, code): prompt = f""" NOTICE Role: You are a professional software engineer, Your task is to review the code. @@ -146,7 +146,7 @@ def aiReviewCode(self, fileTask, code): return data, success - def aiMergeCode(self, task, baseCode, newCode): + def aiMergeCode(self, requirementID, task, baseCode, newCode): prompt = f""" As a senior full stack developer. Your task is to integrate with existing code according to the "Development Task" and "Development Task corresponding code" provided below. In the process of integrating code, you must use the existing code as a baseline, and always be careful to ensure that the functionality of the existing code body is not affected. The consolidated code responds according to the response format example. @@ -176,7 +176,7 @@ def aiMergeCode(self, task, baseCode, newCode): return json.loads(fix_llm_json_str(data)), success - def aiGenCode(self, fileTask, newTask, newCode): + def aiGenCode(self, requirementID, fileTask, newTask, newCode): prompt = f""" As a senior full stack developer. you need to modify the "basic code" based on the "change suggestions" and return all the complete code that works well. The code style is consistent with the "base code", try not to break the original function. diff --git a/backend/app/pkgs/prompt/code_interface.py b/backend/app/pkgs/prompt/code_interface.py index 96a0423e5..552c10b7e 100644 --- a/backend/app/pkgs/prompt/code_interface.py +++ b/backend/app/pkgs/prompt/code_interface.py @@ -4,25 +4,25 @@ class CodeInterface(ABC): @abstractmethod - def aiReferenceRepair(self, newCode, referenceCode, fileTask): + def aiReferenceRepair(self, requirementID, newCode, referenceCode, fileTask): pass @abstractmethod - def aiAnalyzeError(self, message): + def aiAnalyzeError(self, requirementID, message): pass @abstractmethod - def aiFixError(self, solution, code): + def aiFixError(self, requirementID, solution, code): pass @abstractmethod - def aiCheckCode(self, fileTask, code): + def aiCheckCode(self, requirementID, fileTask, code): pass @abstractmethod - def aiMergeCode(self, task, baseCode, newCode): + def aiMergeCode(self, requirementID, task, baseCode, newCode): pass @abstractmethod - def aiGenCode(self, fileTask, newTask, newCode): + def aiGenCode(self, requirementID, fileTask, newTask, newCode): pass \ No newline at end of file diff --git a/backend/app/pkgs/prompt/prompt.py b/backend/app/pkgs/prompt/prompt.py index f1ffccb6a..2c94d4b46 100644 --- a/backend/app/pkgs/prompt/prompt.py +++ b/backend/app/pkgs/prompt/prompt.py @@ -10,23 +10,23 @@ from app.pkgs.prompt.code_pro import CodePro from config import GRADE -def clarifyRequirement(userPrompt, globalContext, appArchitecture): +def clarifyRequirement(requirementID, userPrompt, globalContext, appArchitecture): if GRADE == "base": obj = RequirementBasic() else: obj = RequirementPro() - return obj.clarifyRequirement(userPrompt, globalContext, appArchitecture) + return obj.clarifyRequirement(requirementID, userPrompt, globalContext, appArchitecture) -def clarifyAPI(userPrompt, apiDoc): +def clarifyAPI(requirementID, userPrompt, apiDoc): if GRADE == "base": obj = ApiBasic() else: obj = ApiPro() - return obj.clarifyAPI(userPrompt, apiDoc) + return obj.clarifyAPI(requirementID, userPrompt, apiDoc) -def splitTask(newfeature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID): +def splitTask(requirementID, newfeature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID): if GRADE == "base": obj = SubtaskBasic() else: @@ -37,52 +37,52 @@ def splitTask(newfeature, serviceName, appBasePrompt, projectInfo, projectLib, s else: obj = SubtaskPro() - return obj.splitTask(newfeature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID) + return obj.splitTask(requirementID, newfeature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID) -def aiReferenceRepair(newCode, referenceCode, fileTask): +def aiReferenceRepair(requirementID, newCode, referenceCode, fileTask): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiReferenceRepair(newCode, referenceCode, fileTask) + return obj.aiReferenceRepair(requirementID, newCode, referenceCode, fileTask) -def aiAnalyzeError(message): +def aiAnalyzeError(requirementID, message): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiAnalyzeError(message) + return obj.aiAnalyzeError(requirementID, message) -def aiFixError(solution, code): +def aiFixError(requirementID, solution, code): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiFixError(solution, code) + return obj.aiFixError(requirementID, solution, code) -def aiCheckCode(fileTask, code): +def aiCheckCode(requirementID, fileTask, code): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiCheckCode(fileTask, code) + return obj.aiCheckCode(requirementID, fileTask, code) -def aiMergeCode(fileTask, appName, baseCode, newCode): +def aiMergeCode(requirementID, fileTask, appName, baseCode, newCode): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiMergeCode(fileTask, appName, baseCode, newCode) + return obj.aiMergeCode(requirementID, fileTask, appName, baseCode, newCode) -def aiGenCode(fileTask, newTask, newCode): +def aiGenCode(requirementID, fileTask, newTask, newCode): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiGenCode(fileTask, newTask, newCode) \ No newline at end of file + return obj.aiGenCode(requirementID, fileTask, newTask, newCode) \ No newline at end of file diff --git a/backend/app/pkgs/prompt/requirement_basic.py b/backend/app/pkgs/prompt/requirement_basic.py index f489fdf31..f6d9e335c 100644 --- a/backend/app/pkgs/prompt/requirement_basic.py +++ b/backend/app/pkgs/prompt/requirement_basic.py @@ -7,7 +7,7 @@ from app.pkgs.tools.llm import chatCompletion class RequirementBasic(RequirementInterface): - def clarifyRequirement(self, userPrompt, globalContext, appArchitecture): + def clarifyRequirement(self, requirementID, userPrompt, globalContext, appArchitecture): _ = getI18n("prompt") requirementsDetail = _("Prerequisites, Detailed Operation Steps, Expected Results, Other Explanatory Notes.") diff --git a/backend/app/pkgs/prompt/requirement_interface.py b/backend/app/pkgs/prompt/requirement_interface.py index 543f221bd..f4ba0a39f 100644 --- a/backend/app/pkgs/prompt/requirement_interface.py +++ b/backend/app/pkgs/prompt/requirement_interface.py @@ -4,5 +4,5 @@ class RequirementInterface(ABC): @abstractmethod - def clarifyRequirement(self, userPrompt, globalContext, appArchitecture): + def clarifyRequirement(self, requirementID, userPrompt, globalContext, appArchitecture): pass \ No newline at end of file diff --git a/backend/app/pkgs/prompt/subtask_basic.py b/backend/app/pkgs/prompt/subtask_basic.py index 4bbdad84b..fc18d161e 100644 --- a/backend/app/pkgs/prompt/subtask_basic.py +++ b/backend/app/pkgs/prompt/subtask_basic.py @@ -8,7 +8,7 @@ from config import MODE class SubtaskBasic(SubtaskInterface): - def splitTask(self, feature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID): + def splitTask(self, requirementID, feature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID): #return setpGenCode(TEST_PSEUDOCODE, feature, appBasePrompt, "- You can choose any appropriate development language", serviceStruct) if MODE == "FAKE": time.sleep(5) diff --git a/backend/app/pkgs/prompt/subtask_interface.py b/backend/app/pkgs/prompt/subtask_interface.py index 715b5510b..4f8a3b4de 100644 --- a/backend/app/pkgs/prompt/subtask_interface.py +++ b/backend/app/pkgs/prompt/subtask_interface.py @@ -4,5 +4,5 @@ class SubtaskInterface(ABC): @abstractmethod - def splitTask(self, feature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID): + def splitTask(self, requirementID, feature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID): pass \ No newline at end of file diff --git a/backend/config.py b/backend/config.py index cde6d2cfb..6c06d244b 100644 --- a/backend/config.py +++ b/backend/config.py @@ -24,6 +24,31 @@ def read_config(key): REQUIREMENT_STATUS_Evaluated = "Evaluated" REQUIREMENT_STATUS_Canceled = "Canceled" +REQUIREMENT_MEM_STEP_Requirement_clarify = "Requirement_clarify" +REQUIREMENT_MEM_STEP_Requirement_organize = "Requirement_organize" +REQUIREMENT_MEM_STEP_API_subtasks = "API_subtasks" +REQUIREMENT_MEM_STEP_API_organize = "API_organize" +REQUIREMENT_MEM_STEP_Subtask_chooseLib = "Subtask_chooseLib" +REQUIREMENT_MEM_STEP_Subtask_subtasks = "Subtask_subtasks" +REQUIREMENT_MEM_STEP_Subtask_pseudocode = "Subtask_pseudocode" +REQUIREMENT_MEM_STEP_Subtask_code = "Subtask_code" +REQUIREMENT_MEM_STEP_Code_checkCode = "Code_checkCode" +REQUIREMENT_MEM_STEP_Code_referenceRepair = "Code_referenceRepair" +REQUIREMENT_MEM_STEP_Code_analyzeError = "Code_analyzeError" +REQUIREMENT_MEM_STEP_Code_fixError = "Code_fixError" +REQUIREMENT_MEM_STEP_Code_reviewCode = "Code_reviewCode" +REQUIREMENT_MEM_STEP_Code_mergeCode = "Code_mergeCode" +REQUIREMENT_MEM_STEP_Code_genCode = "Code_genCode" +REQUIREMENT_MEM_STEP_DevOps_compileCheck = "DevOps_compileCheck" +REQUIREMENT_MEM_STEP_DevOps_lintCheck = "DevOps_lintCheck" +REQUIREMENT_MEM_STEP_DevOps_unitTest = "DevOps_unitTest" +REQUIREMENT_MEM_STEP_DevOps_apiTest = "DevOps_apiTest" +REQUIREMENT_MEM_TYPE_RequirementDocument = "RequirementDocument" +REQUIREMENT_MEM_TYPE_APIDocument = "APIDocument" +REQUIREMENT_MEM_STEP_Subtask = "Subtask" +REQUIREMENT_MEM_STEP_Code = "Code" +REQUIREMENT_MEM_STEP_DevOps = "DevOps" + try: BACKEND_HOST = read_config("BACKEND_HOST") BACKEND_DEBUG = read_config("BACKEND_DEBUG") diff --git a/frontend/requirement.html b/frontend/requirement.html index b16c57ea9..18e09c9e1 100644 --- a/frontend/requirement.html +++ b/frontend/requirement.html @@ -48,7 +48,7 @@
- +
diff --git a/frontend/static/js/coder.js b/frontend/static/js/coder.js index 7f57fff80..2997ea711 100644 --- a/frontend/static/js/coder.js +++ b/frontend/static/js/coder.js @@ -472,7 +472,7 @@ function fixLint(solution, uuid, file_path, service_name, times) { $("#task_status_td_" + uuid).html(str) $('.task_status_fix_lint_button').popup(); - var requestData = JSON.stringify({ 'code': code, 'solution': solution }) + var requestData = JSON.stringify({ 'code': code, 'solution': solution, 'task_id': getTaskID() }) successCallback = function(data) { let buttonid = "task_status_fix_lint_"+globalCompileTimes[service_name.replace("/","-")]+"_"+times+"_"+uuid @@ -518,7 +518,7 @@ function fixCompile(solution, uuid, file_path, service_name, times) { $("#task_status_td_" + uuid).html(str) $('.task_status_fix_compile_button').popup(); - var requestData = JSON.stringify({ 'code': code, 'solution': solution }) + var requestData = JSON.stringify({ 'code': code, 'solution': solution, 'task_id': getTaskID() }) successCallback = function(data) { let buttonid = "task_status_fix_compile_"+globalCompileTimes[service_name.replace("/","-")]+"_"+times+"_"+uuid @@ -752,7 +752,7 @@ function editFileTask(service_name, file_idx) { $("#task_status_td_" + uuid).html(str) $('.task_status_button').popup(); - var requestData = JSON.stringify({ 'file_task': fileTask, 'new_task': newTask, 'new_code': newCode }) + var requestData = JSON.stringify({ 'file_task': fileTask, 'new_task': newTask, 'new_code': newCode, 'task_id': getTaskID() }) successCallback = function(data){ $("#task_status_redo_"+uuid).children().removeClass("spinner") @@ -791,7 +791,7 @@ function mergeCode(uuid, newCode, oldCode, fileTask, service_name, file_path) { $("#task_status_td_" + uuid).html(str) $('.task_status_button').popup(); - var requestData = JSON.stringify({ 'file_task': fileTask, 'new_code': newCode, 'old_code': oldCode }) + var requestData = JSON.stringify({ 'file_task': fileTask, 'new_code': newCode, 'old_code': oldCode, 'task_id': getTaskID() }) successCallback = function(data) { $("#task_status_check_"+uuid).children().removeClass("spinner") @@ -832,7 +832,7 @@ function referenceRepair(newCode, fileTask, uuid, referenceFile, repo, file_path $("#task_status_td_" + uuid).html(str) $('.task_status_button').popup(); - var requestData = JSON.stringify({ 'new_code': newCode, 'file_task': fileTask, 'reference_file': referenceFile, 'repo': repo }) + var requestData = JSON.stringify({ 'new_code': newCode, 'file_task': fileTask, 'reference_file': referenceFile, 'repo': repo, 'task_id': getTaskID() }) successCallback = function(data) { $("#task_status_check_"+uuid).children().removeClass("spinner") @@ -1240,7 +1240,7 @@ function genInterfaceDoc(customPrompt, thisElement) { thinkUI(customPrompt, globalFrontendText["ai_think"]) - var requestData = JSON.stringify({ 'user_prompt': customPrompt }) + var requestData = JSON.stringify({ 'user_prompt': customPrompt, 'task_id': getTaskID() }) var retruBtn = '

' successCallback = function(data) { @@ -1286,7 +1286,7 @@ function taskAnalysis(customPrompt, service_name, hideUserPrompt, thisElement) { $('html, body').animate({ scrollTop: $(document).height() }, 'slow'); }, 900); - var requestData = JSON.stringify({ 'service_name': service_name, 'api_doc': customPrompt }) + var requestData = JSON.stringify({ 'service_name': service_name, 'api_doc': customPrompt, 'task_id': getTaskID() }) var retruBtn = '

' From 2389afd1b66a7bfb6b08dc000961fccf1761391a Mon Sep 17 00:00:00 2001 From: booboosui Date: Mon, 28 Aug 2023 14:25:55 +0800 Subject: [PATCH 2/5] feat(requirement_memory): save data 100% --- backend/app/controllers/requirement.py | 2 +- backend/app/controllers/setting.py | 16 ++---- backend/app/controllers/step_api.py | 5 +- backend/app/controllers/step_code.py | 2 +- backend/app/controllers/step_devops.py | 59 ++++++++++----------- backend/app/controllers/step_requirement.py | 9 ++-- backend/app/controllers/step_subtask.py | 16 +++--- backend/app/controllers/workspace.py | 42 ++++++--------- backend/app/models/requirement.py | 25 ++++++++- backend/app/pkgs/devops/cd.py | 11 +++- backend/app/pkgs/devops/devops.py | 11 +++- backend/app/pkgs/knowledge/app_info.py | 7 ++- backend/app/pkgs/prompt/code_basic.py | 2 +- backend/app/pkgs/prompt/subtask_basic.py | 14 ++--- backend/config.py | 1 + frontend/static/js/coder.js | 10 ++-- 16 files changed, 126 insertions(+), 106 deletions(-) diff --git a/backend/app/controllers/requirement.py b/backend/app/controllers/requirement.py index adb2eafc0..bd6b478bd 100644 --- a/backend/app/controllers/requirement.py +++ b/backend/app/controllers/requirement.py @@ -33,7 +33,7 @@ def setup_app(): featureBranch = data['feature_branch'] username = session['username'] - requirement = Requirement.create_requirement("", "New", appID, 1, REQUIREMENT_STATUS_NotStarted, 0, 0) + requirement = Requirement.create_requirement("", "New", appID, 1, sourceBranch, featureBranch, REQUIREMENT_STATUS_NotStarted, 0, 0) session[username]['memory']['task_info'] = { "app_id": appID, diff --git a/backend/app/controllers/setting.py b/backend/app/controllers/setting.py index 421034af2..3bfc3898f 100644 --- a/backend/app/controllers/setting.py +++ b/backend/app/controllers/setting.py @@ -10,11 +10,9 @@ @json_response def get_git_config_list(): _ = getI18n("controllers") - username = session['username'] tenantID = session['tenant_id'] - appID = session[username]['memory']['task_info']['app_id'] - gitList, success = getGitConfigList(tenantID, appID) + gitList, success = getGitConfigList(tenantID, 0) if not success: raise Exception(_("Failed to get git config list.")) @@ -24,11 +22,9 @@ def get_git_config_list(): @json_response def get_ci_config_list(): _ = getI18n("controllers") - username = session['username'] tenantID = session['tenant_id'] - appID = session[username]['memory']['task_info']['app_id'] - gitList, success = getCIConfigList(tenantID, appID) + gitList, success = getCIConfigList(tenantID, 0) if not success: raise Exception(_("Failed to get git config list.")) @@ -38,11 +34,9 @@ def get_ci_config_list(): @json_response def get_cd_config_list(): _ = getI18n("controllers") - username = session['username'] tenantID = session['tenant_id'] - appID = session[username]['memory']['task_info']['app_id'] - gitList, success = getCDConfigList(tenantID, appID) + gitList, success = getCDConfigList(tenantID, 0) if not success: raise Exception(_("Failed to get git config list.")) @@ -52,11 +46,9 @@ def get_cd_config_list(): @json_response def get_llm_config_list(): _ = getI18n("controllers") - username = session['username'] tenantID = session['tenant_id'] - appID = session[username]['memory']['task_info']['app_id'] - gitList, success = getLLMConfigList(tenantID, appID) + gitList, success = getLLMConfigList(tenantID, 0) if not success: raise Exception(_("Failed to get git config list.")) diff --git a/backend/app/controllers/step_api.py b/backend/app/controllers/step_api.py index 8830c13e3..fea8c4932 100644 --- a/backend/app/controllers/step_api.py +++ b/backend/app/controllers/step_api.py @@ -4,6 +4,7 @@ from app.pkgs.tools.i18b import getI18n from app.pkgs.prompt.prompt import clarifyAPI from app.pkgs.knowledge.app_info import getServiceSwagger +from app.models.requirement import Requirement bp = Blueprint('step_api', __name__, url_prefix='/step_api') @@ -16,8 +17,8 @@ def gen_interface_doc(): requirementID = request.json.get('task_id') # todo Use llm to determine which interface documents to adjust - appID = session[username]['memory']['task_info']['app_id'] - apiDoc, success = getServiceSwagger(appID, 0) + req = Requirement.get_requirement_by_id(requirementID) + apiDoc, success = getServiceSwagger(req["app_id"], 0) msg, success = clarifyAPI(requirementID, userPrompt, apiDoc) diff --git a/backend/app/controllers/step_code.py b/backend/app/controllers/step_code.py index d85da830b..60c6c085c 100644 --- a/backend/app/controllers/step_code.py +++ b/backend/app/controllers/step_code.py @@ -22,7 +22,7 @@ def edit_file_task(): return {'success': success, 'code': re["code"], 'reasoning': re["reasoning"]} -@bp.route('/check_file', methods=['POST']) +@bp.route('/check_code', methods=['POST']) @json_response def check_file(): _ = getI18n("controllers") diff --git a/backend/app/controllers/step_devops.py b/backend/app/controllers/step_devops.py index 5b7b84f30..2dad81710 100644 --- a/backend/app/controllers/step_devops.py +++ b/backend/app/controllers/step_devops.py @@ -10,6 +10,7 @@ from app.models.application_service import ApplicationService from flask import Blueprint from app.models.setting import getCIConfigList, getCDConfigList +from app.models.requirement import Requirement bp = Blueprint('step_devops', __name__, url_prefix='/step_devops') @@ -18,29 +19,29 @@ def trigger_ci(): serviceName = request.json.get('repo_path') username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] - serviceInfo = ApplicationService.get_service_by_name(appID, serviceName) + requirementID = request.json.get('task_id') + req = Requirement.get_requirement_by_id(requirementID) + serviceInfo = ApplicationService.get_service_by_name(req["app_id"], serviceName) tenantID = session['tenant_id'] - appID = session[username]['memory']['task_info']['app_id'] - ciConfigList, success = getCIConfigList(tenantID, appID) + ciConfigList, success = getCIConfigList(tenantID, req["app_id"]) branch = session[username]['memory']['task_info']['feature_branch'] - result, piplineID, piplineUrl, success = triggerPipeline(branch, serviceInfo, ciConfigList[0]) + result, piplineID, piplineUrl, success = triggerPipeline(requirementID, branch, serviceInfo, ciConfigList[0]) if success: return {"name": 'ci', "info": {"piplineID": piplineID, "repopath": serviceInfo["git_path"], "piplineUrl": piplineUrl}} else: raise Exception(result) -@bp.route('/plugin_ci', methods=['GET']) +@bp.route('/query_ci', methods=['GET']) @json_response def plugin_ci(): pipeline_id = request.args.get('piplineID') repopath = request.args.get('repopath') tenantID = session['tenant_id'] - username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] - ciConfigList, success = getCIConfigList(tenantID, appID) + requirementID = request.args.get('task_id') + req = Requirement.get_requirement_by_id(requirementID) + ciConfigList, success = getCIConfigList(tenantID, req["app_id"] ) piplineJobs, success = getPipelineStatus(pipeline_id, repopath, ciConfigList[0]) print("piplineJobs:", piplineJobs) @@ -56,20 +57,19 @@ def plugin_ci(): @json_response def check_compile(): _ = getI18n("controllers") - task_id = request.json.get('task_id') + requirementID = request.json.get('task_id') serviceName = request.json.get('repo_path') - wsPath = get_ws_path(task_id) - username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] - gitPath, success = getServiceGitPath(appID, serviceName) + wsPath = get_ws_path(requirementID) + req = Requirement.get_requirement_by_id(requirementID) + gitPath, success = getServiceGitPath(req["app_id"], serviceName) - success, message = compileCheck(task_id, wsPath, gitPath) + success, message = compileCheck(requirementID, wsPath, gitPath) if success: reasoning = _("Compile check pass.") return {'pass': True, 'message': message, 'reasoning': reasoning} else: - reasoning, success = aiAnalyzeError(task_id, message) + reasoning, success = aiAnalyzeError(requirementID, message) if success: return {'pass': False, 'message': message, 'reasoning': reasoning} else: @@ -80,21 +80,20 @@ def check_compile(): @json_response def check_lint(): _ = getI18n("controllers") - task_id = request.json.get('task_id') + requirementID = request.json.get('task_id') file_path = request.json.get('file_path') serviceName = request.json.get('service_name') - username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] - gitPath, success = getServiceGitPath(appID, serviceName) - ws_path = get_ws_path(task_id) + req = Requirement.get_requirement_by_id(requirementID) + gitPath, success = getServiceGitPath(req["app_id"], serviceName) + ws_path = get_ws_path(requirementID) - success, message = lintCheck(ws_path, gitPath, file_path) + success, message = lintCheck(requirementID, ws_path, gitPath, file_path) if success: reasoning = _("Static code scan passed.") return {'pass': True, 'message': message, 'reasoning': reasoning} else: - reasoning, success = aiAnalyzeError(task_id, message) + reasoning, success = aiAnalyzeError(requirementID, message) if success: return {'pass': False, 'message': message, 'reasoning': reasoning} else: @@ -103,17 +102,15 @@ def check_lint(): @bp.route('/trigger_cd', methods=['POST']) @json_response def trigger_cd(): - username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] + requirementID = request.json.get('task_id') + req = Requirement.get_requirement_by_id(requirementID) serviceName = request.json.get('repo_path') - serviceInfo = ApplicationService.get_service_by_name(appID, serviceName) - image, success = getServiceDockerImage(appID, serviceName) + serviceInfo = ApplicationService.get_service_by_name(req["app_id"], serviceName) + image, success = getServiceDockerImage(req["app_id"], serviceName) tenantID = session['tenant_id'] - username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] - cdConfigList, success = getCDConfigList(tenantID, appID) + cdConfigList, success = getCDConfigList(tenantID, req["app_id"]) - result, success = triggerCD(image, serviceInfo, cdConfigList[0]) + result, success = triggerCD(requirementID, image, serviceInfo, cdConfigList[0]) if success: return {"internet_ip": result} else: diff --git a/backend/app/controllers/step_requirement.py b/backend/app/controllers/step_requirement.py index 699ec6dc5..9a16cda5a 100644 --- a/backend/app/controllers/step_requirement.py +++ b/backend/app/controllers/step_requirement.py @@ -18,14 +18,15 @@ def clarify(): userName = session["username"] requirementID = request.json.get('task_id') - appID = session[userName]['memory']['task_info']['app_id'] + req = Requirement.get_requirement_by_id(requirementID) - if len(appID) == 0 or not appID: + if not req["app_id"] or req["app_id"] < 1 : raise Exception(_("Please select the application you want to develop.")) - Requirement.update_requirement(requirement_id=requirementID, original_requirement=userPrompt, status=REQUIREMENT_STATUS_InProgress) + if len(globalContext) < 4 : + Requirement.update_requirement(requirement_id=requirementID, original_requirement=userPrompt, status=REQUIREMENT_STATUS_InProgress) - appArchitecture, _ = getAppArchitecture(appID) + appArchitecture, _ = getAppArchitecture(req["app_id"]) msg, success = clarifyRequirement(requirementID, userPrompt, globalContext, appArchitecture) if success: diff --git a/backend/app/controllers/step_subtask.py b/backend/app/controllers/step_subtask.py index 931d40088..f664ae766 100644 --- a/backend/app/controllers/step_subtask.py +++ b/backend/app/controllers/step_subtask.py @@ -2,11 +2,11 @@ from app.controllers.common import json_response from app.pkgs.devops.local_tools import getFileContent from app.pkgs.tools.i18b import getI18n -from app.pkgs.tools.file_tool import get_ws_path from flask import Blueprint from app.pkgs.prompt.prompt import splitTask from app.pkgs.knowledge.app_info import getServiceSwagger from app.pkgs.knowledge.app_info import getServiceBasePrompt, getServiceIntro, getServiceLib, getServiceStruct +from app.models.requirement import Requirement bp = Blueprint('step_subtask', __name__, url_prefix='/step_subtask') @@ -23,8 +23,8 @@ def analysis(): requirementID = request.json.get('task_id') # todo Use llm to determine which interface documents to adjust - appID = session[username]['memory']['task_info']['app_id'] - defaultApiDoc, success = getServiceSwagger(appID, 0) + req = Requirement.get_requirement_by_id(requirementID) + defaultApiDoc, success = getServiceSwagger(req["app_id"], 0) if len(defaultApiDoc) > 0: newfeature = requirementDoc+""" @@ -37,12 +37,12 @@ def analysis(): else: newfeature = requirementDoc - appBasePrompt, _ = getServiceBasePrompt(appID, serviceName) - projectInfo, _ = getServiceIntro(appID, serviceName) - projectLib, _ = getServiceLib(appID, serviceName) - serviceStruct,_ = getServiceStruct(appID, serviceName) + appBasePrompt, _ = getServiceBasePrompt(req["app_id"], serviceName) + projectInfo, _ = getServiceIntro(req["app_id"], serviceName) + projectLib, _ = getServiceLib(req["app_id"], serviceName) + serviceStruct,_ = getServiceStruct(req["app_id"], serviceName) - filesToEdit, success = splitTask(requirementID, newfeature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID) + filesToEdit, success = splitTask(requirementID, newfeature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, req["app_id"]) if success: for index, file in enumerate(filesToEdit): diff --git a/backend/app/controllers/workspace.py b/backend/app/controllers/workspace.py index 1b5ae7b44..4bea31af8 100644 --- a/backend/app/controllers/workspace.py +++ b/backend/app/controllers/workspace.py @@ -16,14 +16,13 @@ @json_response def save_code(): _ = getI18n("controllers") - task_id = request.json.get('task_id') + requirementID = request.json.get('task_id') file_path = request.json.get('file_path') serviceName = request.json.get('service_name') code = request.json.get('code') - username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] - gitPath, success = getServiceGitPath(appID, serviceName) - path = get_ws_path(task_id)+'/'+gitPath+"/"+file_path + req = Requirement.get_requirement_by_id(requirementID) + gitPath, success = getServiceGitPath(req["app_id"] , serviceName) + path = get_ws_path(requirementID)+'/'+gitPath+"/"+file_path write_file_content(path, code) return _("Saved code successfully.") @@ -32,26 +31,20 @@ def save_code(): @json_response def create(): _ = getI18n("controllers") - task_id = request.json.get('task_id') + requirementID = request.json.get('task_id') serviceName = request.json.get('repo_path') - base_branch = request.json.get('base_branch') - fature_branch = request.json.get('feature_branch') - ws_path = get_ws_path(task_id) - username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] - print(appID) - print("@@@@@@@@") - gitPath, success = getServiceGitPath(appID, serviceName) + ws_path = get_ws_path(requirementID) + req = Requirement.get_requirement_by_id(requirementID) + + gitPath, success = getServiceGitPath(req["app_id"], serviceName) tenantID = session['tenant_id'] - username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] - gitConfigList, success = getGitConfigList(tenantID, appID) + gitConfigList, success = getGitConfigList(tenantID, req["app_id"]) if not GIT_ENABLED: success = True else: - success, msg = pullCode(ws_path, gitPath, base_branch, fature_branch, gitConfigList) + success, msg = pullCode(ws_path, gitPath, req["default_source_branch"], req["default_target_branch"], gitConfigList) if success: return _("Create workspace successfully.") @@ -64,18 +57,17 @@ def gitpush(): _ = getI18n("controllers") username = session['username'] commitMsg = session[username]['memory']['originalPrompt'] - task_id = request.json.get('task_id') + requirementID = request.json.get('task_id') serviceName = request.json.get('service_name') fatureBranch = session[username]['memory']['task_info']['feature_branch'] - wsPath = get_ws_path(task_id) - appID = session[username]['memory']['task_info']['app_id'] - gitPath, success = getServiceGitPath(appID, serviceName) + wsPath = get_ws_path(requirementID) + req = Requirement.get_requirement_by_id(requirementID) + gitPath, success = getServiceGitPath(req["app_id"], serviceName) tenantID = session['tenant_id'] username = session['username'] - appID = session[username]['memory']['task_info']['app_id'] - gitConfigList, success = getGitConfigList(tenantID, appID) + gitConfigList, success = getGitConfigList(tenantID, req["app_id"]) - Requirement.update_requirement(requirement_id=task_id, status=REQUIREMENT_STATUS_Completed) + Requirement.update_requirement(requirement_id=requirementID, status=REQUIREMENT_STATUS_Completed) if not GIT_ENABLED: raise Exception(_("Failed to push code.")+f" You did not set Git parameters in the configuration file.") diff --git a/backend/app/models/requirement.py b/backend/app/models/requirement.py index 1a5a03877..f55a31a97 100644 --- a/backend/app/models/requirement.py +++ b/backend/app/models/requirement.py @@ -6,6 +6,8 @@ class Requirement(db.Model): original_requirement = db.Column(db.String(1000)) app_id = db.Column(db.Integer, nullable=False) user_id = db.Column(db.Integer, nullable=False) + default_source_branch = db.Column(db.String(255)) + default_target_branch = db.Column(db.String(255)) status = db.Column(db.String(20)) satisfaction_rating = db.Column(db.Integer) completion_rating = db.Column(db.Integer) @@ -13,13 +15,15 @@ class Requirement(db.Model): updated_at = db.Column(db.TIMESTAMP, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp()) @staticmethod - def create_requirement(requirement_name, original_requirement, app_id, user_id, status, satisfaction_rating=None, completion_rating=None): + def create_requirement(requirement_name, original_requirement, app_id, user_id, default_source_branch, default_target_branch, status, satisfaction_rating=None, completion_rating=None): requirement = Requirement( requirement_name=requirement_name, original_requirement=original_requirement, app_id=app_id, user_id=user_id, status=status, + default_source_branch=default_source_branch, + default_target_branch=default_target_branch, satisfaction_rating=satisfaction_rating, completion_rating=completion_rating ) @@ -39,6 +43,8 @@ def get_all_requirements(app_id=None): 'original_requirement': req.original_requirement, 'app_id': req.app_id, 'user_id': req.user_id, + 'default_source_branch': req.default_source_branch, + 'default_target_branch': req.default_target_branch, 'status': req.status, 'satisfaction_rating': req.satisfaction_rating, 'completion_rating': req.completion_rating, @@ -51,7 +57,22 @@ def get_all_requirements(app_id=None): @staticmethod def get_requirement_by_id(requirement_id): - return Requirement.query.get(requirement_id) + req = Requirement.query.get(requirement_id) + req_dict = { + 'requirement_id': req.requirement_id, + 'requirement_name': req.requirement_name, + 'original_requirement': req.original_requirement, + 'app_id': req.app_id, + 'user_id': req.user_id, + 'default_source_branch': req.default_source_branch, + 'default_target_branch': req.default_target_branch, + 'status': req.status, + 'satisfaction_rating': req.satisfaction_rating, + 'completion_rating': req.completion_rating, + 'created_at': req.created_at, + 'updated_at': req.updated_at + } + return req_dict @staticmethod def update_requirement(requirement_id, requirement_name=None, original_requirement=None, app_id=None, user_id=None, status=None, satisfaction_rating=None, completion_rating=None): diff --git a/backend/app/pkgs/devops/cd.py b/backend/app/pkgs/devops/cd.py index cd5e6a15a..1b51ea5cc 100644 --- a/backend/app/pkgs/devops/cd.py +++ b/backend/app/pkgs/devops/cd.py @@ -1,7 +1,9 @@ from app.pkgs.devops.cd_aliyun import CDAliyun from app.pkgs.devops.cd_local import CDLocal +from app.pkgs.devops.devops_pro import triggerCDPro +from config import GRADE -def triggerCD(image, serviceInfo, cdConfig): +def triggerCD(requirementID, image, serviceInfo, cdConfig): CD_TOOLS = cdConfig["cd_provider"] if CD_TOOLS == 'local': @@ -9,4 +11,9 @@ def triggerCD(image, serviceInfo, cdConfig): elif CD_TOOLS == 'aliyun': obj = CDAliyun() - return obj.triggerCD(image, serviceInfo, cdConfig) \ No newline at end of file + re, success = obj.triggerCD(image, serviceInfo, cdConfig) + + if GRADE != "base": + triggerCDPro(requirementID, image, re) + + return re, success \ No newline at end of file diff --git a/backend/app/pkgs/devops/devops.py b/backend/app/pkgs/devops/devops.py index 847a61929..5f38f34b3 100644 --- a/backend/app/pkgs/devops/devops.py +++ b/backend/app/pkgs/devops/devops.py @@ -1,8 +1,10 @@ from app.pkgs.devops.devops_gitlab import DevopsGitlab from app.pkgs.devops.devops_local import DevopsLocal from app.pkgs.devops.devops_github import DevopsGitHub +from app.pkgs.devops.devops_pro import triggerPipelinePro +from config import GRADE -def triggerPipeline(branchName, serviceInfo, ciConfig): +def triggerPipeline(requirementID, branchName, serviceInfo, ciConfig): DEVOPS_TOOLS = ciConfig["ci_provider"] if DEVOPS_TOOLS == 'local': @@ -11,8 +13,13 @@ def triggerPipeline(branchName, serviceInfo, ciConfig): obj = DevopsGitlab() elif DEVOPS_TOOLS == 'github': obj = DevopsGitHub() + + result, piplineID, piplineUrl, success = obj.triggerPipeline(branchName, serviceInfo, ciConfig) + + if GRADE != "base": + triggerPipelinePro(requirementID, branchName, {"piplineUrl": piplineUrl, "piplineID": piplineID}) - return obj.triggerPipeline(branchName, serviceInfo, ciConfig) + return result, piplineID, piplineUrl, success def getPipelineStatus(piplineId, repoPath, ciConfig): DEVOPS_TOOLS = ciConfig["ci_provider"] diff --git a/backend/app/pkgs/knowledge/app_info.py b/backend/app/pkgs/knowledge/app_info.py index f7bf008d5..dafe9dcbf 100644 --- a/backend/app/pkgs/knowledge/app_info.py +++ b/backend/app/pkgs/knowledge/app_info.py @@ -24,10 +24,9 @@ def getServiceSwagger(appID, serviceName): if len(apps) > 0: services = apps[0]["service"] for service in services: - if service["name"] == serviceName: - # todo get interface document content dynamically - # todo Use llm to determine which interface documents to adjust - swaggerDoc = service["api_location"] + # todo get interface document content dynamically + # todo Use llm to determine which interface documents to adjust + swaggerDoc = service["api_location"] return swaggerDoc, True diff --git a/backend/app/pkgs/prompt/code_basic.py b/backend/app/pkgs/prompt/code_basic.py index cd695ce04..ef60d54c9 100644 --- a/backend/app/pkgs/prompt/code_basic.py +++ b/backend/app/pkgs/prompt/code_basic.py @@ -81,7 +81,7 @@ def aiFixError(self, requirementID, solution, code): def aiCheckCode(self, requirementID, fileTask, code): - goodCodeRe, success = self.aiReviewCode(fileTask, code) + goodCodeRe, success = self.aiReviewCode(requirementID, fileTask, code) jsonData = {"reasoning": goodCodeRe, "code": code} diff --git a/backend/app/pkgs/prompt/subtask_basic.py b/backend/app/pkgs/prompt/subtask_basic.py index fc18d161e..fded9ca53 100644 --- a/backend/app/pkgs/prompt/subtask_basic.py +++ b/backend/app/pkgs/prompt/subtask_basic.py @@ -32,14 +32,14 @@ def splitTask(self, requirementID, feature, serviceName, appBasePrompt, projectI # pseudocode pseudocode, success = setpPseudocode(ctx, subtask, serviceStruct, appBasePrompt) if success: - return setpGenCode(pseudocode, feature, appBasePrompt, specification, serviceStruct) + return setpGenCode(pseudocode, feature, appBasePrompt, specification, serviceStruct, serviceName) else: return pseudocode, False else: return subtask, False -def setpGenCode(pseudocode, feature, appBasePrompt, specification, serviceStruct): +def setpGenCode(pseudocode, feature, appBasePrompt, specification, serviceStruct, serviceName): context = [] context.append({ "role": "system", @@ -75,7 +75,7 @@ def setpGenCode(pseudocode, feature, appBasePrompt, specification, serviceStruct You will output the content of each file including ALL code. Each code file must strictly follow a markdown code block format, where the following tokens must be replaced such that -FILEPATH is the lowercase file name including the file extension +FILEPATH is a file name that contains the file extension LANG is the markup code block language for the code's language CODE_EXPLANATION explain the code you provide in detail, this explain should be independent. For example: specific variable names and types to be added and modified, method names to be added or modified, parameter names, and so on CODE is the code: @@ -96,7 +96,7 @@ def setpGenCode(pseudocode, feature, appBasePrompt, specification, serviceStruct # success = True data, success = chatCompletion(context) - jsonData = parse_chat(data) + jsonData = parse_chat(data, serviceName) print(jsonData) return jsonData, success @@ -117,7 +117,7 @@ def setpPseudocode(context, subtask, serviceStruct, appBasePrompt): ``` Each pseudocode file must strictly follow a markdown code block format, where the following tokens must be replaced such that -FILEPATH is the lowercase file name including the file extension +FILEPATH is a file name that contains the file extension LANG is the markup code block language for the code's language COMMENT as well as a quick comment on their purpose CODE is the code: @@ -213,7 +213,7 @@ def setpReqChooseLib(feature, appBasePrompt, projectInfo, projectLib): return json.loads(data), success -def parse_chat(chat): +def parse_chat(chat, serviceName): regex = r"(.+?)```[^\n]*\n(.+?)```" matches = re.finditer(regex, chat, re.DOTALL) @@ -234,6 +234,8 @@ def parse_chat(chat): code = match.group(2) # Add the file to the list + if path.startswith(serviceName+"/"): + path = path[len(serviceName+"/"):] files.append({"file-path": path,"code": code, "code-interpreter": interpreter, "reference-file": ""}) # Return the files diff --git a/backend/config.py b/backend/config.py index 6c06d244b..d44d5b328 100644 --- a/backend/config.py +++ b/backend/config.py @@ -43,6 +43,7 @@ def read_config(key): REQUIREMENT_MEM_STEP_DevOps_lintCheck = "DevOps_lintCheck" REQUIREMENT_MEM_STEP_DevOps_unitTest = "DevOps_unitTest" REQUIREMENT_MEM_STEP_DevOps_apiTest = "DevOps_apiTest" +REQUIREMENT_MEM_STEP_DevOps_CI = "DevOps_CI" REQUIREMENT_MEM_TYPE_RequirementDocument = "RequirementDocument" REQUIREMENT_MEM_TYPE_APIDocument = "APIDocument" REQUIREMENT_MEM_STEP_Subtask = "Subtask" diff --git a/frontend/static/js/coder.js b/frontend/static/js/coder.js index 2997ea711..81dfd372f 100644 --- a/frontend/static/js/coder.js +++ b/frontend/static/js/coder.js @@ -647,7 +647,7 @@ function checkCode(code, fileTask, uuid, file_path, service_name) { $("#task_status_check_"+uuid).attr("show-code-reason", error) } - sendAjaxRequest('/step_code/check_file', "POST", requestData, successCallback, errorCallback, true, false) + sendAjaxRequest('/step_code/check_code', "POST", requestData, successCallback, errorCallback, true, false) } function checkCompile(repo_path, times) { @@ -1039,7 +1039,7 @@ function startCi(repo_path, repo_branch) { thinkUI(customPrompt, globalFrontendText["ai_think"]) - var requestData = JSON.stringify({ 'repo_path': repo_path}) + var requestData = JSON.stringify({ 'repo_path': repo_path, 'task_id': getTaskID()}) successCallback = function(data) { pluginci(data.data.info) @@ -1053,7 +1053,7 @@ function startCd(repo_path) { thinkUI(customPrompt, globalFrontendText["ai_think"]) - var requestData = JSON.stringify({ 'repo_path': repo_path}) + var requestData = JSON.stringify({ 'repo_path': repo_path, 'task_id': getTaskID()}) successCallback = function(data) { var str = globalFrontendText["start_cd"]+": "+data.data["internet_ip"] @@ -1095,13 +1095,13 @@ function refreshPluginciStatus(piplineID, repopath, piplineUrl, element, times) var times=0 } $(element).addClass('loading'); - info = { "piplineID": piplineID, "repopath": repopath } + info = { "piplineID": piplineID, "repopath": repopath, 'task_id': getTaskID() } $.ajax({ type: 'GET', xhrFields: { withCredentials: true }, - url: apiUrl + '/step_devops/plugin_ci', + url: apiUrl + '/step_devops/query_ci', data: info, contentType: 'application/json', dataType: 'json' From 9ff962ffe33a48b10f5df37d85eecc9be7be836f Mon Sep 17 00:00:00 2001 From: booboosui Date: Mon, 28 Aug 2023 22:44:46 +0800 Subject: [PATCH 3/5] chore(pro) --- backend/app/controllers/requirement.py | 40 +- backend/app/controllers/step_code.py | 18 +- backend/app/controllers/step_devops.py | 4 +- backend/app/controllers/step_requirement.py | 2 +- backend/app/models/application.py | 14 + backend/app/models/requirement.py | 12 +- backend/app/pkgs/prompt/code_basic.py | 14 +- backend/app/pkgs/prompt/code_interface.py | 12 +- backend/app/pkgs/prompt/prompt.py | 24 +- backend/config.py | 7 +- frontend/static/js/coder.js | 512 +++++++++++++------- frontend/static/js/requirement.js | 2 +- 12 files changed, 434 insertions(+), 227 deletions(-) diff --git a/backend/app/controllers/requirement.py b/backend/app/controllers/requirement.py index bd6b478bd..e7fccc7a6 100644 --- a/backend/app/controllers/requirement.py +++ b/backend/app/controllers/requirement.py @@ -3,7 +3,8 @@ from app.models.task import getEmptyTaskInfo from app.pkgs.tools.i18b import getI18n from app.models.requirement import Requirement -from config import REQUIREMENT_STATUS_NotStarted +from app.models.requirement_memory_pro import RequirementMemory +from config import REQUIREMENT_STATUS_NotStarted, GRADE bp = Blueprint('requirement', __name__, url_prefix='/requirement') @@ -32,8 +33,9 @@ def setup_app(): sourceBranch = data['source_branch'] featureBranch = data['feature_branch'] username = session['username'] + tenantID = session['tenant_id'] - requirement = Requirement.create_requirement("", "New", appID, 1, sourceBranch, featureBranch, REQUIREMENT_STATUS_NotStarted, 0, 0) + requirement = Requirement.create_requirement(tenantID, "", "New", appID, 1, sourceBranch, featureBranch, REQUIREMENT_STATUS_NotStarted, 0, 0) session[username]['memory']['task_info'] = { "app_id": appID, @@ -44,20 +46,42 @@ def setup_app(): session.update() if requirement.requirement_id: - return {"task_id": session[username]['memory']['task_info']['task_id']} + return Requirement.get_requirement_by_id(requirement.requirement_id) else: raise Exception(_("Failed to set up app.")) @bp.route('/get', methods=['GET']) @json_response -def getAll(): +def get_all(): _ = getI18n("controllers") - owner = session['username'] - appID = request.args.get('app_id') + tenantID = session['tenant_id'] try: - requirements = Requirement.get_all_requirements(appID) + requirements = Requirement.get_all_requirements(tenantID) return {'requirements': requirements} except Exception as e: - raise Exception(_("Failed to get applications.")) \ No newline at end of file + raise Exception(_("Failed to get applications.")) + +@bp.route('/get_one', methods=['GET']) +@json_response +def get_one(): + _ = getI18n("controllers") + requirementID = request.args.get('requirement_id') + + requirement = Requirement.get_requirement_by_id(requirementID) + + memory = { + "task_info" : { + "app_id": requirement["app_id"], + "task_id": requirement["requirement_id"], + "source_branch": requirement["default_source_branch"], + "feature_branch": requirement["default_target_branch"] + } + } + requirement["old_memory"] = memory + + if GRADE != "base": + requirement["memory"] = RequirementMemory.get_all_requirement_memories(requirementID, 1) + + return requirement \ No newline at end of file diff --git a/backend/app/controllers/step_code.py b/backend/app/controllers/step_code.py index 60c6c085c..a406a563a 100644 --- a/backend/app/controllers/step_code.py +++ b/backend/app/controllers/step_code.py @@ -14,9 +14,10 @@ def edit_file_task(): newTask = request.json.get('new_task') newCode = request.json.get('new_code') fileTask = request.json.get('file_task') + filePath = request.json.get('file_path') requirementID = request.json.get('task_id') - re, success = aiGenCode(requirementID, fileTask, newTask, newCode) + re, success = aiGenCode(requirementID, fileTask, newTask, newCode, filePath) if not success: raise Exception(_("Failed to edit file with new task.")) @@ -29,8 +30,9 @@ def check_file(): code = request.json.get('code') fileTask = request.json.get('fileTask') requirementID = request.json.get('task_id') + filePath = request.json.get('file_path') - re, success = aiCheckCode(requirementID, fileTask, code) + re, success = aiCheckCode(requirementID, fileTask, code, filePath) if not success: raise Exception(_("Failed to check file.")) @@ -46,8 +48,9 @@ def merge_file(): userName = session["username"] appName = session[userName]['memory']['task_info']['app_name'] requirementID = request.json.get('task_id') + filePath = request.json.get('file_path') - re, success = aiMergeCode(requirementID, fileTask, appName, baseCode, newCode) + re, success = aiMergeCode(requirementID, fileTask, appName, baseCode, newCode, filePath) if not success: raise Exception(_("Failed to merge old and new code.")) @@ -65,12 +68,13 @@ def reference_repair(): appName = session[userName]['memory']['task_info']['app_name'] branch = session[userName]['memory']['task_info']['source_branch'] requirementID = request.json.get('task_id') + filePath = request.json.get('file_path') hasGitCode, referenceCode = getFileContent(referenceFile, branch, repo) if not hasGitCode: raise Exception(_("Failed to reference repair no reference file found.")) - re, success = aiReferenceRepair(requirementID, newCode, appName, referenceCode, fileTask) + re, success = aiReferenceRepair(requirementID, newCode, appName, referenceCode, fileTask, filePath) if not success: raise Exception(_("Reference repair failed for unknown reasons.")) @@ -83,8 +87,9 @@ def fix_compile(): code = request.json.get('code') solution = request.json.get('solution') requirementID = request.json.get('task_id') + filePath = request.json.get('file_path') - re, success = aiFixError(requirementID, solution, code) + re, success = aiFixError(requirementID, solution, code, filePath, "compile") reCode = re["code"] reason = re["reasoning"] @@ -97,8 +102,9 @@ def fix_lint(): code = request.json.get('code') solution = request.json.get('solution') requirementID = request.json.get('task_id') + filePath = request.json.get('file_path') - re, success = aiFixError(requirementID, solution, code) + re, success = aiFixError(requirementID, solution, code, filePath, "lint") reCode = re["code"] reason = re["reasoning"] diff --git a/backend/app/controllers/step_devops.py b/backend/app/controllers/step_devops.py index 2dad81710..ec4a5f62c 100644 --- a/backend/app/controllers/step_devops.py +++ b/backend/app/controllers/step_devops.py @@ -69,7 +69,7 @@ def check_compile(): reasoning = _("Compile check pass.") return {'pass': True, 'message': message, 'reasoning': reasoning} else: - reasoning, success = aiAnalyzeError(requirementID, message) + reasoning, success = aiAnalyzeError(requirementID, message, "") if success: return {'pass': False, 'message': message, 'reasoning': reasoning} else: @@ -93,7 +93,7 @@ def check_lint(): reasoning = _("Static code scan passed.") return {'pass': True, 'message': message, 'reasoning': reasoning} else: - reasoning, success = aiAnalyzeError(requirementID, message) + reasoning, success = aiAnalyzeError(requirementID, message, file_path) if success: return {'pass': False, 'message': message, 'reasoning': reasoning} else: diff --git a/backend/app/controllers/step_requirement.py b/backend/app/controllers/step_requirement.py index 9a16cda5a..68cbb0439 100644 --- a/backend/app/controllers/step_requirement.py +++ b/backend/app/controllers/step_requirement.py @@ -30,6 +30,6 @@ def clarify(): msg, success = clarifyRequirement(requirementID, userPrompt, globalContext, appArchitecture) if success: - return {'message': msg, 'memory': session[userName]['memory']} + return {'message': msg, 'memory': session[userName]['memory'], "input_prompt": userPrompt} else: raise Exception(_("Failed to clarify requirement.")) diff --git a/backend/app/models/application.py b/backend/app/models/application.py index 68121c0b0..d9d77c81e 100644 --- a/backend/app/models/application.py +++ b/backend/app/models/application.py @@ -48,3 +48,17 @@ def get_all_application(owner, appID): application_list.append(app_dict) return application_list + + def get_application_by_id(appID): + app = Application.query.get(appID) + app_dict = { + 'app_id': app.app_id, + 'tenant_id': app.tenant_id, + 'creater': app.creater, + 'name': app.name, + 'description': app.description, + 'default_source_branch': app.default_source_branch, + 'default_target_branch': app.default_target_branch, + 'service': ApplicationService.get_services_by_app_id(app.app_id) + } + return app_dict \ No newline at end of file diff --git a/backend/app/models/requirement.py b/backend/app/models/requirement.py index f55a31a97..b469c3af4 100644 --- a/backend/app/models/requirement.py +++ b/backend/app/models/requirement.py @@ -1,7 +1,9 @@ from app.extensions import db +from app.models.application import Application class Requirement(db.Model): requirement_id = db.Column(db.Integer, primary_key=True) + tenant_id = db.Column(db.Integer, nullable=False) requirement_name = db.Column(db.String(255), nullable=False) original_requirement = db.Column(db.String(1000)) app_id = db.Column(db.Integer, nullable=False) @@ -15,8 +17,9 @@ class Requirement(db.Model): updated_at = db.Column(db.TIMESTAMP, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp()) @staticmethod - def create_requirement(requirement_name, original_requirement, app_id, user_id, default_source_branch, default_target_branch, status, satisfaction_rating=None, completion_rating=None): + def create_requirement(tenant_id, requirement_name, original_requirement, app_id, user_id, default_source_branch, default_target_branch, status, satisfaction_rating=None, completion_rating=None): requirement = Requirement( + tenant_id=tenant_id, requirement_name=requirement_name, original_requirement=original_requirement, app_id=app_id, @@ -32,8 +35,8 @@ def create_requirement(requirement_name, original_requirement, app_id, user_id, return requirement @staticmethod - def get_all_requirements(app_id=None): - requirements = Requirement.query.order_by(Requirement.requirement_id.desc()).all() + def get_all_requirements(tenantID=None): + requirements = Requirement.query.filter_by(tenant_id=tenantID).order_by(Requirement.requirement_id.desc()).all() requirement_list = [] for req in requirements: @@ -70,7 +73,8 @@ def get_requirement_by_id(requirement_id): 'satisfaction_rating': req.satisfaction_rating, 'completion_rating': req.completion_rating, 'created_at': req.created_at, - 'updated_at': req.updated_at + 'updated_at': req.updated_at, + 'app': Application.get_application_by_id(req.app_id) } return req_dict diff --git a/backend/app/pkgs/prompt/code_basic.py b/backend/app/pkgs/prompt/code_basic.py index ef60d54c9..2242c50a3 100644 --- a/backend/app/pkgs/prompt/code_basic.py +++ b/backend/app/pkgs/prompt/code_basic.py @@ -5,7 +5,7 @@ from app.pkgs.prompt.code_interface import CodeInterface class CodeBasic(CodeInterface): - def aiReferenceRepair(self, requirementID, newCode, referenceCode, fileTask): + def aiReferenceRepair(self, requirementID, newCode, referenceCode, fileTask, filePath): prompt = f""" As a senior full stack developer. Your task is to analyze the following "reference code" style and specification (including but not limited to: naming conventions, coding styles, import package specifications, comment specifications, etc.) line by line, and use this to correct the "development task corresponding code" with the "reference code" style and specification is inconsistent. Ensure that the newly generated code can conform to the overall code style and specification of the program as well as the reference code without compromising the "development task". The consolidated code responds according to the response format example. @@ -35,7 +35,7 @@ def aiReferenceRepair(self, requirementID, newCode, referenceCode, fileTask): return json.loads(fix_llm_json_str(data)), success - def aiAnalyzeError(self, requirementID, message): + def aiAnalyzeError(self, requirementID, message, filePath): prompt = f""" As a senior full stack developer. Your task is to analyze code execution error messages, return files that may need to be modified, and analyze the solution. Follow the response format example. @@ -55,7 +55,7 @@ def aiAnalyzeError(self, requirementID, message): return json.loads(fix_llm_json_str(data)), success - def aiFixError(self, requirementID, solution, code): + def aiFixError(self, requirementID, solution, code, filePath, type): prompt = f""" As a senior full stack developer. Your task is to fix errors in the "initial code". Please fix the problems in the "initial code" according to the solution, taking care not to affect other code functions. The consolidated code responds according to the response format example. @@ -80,7 +80,7 @@ def aiFixError(self, requirementID, solution, code): return json.loads(fix_llm_json_str(data)), success - def aiCheckCode(self, requirementID, fileTask, code): + def aiCheckCode(self, requirementID, fileTask, code, filePath): goodCodeRe, success = self.aiReviewCode(requirementID, fileTask, code) jsonData = {"reasoning": goodCodeRe, "code": code} @@ -116,7 +116,7 @@ def aiCheckCode(self, requirementID, fileTask, code): return jsonData, success - def aiReviewCode(self, requirementID, fileTask, code): + def aiReviewCode(self, requirementID, fileTask, code, filePath): prompt = f""" NOTICE Role: You are a professional software engineer, Your task is to review the code. @@ -146,7 +146,7 @@ def aiReviewCode(self, requirementID, fileTask, code): return data, success - def aiMergeCode(self, requirementID, task, baseCode, newCode): + def aiMergeCode(self, requirementID, task, baseCode, newCode, filePath): prompt = f""" As a senior full stack developer. Your task is to integrate with existing code according to the "Development Task" and "Development Task corresponding code" provided below. In the process of integrating code, you must use the existing code as a baseline, and always be careful to ensure that the functionality of the existing code body is not affected. The consolidated code responds according to the response format example. @@ -176,7 +176,7 @@ def aiMergeCode(self, requirementID, task, baseCode, newCode): return json.loads(fix_llm_json_str(data)), success - def aiGenCode(self, requirementID, fileTask, newTask, newCode): + def aiGenCode(self, requirementID, fileTask, newTask, newCode, filePath): prompt = f""" As a senior full stack developer. you need to modify the "basic code" based on the "change suggestions" and return all the complete code that works well. The code style is consistent with the "base code", try not to break the original function. diff --git a/backend/app/pkgs/prompt/code_interface.py b/backend/app/pkgs/prompt/code_interface.py index 552c10b7e..96ce4fd0b 100644 --- a/backend/app/pkgs/prompt/code_interface.py +++ b/backend/app/pkgs/prompt/code_interface.py @@ -4,25 +4,25 @@ class CodeInterface(ABC): @abstractmethod - def aiReferenceRepair(self, requirementID, newCode, referenceCode, fileTask): + def aiReferenceRepair(self, requirementID, newCode, referenceCode, fileTask, filePath): pass @abstractmethod - def aiAnalyzeError(self, requirementID, message): + def aiAnalyzeError(self, requirementID, message, filePath): pass @abstractmethod - def aiFixError(self, requirementID, solution, code): + def aiFixError(self, requirementID, solution, code, filePath, type): pass @abstractmethod - def aiCheckCode(self, requirementID, fileTask, code): + def aiCheckCode(self, requirementID, fileTask, code, filePath): pass @abstractmethod - def aiMergeCode(self, requirementID, task, baseCode, newCode): + def aiMergeCode(self, requirementID, task, baseCode, newCode, filePath): pass @abstractmethod - def aiGenCode(self, requirementID, fileTask, newTask, newCode): + def aiGenCode(self, requirementID, fileTask, newTask, newCode, filePath): pass \ No newline at end of file diff --git a/backend/app/pkgs/prompt/prompt.py b/backend/app/pkgs/prompt/prompt.py index 2c94d4b46..2a22524a5 100644 --- a/backend/app/pkgs/prompt/prompt.py +++ b/backend/app/pkgs/prompt/prompt.py @@ -39,50 +39,50 @@ def splitTask(requirementID, newfeature, serviceName, appBasePrompt, projectInfo return obj.splitTask(requirementID, newfeature, serviceName, appBasePrompt, projectInfo, projectLib, serviceStruct, appID) -def aiReferenceRepair(requirementID, newCode, referenceCode, fileTask): +def aiReferenceRepair(requirementID, newCode, referenceCode, fileTask, filePath): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiReferenceRepair(requirementID, newCode, referenceCode, fileTask) + return obj.aiReferenceRepair(requirementID, newCode, referenceCode, fileTask, filePath) -def aiAnalyzeError(requirementID, message): +def aiAnalyzeError(requirementID, message, filePath): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiAnalyzeError(requirementID, message) + return obj.aiAnalyzeError(requirementID, message, filePath) -def aiFixError(requirementID, solution, code): +def aiFixError(requirementID, solution, code, filePath, type): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiFixError(requirementID, solution, code) + return obj.aiFixError(requirementID, solution, code, filePath, type) -def aiCheckCode(requirementID, fileTask, code): +def aiCheckCode(requirementID, fileTask, code, filePath): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiCheckCode(requirementID, fileTask, code) + return obj.aiCheckCode(requirementID, fileTask, code, filePath) -def aiMergeCode(requirementID, fileTask, appName, baseCode, newCode): +def aiMergeCode(requirementID, fileTask, appName, baseCode, newCode, filePath): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiMergeCode(requirementID, fileTask, appName, baseCode, newCode) + return obj.aiMergeCode(requirementID, fileTask, appName, baseCode, newCode, filePath) -def aiGenCode(requirementID, fileTask, newTask, newCode): +def aiGenCode(requirementID, fileTask, newTask, newCode, filePath): if GRADE == "base": obj = CodeBasic() else: obj = CodePro() - return obj.aiGenCode(requirementID, fileTask, newTask, newCode) \ No newline at end of file + return obj.aiGenCode(requirementID, fileTask, newTask, newCode, filePath) \ No newline at end of file diff --git a/backend/config.py b/backend/config.py index d44d5b328..6940cb53a 100644 --- a/backend/config.py +++ b/backend/config.py @@ -44,11 +44,12 @@ def read_config(key): REQUIREMENT_MEM_STEP_DevOps_unitTest = "DevOps_unitTest" REQUIREMENT_MEM_STEP_DevOps_apiTest = "DevOps_apiTest" REQUIREMENT_MEM_STEP_DevOps_CI = "DevOps_CI" + REQUIREMENT_MEM_TYPE_RequirementDocument = "RequirementDocument" REQUIREMENT_MEM_TYPE_APIDocument = "APIDocument" -REQUIREMENT_MEM_STEP_Subtask = "Subtask" -REQUIREMENT_MEM_STEP_Code = "Code" -REQUIREMENT_MEM_STEP_DevOps = "DevOps" +REQUIREMENT_MEM_TYPE_Subtask = "Subtask" +REQUIREMENT_MEM_TYPE_Code = "Code" +REQUIREMENT_MEM_TYPE_DevOps = "DevOps" try: BACKEND_HOST = read_config("BACKEND_HOST") diff --git a/frontend/static/js/coder.js b/frontend/static/js/coder.js index 81dfd372f..87c8251f9 100644 --- a/frontend/static/js/coder.js +++ b/frontend/static/js/coder.js @@ -93,6 +93,15 @@ function thinkUI(customPrompt, thinkText) { }, 900); } +function thinkUIShow(customPrompt, thinkText) { + $('#prompt-textarea').val(""); + $("#prompt-hidePrompt").val("") + var newField = $('
' + customPrompt.replaceAll("\n", "
") + '
'+thinkText+'
'); + $(".ai-prompt-container").eq($('ai-prompt-container').length - 1).before(newField); + + $('html, body').animate({ scrollTop: $(document).height() }, 'slow'); +} + function answerUI(str) { $(".ai-code").eq($('ai-code').length - 1).html(str); $(".ai-code").eq($('ai-code').length - 1).hide().fadeIn('fast'); @@ -111,6 +120,23 @@ function modelInfoUpdate(appName, content) { sendAjaxRequest('/app/update', 'POST', requestData, successCallback, alertErrorCallback, true, false) } +modelSelectedSuccessCallback = function(data){ + data = data.data + var repos = "" + data.app.service.forEach(function (s, element_index, element_array) { + repos += s.name+", " + }); + str = globalFrontendText["ai_selected_app_1"] + ": " + data.app.name + +"
"+ globalFrontendText["ai_selected_app_2"] + ": "+ data["requirement_id"] + +"
"+ globalFrontendText["ai_selected_app_3"] + ": "+ repos + +"
"+ globalFrontendText["ai_selected_app_4"] + data.default_source_branch +" "+ globalFrontendText["ai_selected_app_5"] +" "+ data.default_target_branch + +"

" + globalFrontendText["ai_selected_app_6"]; + const url = window.location; + const newUrl = url.origin + '?task_id=' + data["requirement_id"]; + history.pushState('', '', newUrl); + answerUI(str) +} + function modelSelected(appName, appID, repos) { source_branch = $("#model_source_branch_" + appID).val() feature_branch = $("#model_feature_branch_" + appID).val() @@ -123,20 +149,6 @@ function modelSelected(appName, appID, repos) { requestData = JSON.stringify({ "app_id": appID, "source_branch": source_branch, "feature_branch": feature_branch }) - successCallback = function(data){ - data = data.data - globalChangeServiceList = data.repo_list - str = globalFrontendText["ai_selected_app_1"] + ": " + appName - +"
"+ globalFrontendText["ai_selected_app_2"] + ": "+ data["task_id"] - +"
"+ globalFrontendText["ai_selected_app_3"] + ": "+ repos - +"
"+ globalFrontendText["ai_selected_app_4"] + source_branch +" "+ globalFrontendText["ai_selected_app_5"] +" "+ feature_branch - +"

" + globalFrontendText["ai_selected_app_6"]; - const url = window.location; - const newUrl = url.origin + '?task_id=' + data.task_id; - history.pushState('', '', newUrl); - answerUI(str) - } - errorCallback = function (error){ $('.model-selector').removeClass("disabled") str = error @@ -147,12 +159,13 @@ function modelSelected(appName, appID, repos) { }, 1000); } - sendAjaxRequest('/requirement/setup_app', 'POST', requestData, successCallback, errorCallback, true, true) + sendAjaxRequest('/requirement/setup_app', 'POST', requestData, modelSelectedSuccessCallback, errorCallback, true, true) } $(document).ready(function () { language() logincheck() + getRequirement() codeMirror = CodeMirror.fromTextArea(document.getElementById('code-edit-code'), { theme: 'darcula', @@ -232,7 +245,7 @@ $(document).ready(function () { }); $('#cancel-task').click(function () { - location.reload(); + window.location.href = "/index.html" }); // show dropdown on hover @@ -296,6 +309,114 @@ function escapeString(str) { }); } +function getRequirement() { + var requirement_id = getTaskID() + info = { 'requirement_id': requirement_id } + + successCallback = function(data) { + modelSelectedSuccessCallback(data) + for (let element_index = 0; element_index < data.data.memory.length; element_index++) { + globalMemory = data.data.old_memory + const memory = data.data.memory[element_index]; + + console.log(memory); + + if (memory.artifact_type == "RequirementDocument") { + thinkUIShow(memory.input_prompt, globalFrontendText["ai_think"]); + const d = { + "data": { + "message": JSON.parse(memory.artifact_content), + "input_prompt": memory.input_prompt + } + }; + clarifySuccessCallback(d); + } + if (memory.step == "API_organize") { + const d = { + "data": { + "message": memory.artifact_content + } + }; + genInterfaceDocSuccessCallback(d); + } + if (memory.step == "Subtask_code") { + thinkUIShow(memory.artifact_path, globalFrontendText["ai_think"]); + const info = { + "files": JSON.parse(memory.artifact_content), + "service_name": memory.artifact_path + }; + pluginTaskList(info, true) + } + if (memory.step == "Code_checkCode") { + codedata = { + "data": { + code: memory.artifact_content, + reasoning: memory.input_prompt, + success: true + } + } + uuid = 0 + service_name = "" + for (const key in globalTasks) { + globalTasks[key].forEach(function (file, element_index, element_array) { + let file_path = file["file-path"] + if (file_path == memory.artifact_path) { + uuid = file.uuid + service_name = key + } + }) + } + checkCodeStar(uuid, service_name) + checkCodeSuccessCallback(codedata, uuid, memory.artifact_path) + } + if (memory.step == "Code_fixError_compile") { + codedata = { + "data": JSON.parse(memory.artifact_content) + } + uuid = 0 + service_name = "" + for (const key in globalTasks) { + globalTasks[key].forEach(function (file, element_index, element_array) { + let file_path = file["file-path"] + if (file_path == memory.artifact_path) { + uuid = file.uuid + service_name = key + } + }) + } + fixCompileStar(service_name, element_index, uuid) + fixCompileSuccessCallback(codedata, service_name, element_index, uuid, memory.artifact_path) + } + if (memory.step == "Code_fixError_lint") { + codedata = { + "data": JSON.parse(memory.artifact_content) + } + uuid = 0 + service_name = "" + for (const key in globalTasks) { + globalTasks[key].forEach(function (file, element_index, element_array) { + let file_path = file["file-path"] + if (file_path == memory.artifact_path) { + uuid = file.uuid + service_name = key + } + }) + } + fixLintStar(service_name, element_index, uuid) + fixLintSuccessCallback(codedata, service_name, element_index, uuid, memory.artifact_path) + } + } + } + + errorCallback = function(){ + myAlertPure(globalFrontendText["notice"], globalFrontendText["opensource_version_1"] + ": ./workspace/"+requirement_id) + } + + if (requirement_id>0) { + sendAjaxRequest('/requirement/get_one', 'GET', info, successCallback, errorCallback, true, false) + } +} + function genCodeCallbackPushcode(isSuccess, data) { var uuid = data.plugin.uuid; if (isSuccess) { @@ -332,11 +453,13 @@ function language() { } function logincheck() { + info = { 'requirement_id': getTaskID() } + successCallback = function(data) { var username = data.data.username - const url = window.location; - const newUrl = url.origin+url.pathname; - history.pushState('', '', newUrl); + //const url = window.location; + //const newUrl = url.origin+url.pathname; + //history.pushState('', '', newUrl); $("#current-username").html(username) $("#watermark-username").html(username) } @@ -345,7 +468,7 @@ function logincheck() { $("#my-login").modal('show') } - sendAjaxRequest('/requirement/clear_up', 'GET', "", successCallback, errorCallback, true, false) + sendAjaxRequest('/requirement/clear_up', 'GET', info, successCallback, errorCallback, true, false) } function logout() { @@ -413,7 +536,7 @@ function triggerPlugin(plugin) { pluginci(plugin["info"]) } if (plugin["name"] == "task_list") { - pluginTaskList(plugin["info"]) + pluginTaskList(plugin["info"], false) } if (plugin["name"] == "task_runner") { pluginTaskRunner(plugin["info"]) @@ -459,33 +582,41 @@ function createWS(serviceName, sourceBranch, featureBranch) { sendAjaxRequest('/workspace/create', "POST", requestData, successCallback, errorCallback, false, false) } -function fixLint(solution, uuid, file_path, service_name, times) { - if (times >= 2) { - return - } - var code = gloablCode["newCode_" + uuid] - +function fixLintStar(service_name, times, uuid){ let buttonid = "task_status_fix_lint_"+globalCompileTimes[service_name.replace("/","-")]+"_"+times+"_"+uuid str = $("#task_status_td_" + uuid).html()+` ` $("#task_status_td_" + uuid).html(str) $('.task_status_fix_lint_button').popup(); +} - var requestData = JSON.stringify({ 'code': code, 'solution': solution, 'task_id': getTaskID() }) +function fixLintSuccessCallback(data, service_name, times, uuid, file_path) { + let buttonid = "task_status_fix_lint_"+globalCompileTimes[service_name.replace("/","-")]+"_"+times+"_"+uuid + $("#"+buttonid).children().removeClass("spinner") + $("#"+buttonid).children().removeClass("loading") + $("#"+buttonid).children().addClass("check") + $("#"+buttonid).addClass("green") + $("#"+buttonid).removeClass("olive") + $("#"+buttonid).attr("show-code-key", file_path) + $("#"+buttonid).attr("show-code-value", escapeHtml(data.data["code"])) + $("#"+buttonid).attr("show-code-reason", escapeHtml(data.data["reasoning"])) + + gloablCode["newCode_" + uuid] = data.data["code"] +} - successCallback = function(data) { - let buttonid = "task_status_fix_lint_"+globalCompileTimes[service_name.replace("/","-")]+"_"+times+"_"+uuid - $("#"+buttonid).children().removeClass("spinner") - $("#"+buttonid).children().removeClass("loading") - $("#"+buttonid).children().addClass("check") - $("#"+buttonid).addClass("green") - $("#"+buttonid).removeClass("olive") - $("#"+buttonid).attr("show-code-key", file_path) - $("#"+buttonid).attr("show-code-value", escapeHtml(data.data["code"])) - $("#"+buttonid).attr("show-code-reason", escapeHtml(data.data["reasoning"])) +function fixLint(solution, uuid, file_path, service_name, times) { + if (times >= 2) { + return + } + var code = gloablCode["newCode_" + uuid] - gloablCode["newCode_" + uuid] = data.data["code"] + fixLintStar(service_name, times, uuid) + + var requestData = JSON.stringify({ 'code': code, 'solution': solution, 'task_id': getTaskID(), 'file_path': file_path }) + + successCallback = function(data) { + fixLintSuccessCallback(data, service_name, times, uuid, file_path) times++ checkLint(service_name, file_path, uuid, times) @@ -505,33 +636,41 @@ function fixLint(solution, uuid, file_path, service_name, times) { sendAjaxRequest('/step_code/fix_lint', "POST", requestData, successCallback, errorCallback, true, false) } -function fixCompile(solution, uuid, file_path, service_name, times) { - if (times >= 2) { - return - } - var code = gloablCode["newCode_" + uuid] +function fixCompileSuccessCallback(data, service_name, times, uuid, file_path) { + let buttonid = "task_status_fix_compile_"+globalCompileTimes[service_name.replace("/","-")]+"_"+times+"_"+uuid + $("#"+buttonid).children().removeClass("spinner") + $("#"+buttonid).children().removeClass("loading") + $("#"+buttonid).children().addClass("check") + $("#"+buttonid).addClass("green") + $("#"+buttonid).removeClass("olive") + $("#"+buttonid).attr("show-code-key", file_path) + $("#"+buttonid).attr("show-code-value", escapeHtml(data.data["code"])) + $("#"+buttonid).attr("show-code-reason", escapeHtml(data.data["reasoning"])) + + gloablCode["newCode_" + uuid] = data.data["code"] +} +function fixCompileStar(service_name, times, uuid) { let buttonid = "task_status_fix_compile_"+globalCompileTimes[service_name.replace("/","-")]+"_"+times+"_"+uuid str = $("#task_status_td_" + uuid).html()+` ` $("#task_status_td_" + uuid).html(str) $('.task_status_fix_compile_button').popup(); +} + +function fixCompile(solution, uuid, file_path, service_name, times) { + if (times >= 2) { + return + } + var code = gloablCode["newCode_" + uuid] + + fixCompileStar(service_name, times, uuid) - var requestData = JSON.stringify({ 'code': code, 'solution': solution, 'task_id': getTaskID() }) + var requestData = JSON.stringify({ 'code': code, 'solution': solution, 'task_id': getTaskID(), 'file_path': file_path }) successCallback = function(data) { - let buttonid = "task_status_fix_compile_"+globalCompileTimes[service_name.replace("/","-")]+"_"+times+"_"+uuid - $("#"+buttonid).children().removeClass("spinner") - $("#"+buttonid).children().removeClass("loading") - $("#"+buttonid).children().addClass("check") - $("#"+buttonid).addClass("green") - $("#"+buttonid).removeClass("olive") - $("#"+buttonid).attr("show-code-key", file_path) - $("#"+buttonid).attr("show-code-value", escapeHtml(data.data["code"])) - $("#"+buttonid).attr("show-code-reason", escapeHtml(data.data["reasoning"])) - - gloablCode["newCode_" + uuid] = data.data["code"] + fixCompileSuccessCallback(data, service_name, times, uuid, file_path) times++ checkCompile(service_name, times) @@ -610,26 +749,35 @@ function checkLint(service_name, filePath, uuid, times) { sendAjaxRequest('/step_devops/check_lint', "POST", requestData, successCallback, errorCallback, true, false) } -function checkCode(code, fileTask, uuid, file_path, service_name) { +function checkCodeStar(uuid, service_name) { str = $("#task_status_td_" + uuid).html()+` - - ` + + ` $("#task_status_td_" + uuid).html(str) $('.task_status_button').popup(); +} - var requestData = JSON.stringify({ 'code': code, 'fileTask': fileTask, 'task_id': getTaskID() }) +function checkCodeSuccessCallback(data, uuid, file_path) { + console.log("checkCodeSuccessCallback:", data, uuid, file_path) + $("#task_status_check_"+uuid).children().removeClass("spinner") + $("#task_status_check_"+uuid).children().removeClass("loading") + $("#task_status_check_"+uuid).children().addClass("check") + $("#task_status_check_"+uuid).addClass("green") + $("#task_status_check_"+uuid).removeClass("olive") + $("#task_status_check_"+uuid).attr("show-code-key", file_path) + $("#task_status_check_"+uuid).attr("show-code-value", escapeHtml(data.data["code"])) + $("#task_status_check_"+uuid).attr("show-code-reason", escapeHtml(data.data["reasoning"])) + + gloablCode["newCode_" + uuid] = data.data["code"] +} - successCallback = function(data){ - $("#task_status_check_"+uuid).children().removeClass("spinner") - $("#task_status_check_"+uuid).children().removeClass("loading") - $("#task_status_check_"+uuid).children().addClass("check") - $("#task_status_check_"+uuid).addClass("green") - $("#task_status_check_"+uuid).removeClass("olive") - $("#task_status_check_"+uuid).attr("show-code-key", file_path) - $("#task_status_check_"+uuid).attr("show-code-value", escapeHtml(data.data["code"])) - $("#task_status_check_"+uuid).attr("show-code-reason", escapeHtml(data.data["reasoning"])) +function checkCode(code, fileTask, uuid, file_path, service_name) { + checkCodeStar(uuid, service_name) - gloablCode["newCode_" + uuid] = data.data["code"] + var requestData = JSON.stringify({ 'code': code, 'fileTask': fileTask, 'task_id': getTaskID(), 'file_path': file_path }) + + successCallback = function(data){ + checkCodeSuccessCallback(data, uuid, file_path) if(globalTasks[service_name.replace("/","-")].length == $('.'+service_name.replace("/","-")+'.green.task_status_check_button').length){ checkCompile(service_name, 0) @@ -650,6 +798,52 @@ function checkCode(code, fileTask, uuid, file_path, service_name) { sendAjaxRequest('/step_code/check_code', "POST", requestData, successCallback, errorCallback, true, false) } +function checkCompileSuccessCallback(data, times, repo_path){ + if (data.data["pass"] == false) { + globalTasks[repo_path.replace("/","-")].forEach(function (file, element_index, element_array) { + let uuid = file.uuid + let buttonid = "task_status_checkcompile_"+globalCompileTimes[repo_path.replace("/","-")]+"_"+times+"_"+uuid + let file_path = file["file-path"] + $("#"+buttonid).children().removeClass("spinner") + $("#"+buttonid).children().removeClass("loading") + $("#"+buttonid).children().addClass("close") + $("#"+buttonid).removeClass("olive") + $("#"+buttonid).attr("show-code-key", globalFrontendText["compile_check"]) + $("#"+buttonid).attr("show-code-value", escapeHtml(data.data["message"])) + + var solution = globalFrontendText["no_problem_this_file"]+"
" + for (let element_index = 0; element_index < data.data["reasoning"].length; element_index++) { + let element = data.data["reasoning"][element_index]; + if (element["file-path"].includes(file_path)) { + $("#"+buttonid).addClass("red") + solution = element["solution-analysis"]; + fixCompile(solution, uuid, file_path, repo_path, times) + break + } else { + $("#"+buttonid).addClass("teal") + solution += "- "+element["solution-analysis"]+"
"; + } + } + $("#"+buttonid).attr("show-code-reason", solution) + }); + + } else { + globalTasks[repo_path.replace("/","-")].forEach(function (file, element_index, element_array) { + let uuid = file.uuid + let buttonid = "task_status_checkcompile_"+globalCompileTimes[repo_path.replace("/","-")]+"_"+times+"_"+uuid + $("#"+buttonid).children().removeClass("spinner") + $("#"+buttonid).children().removeClass("loading") + $("#"+buttonid).children().addClass("check") + $("#"+buttonid).addClass("green") + $("#"+buttonid).removeClass("olive") + $("#"+buttonid).attr("show-code-reason", "PAAS") + $("#"+buttonid).attr("show-code-key", globalFrontendText["compile_check"]) + $("#"+buttonid).attr("show-code-value", escapeHtml(data.data["message"])) + checkLint(repo_path, file["file-path"], uuid, 0) + }); + } +} + function checkCompile(repo_path, times) { if (typeof globalCompileTimes[repo_path.replace("/","-")] === 'undefined') { globalCompileTimes[repo_path.replace("/","-")] = 0 @@ -676,49 +870,7 @@ function checkCompile(repo_path, times) { var requestData = JSON.stringify({ 'repo_path': repo_path, 'task_id': getTaskID() }) successCallback = function(data) { - if (data.data["pass"] == false) { - globalTasks[repo_path.replace("/","-")].forEach(function (file, element_index, element_array) { - let uuid = file.uuid - let buttonid = "task_status_checkcompile_"+globalCompileTimes[repo_path.replace("/","-")]+"_"+times+"_"+uuid - let file_path = file["file-path"] - $("#"+buttonid).children().removeClass("spinner") - $("#"+buttonid).children().removeClass("loading") - $("#"+buttonid).children().addClass("close") - $("#"+buttonid).removeClass("olive") - $("#"+buttonid).attr("show-code-key", globalFrontendText["compile_check"]) - $("#"+buttonid).attr("show-code-value", escapeHtml(data.data["message"])) - - var solution = globalFrontendText["no_problem_this_file"]+"
" - for (let element_index = 0; element_index < data.data["reasoning"].length; element_index++) { - let element = data.data["reasoning"][element_index]; - if (element["file-path"].includes(file_path)) { - $("#"+buttonid).addClass("red") - solution = element["solution-analysis"]; - fixCompile(solution, uuid, file_path, repo_path, times) - break - } else { - $("#"+buttonid).addClass("teal") - solution += "- "+element["solution-analysis"]+"
"; - } - } - $("#"+buttonid).attr("show-code-reason", solution) - }); - - } else { - globalTasks[repo_path.replace("/","-")].forEach(function (file, element_index, element_array) { - let uuid = file.uuid - let buttonid = "task_status_checkcompile_"+globalCompileTimes[repo_path.replace("/","-")]+"_"+times+"_"+uuid - $("#"+buttonid).children().removeClass("spinner") - $("#"+buttonid).children().removeClass("loading") - $("#"+buttonid).children().addClass("check") - $("#"+buttonid).addClass("green") - $("#"+buttonid).removeClass("olive") - $("#"+buttonid).attr("show-code-reason", "PAAS") - $("#"+buttonid).attr("show-code-key", globalFrontendText["compile_check"]) - $("#"+buttonid).attr("show-code-value", escapeHtml(data.data["message"])) - checkLint(repo_path, file["file-path"], uuid, 0) - }); - } + checkCompileSuccessCallback(data, times, repo_path) } errorCallback = function(error){ @@ -752,7 +904,7 @@ function editFileTask(service_name, file_idx) { $("#task_status_td_" + uuid).html(str) $('.task_status_button').popup(); - var requestData = JSON.stringify({ 'file_task': fileTask, 'new_task': newTask, 'new_code': newCode, 'task_id': getTaskID() }) + var requestData = JSON.stringify({ 'file_task': fileTask, 'new_task': newTask, 'new_code': newCode, 'task_id': getTaskID(), 'file_path': file_path }) successCallback = function(data){ $("#task_status_redo_"+uuid).children().removeClass("spinner") @@ -791,7 +943,7 @@ function mergeCode(uuid, newCode, oldCode, fileTask, service_name, file_path) { $("#task_status_td_" + uuid).html(str) $('.task_status_button').popup(); - var requestData = JSON.stringify({ 'file_task': fileTask, 'new_code': newCode, 'old_code': oldCode, 'task_id': getTaskID() }) + var requestData = JSON.stringify({ 'file_task': fileTask, 'new_code': newCode, 'old_code': oldCode, 'task_id': getTaskID(), 'file_path': file_path }) successCallback = function(data) { $("#task_status_check_"+uuid).children().removeClass("spinner") @@ -832,7 +984,7 @@ function referenceRepair(newCode, fileTask, uuid, referenceFile, repo, file_path $("#task_status_td_" + uuid).html(str) $('.task_status_button').popup(); - var requestData = JSON.stringify({ 'new_code': newCode, 'file_task': fileTask, 'reference_file': referenceFile, 'repo': repo, 'task_id': getTaskID() }) + var requestData = JSON.stringify({ 'new_code': newCode, 'file_task': fileTask, 'reference_file': referenceFile, 'repo': repo, 'task_id': getTaskID(), 'file_path': file_path }) successCallback = function(data) { $("#task_status_check_"+uuid).children().removeClass("spinner") @@ -937,10 +1089,14 @@ function getIdxByUUID(service_name, uuid) { return file_idx } -function pluginTaskList(info) { +function pluginTaskList(info, ifRecover) { + console.log("----") + console.log(info) var service_name = info["service_name"] - createWS(service_name, globalMemory["task_info"]["source_branch"], globalMemory["task_info"]["feature_branch"]) + if (!ifRecover) { + createWS(service_name, globalMemory["task_info"]["source_branch"], globalMemory["task_info"]["feature_branch"]) + } var str = `

`+globalFrontendText["ai_api_subtask"]+`

` @@ -1011,17 +1167,19 @@ function pluginTaskList(info) { $('.plugin-task-list-play').popup(); $('.task_status_button').popup(); - setTimeout(function () { - info["files"].forEach(function (file, file_index, file_array) { - if (file["old-code"].length > 0) { - mergeCode(file["uuid"], file["code"], file["old-code"], file["code-interpreter"], info["service_name"], file["file-path"]) - } else if (file["code"].length > 0 && typeof file["reference-code"] !== "undefined" && file["reference-code"].length > 0) { - referenceRepair(file["code"], file["code-interpreter"], file["uuid"], file["reference-file"], info["service_name"], file["file-path"]) - } else { - checkCode(file["code"], file["code-interpreter"], file["uuid"], file["file-path"], info["service_name"]) - } - }) - }, 1000); + if (!ifRecover) { + setTimeout(function () { + info["files"].forEach(function (file, file_index, file_array) { + if (file["old-code"].length > 0) { + mergeCode(file["uuid"], file["code"], file["old-code"], file["code-interpreter"], info["service_name"], file["file-path"]) + } else if (file["code"].length > 0 && typeof file["reference-code"] !== "undefined" && file["reference-code"].length > 0) { + referenceRepair(file["code"], file["code-interpreter"], file["uuid"], file["reference-file"], info["service_name"], file["file-path"]) + } else { + checkCode(file["code"], file["code-interpreter"], file["uuid"], file["file-path"], info["service_name"]) + } + }) + }, 1000); + } } function startPush(serviceName) { @@ -1182,6 +1340,41 @@ function clarifyOk(element) { clarify(content) } +clarifySuccessCallback = function(data){ + data = data.data + globalMemory = data.memory + var msgJson = data.message + var msg = JSON.stringify(msgJson) + var str = "" + globalContext.push({ role: 'user', content: data.input_prompt }) + globalContext.push({ role: 'assistant', content: msg }) + if (msg.includes("development_requirements_overview")) { + if (msgJson["services_involved"].length > 0) { + globalChangeServiceList = [] + msgJson["services_involved"].forEach(function (element, element_index, element_array) { + globalChangeServiceList.push(element["service-name"]) + }) + } else { + myAlert(globalFrontendText["error"], globalFrontendText["service_modification_item_empty"]) + } + msg = globalFrontendText["ai_requirement_clarify_1"]+"\n"+msgJson.development_requirements_overview+"\n\n"+globalFrontendText["ai_requirement_clarify_2"]+"\n"+msgJson.development_requirements_detail + str = '

' + msg = msg + msg = '
'+globalFrontendText["ai_requirement_clarify_3"]+'
'+msg + } else { + var table = '
'+globalFrontendText["ai_requirement_clarify_4"]+'
' + console.log(msgJson) + msgJson.forEach(function (element, element_index, element_array) { + table += '' + }) + table += '
'+globalFrontendText["question"]+''+globalFrontendText["answer"]+'
'+element["question"]+""+element["reasoning"]+'
' + msg = table + } + + $(".ai-code").eq($('ai-code').length - 1).html(msg.replaceAll('\n', '
')+str); + $(".ai-code").eq($('ai-code').length - 1).hide().fadeIn('fast'); +} + function clarify(customPrompt, thisElement) { customPrompt = decodeURI(customPrompt) $(thisElement).addClass("disabled"); @@ -1191,47 +1384,23 @@ function clarify(customPrompt, thisElement) { var requestData = JSON.stringify({ 'user_prompt': customPrompt, 'global_context': JSON.stringify(globalContext), 'task_id': getTaskID() }) var retruBtn = '

' - successCallback = function(data){ - data = data.data - globalMemory = data.memory - var msgJson = data.message - var msg = JSON.stringify(msgJson) - var str = "" - globalContext.push({ role: 'user', content: customPrompt }) - globalContext.push({ role: 'assistant', content: msg }) - if (msg.includes("development_requirements_overview")) { - if (msgJson["services_involved"].length > 0) { - globalChangeServiceList = [] - msgJson["services_involved"].forEach(function (element, element_index, element_array) { - globalChangeServiceList.push(element["service-name"]) - }) - } else { - myAlert(globalFrontendText["error"], globalFrontendText["service_modification_item_empty"]) - } - msg = globalFrontendText["ai_requirement_clarify_1"]+"\n"+msgJson.development_requirements_overview+"\n\n"+globalFrontendText["ai_requirement_clarify_2"]+"\n"+msgJson.development_requirements_detail - str = '

' - msg = msg - msg = '
'+globalFrontendText["ai_requirement_clarify_3"]+'
'+msg - } else { - var table = '
'+globalFrontendText["ai_requirement_clarify_4"]+'
' - console.log(msgJson) - msgJson.forEach(function (element, element_index, element_array) { - table += '' - }) - table += '
'+globalFrontendText["question"]+''+globalFrontendText["answer"]+'
'+element["question"]+""+element["reasoning"]+'
' - msg = table - } - - $(".ai-code").eq($('ai-code').length - 1).html(msg.replaceAll('\n', '
')+str); - $(".ai-code").eq($('ai-code').length - 1).hide().fadeIn('fast'); - } - errorCallback = function(errorMsg) { $(".ai-code").eq($('ai-code').length - 1).html(errorMsg+retruBtn); $(".ai-code").eq($('ai-code').length - 1).hide().fadeIn('fast'); } - sendAjaxRequest('/step_requirement/clarify', "POST", requestData, successCallback, errorCallback, true, true) + sendAjaxRequest('/step_requirement/clarify', "POST", requestData, clarifySuccessCallback, errorCallback, true, true) +} + +genInterfaceDocSuccessCallback = function(data) { + data = data.data + var msg = data.message + str = "
"+msg+"
" + str += '
' + + str = '
'+globalFrontendText["ai_api_clarify_1"]+'

'+str + $(".ai-code").eq($('ai-code').length - 1).html(str); + $(".ai-code").eq($('ai-code').length - 1).hide().fadeIn('fast'); } function genInterfaceDoc(customPrompt, thisElement) { @@ -1243,23 +1412,12 @@ function genInterfaceDoc(customPrompt, thisElement) { var requestData = JSON.stringify({ 'user_prompt': customPrompt, 'task_id': getTaskID() }) var retruBtn = '

' - successCallback = function(data) { - data = data.data - var msg = data.message - str = "
"+msg+"
" - str += '
' - - str = '
'+globalFrontendText["ai_api_clarify_1"]+'

'+str - $(".ai-code").eq($('ai-code').length - 1).html(str); - $(".ai-code").eq($('ai-code').length - 1).hide().fadeIn('fast'); - } - errorCallback = function(errorMsg) { $(".ai-code").eq($('ai-code').length - 1).html(errorMsg+retruBtn); $(".ai-code").eq($('ai-code').length - 1).hide().fadeIn('fast'); } - sendAjaxRequest('/step_api/clarify', "POST", requestData, successCallback, errorCallback, true, true) + sendAjaxRequest('/step_api/clarify', "POST", requestData, genInterfaceDocSuccessCallback, errorCallback, true, true) } function taskAnalysis(customPrompt, service_name, hideUserPrompt, thisElement) { diff --git a/frontend/static/js/requirement.js b/frontend/static/js/requirement.js index 46f013028..3967a18af 100644 --- a/frontend/static/js/requirement.js +++ b/frontend/static/js/requirement.js @@ -33,5 +33,5 @@ function getRequirementList() { } function showRequirement(requirement_id) { - myAlertPure(globalFrontendText["notice"], globalFrontendText["opensource_version_1"]+": ./workspace/"+requirement_id) + window.location.href = "/index.html?task_id="+requirement_id } \ No newline at end of file From 831b878369c87d8bd985aba524d8ce739505422a Mon Sep 17 00:00:00 2001 From: booboosui Date: Tue, 29 Aug 2023 08:56:46 +0800 Subject: [PATCH 4/5] chore(pro) --- README.md | 5 ++--- backend/app/controllers/requirement.py | 7 ++----- backend/app/models/requirement_memory_pro.py | 3 +++ backend/app/pkgs/devops/devops_pro.py | 5 +++++ backend/app/pkgs/devops/local_tools_pro.py | 8 ++++++++ backend/app/pkgs/prompt/code_basic.py | 2 +- db/database.db | Bin 53248 -> 53248 bytes docs/README_CN.md | 5 ++--- 8 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 backend/app/models/requirement_memory_pro.py create mode 100644 backend/app/pkgs/devops/devops_pro.py create mode 100644 backend/app/pkgs/devops/local_tools_pro.py diff --git a/README.md b/README.md index 9c9ca67ee..da75b2671 100644 --- a/README.md +++ b/README.md @@ -51,14 +51,13 @@ Through the above introduction and Demo demonstration, you must be curious about ## Quick Start 1. Run with source code - ``` - 1. Clone the latest code or select a released version, Python3.7 or later is ready. + 1. Download the [released version](https://github.com/kuafuai/DevOpsGPT/releases), or clone the latest code(instability), Ensure SQLite and Python3.7 or later is ready. 2. Generate the configuration file: Copy `env.yaml.tpl` and rename it to `env.yaml`. 3. Modify the configuration file: Edit `env.yaml` and add the necessary information such as GPT Token (refer to [documentation link](docs/DOCUMENT.md) for detailed instructions). 4. Run the service: Execute `sh run.sh` on Linux or Mac, or double-click `run.bat` on Windows. 5. Access the service: Access the service through a browser (check the startup log for the access address, default is http://127.0.0.1:8080). 6. Complete requirement development: Follow the instructions on the page to complete requirement development, and view the generated code in the `./workspace` directory. - ``` + 2. Run with Docker ```shell 1. Create a directory: mkdir -p workspace diff --git a/backend/app/controllers/requirement.py b/backend/app/controllers/requirement.py index e7fccc7a6..4d79dc535 100644 --- a/backend/app/controllers/requirement.py +++ b/backend/app/controllers/requirement.py @@ -56,12 +56,9 @@ def get_all(): _ = getI18n("controllers") tenantID = session['tenant_id'] - try: - requirements = Requirement.get_all_requirements(tenantID) + requirements = Requirement.get_all_requirements(tenantID) - return {'requirements': requirements} - except Exception as e: - raise Exception(_("Failed to get applications.")) + return {'requirements': requirements} @bp.route('/get_one', methods=['GET']) @json_response diff --git a/backend/app/models/requirement_memory_pro.py b/backend/app/models/requirement_memory_pro.py new file mode 100644 index 000000000..47ab3ba51 --- /dev/null +++ b/backend/app/models/requirement_memory_pro.py @@ -0,0 +1,3 @@ +class RequirementMemory(): + def get_all_requirement_memories(x=None, y=1): + pass \ No newline at end of file diff --git a/backend/app/pkgs/devops/devops_pro.py b/backend/app/pkgs/devops/devops_pro.py new file mode 100644 index 000000000..55e60f966 --- /dev/null +++ b/backend/app/pkgs/devops/devops_pro.py @@ -0,0 +1,5 @@ +def triggerPipelinePro(requirementID, branchName, re): + pass + +def triggerCDPro(requirementID, image, re): + pass diff --git a/backend/app/pkgs/devops/local_tools_pro.py b/backend/app/pkgs/devops/local_tools_pro.py new file mode 100644 index 000000000..a9142e87d --- /dev/null +++ b/backend/app/pkgs/devops/local_tools_pro.py @@ -0,0 +1,8 @@ +from app.pkgs.devops.local_tools_interface import LocalToolsInterface + +class LocalToolsPro(LocalToolsInterface): + def compileCheck(self, requirementID, ws_path, repo_path): + pass + + def lintCheck(self, requirementID, ws_path, repo_path, file_path): + pass \ No newline at end of file diff --git a/backend/app/pkgs/prompt/code_basic.py b/backend/app/pkgs/prompt/code_basic.py index 2242c50a3..f0578839b 100644 --- a/backend/app/pkgs/prompt/code_basic.py +++ b/backend/app/pkgs/prompt/code_basic.py @@ -81,7 +81,7 @@ def aiFixError(self, requirementID, solution, code, filePath, type): def aiCheckCode(self, requirementID, fileTask, code, filePath): - goodCodeRe, success = self.aiReviewCode(requirementID, fileTask, code) + goodCodeRe, success = self.aiReviewCode(requirementID, fileTask, code, filePath) jsonData = {"reasoning": goodCodeRe, "code": code} diff --git a/db/database.db b/db/database.db index db77edbb5895d666014aaf3cf4d111c7e302ae65..471e4f70d2ae53662acda6bec5b9a39759798188 100644 GIT binary patch delta 1415 zcmdT@OH30{6n(EVold9InU24z2#g=3O^TEje;6Rd5Ov{)T9g%afI%Djvz>|fOFN<| zZshY^i6)pB35Y=*O={GQxMkzUgq?{6MK_wb(1r00pHNM7t(m;M`|dk)&OLeeW`>E( zFwtKmGy?$ai;Kkj+5wNhv>9ycoU;=v01Zn3ALLhalWdn|z4;cY!V*|ApbaxUrv;01 z^JbWJqgr+cx=%aN_tB!#qS0B{iaiQgJoeE{EEZQmp-y7;J0_dQiyXe*#j>hN8j#lKtJv} zA%)hAxYC8yF0gtSQ7p{Pdzh!g7x85HWH=^8LIsEgEqo~@5{s1?9EPoe-Dwqb{fqj$DNL#8{JAe|e?Fgx=Z$=qX>1 z?ELs62Pv*Hvk}01xUBsSJI6-YbH=9&jv$-9VB>&23azCy?f28`iu2Di`M!a7xy-xV z*zAje54WGpUhSQI)|bDMo4s-Q{o}EGf6x1&Z2m#tOfEOm+ehtSeoa;Hs`2@vQc97NowB4)eT98zl9Kt|t(h zbvb$sS}7LLrP^Vw2}PsD=v;gYs*S(0@-{${Zvgp5XA)B+rKR9n0FjVhjeB!zdKyis z#hB-#dKKbLJyT}JbVC;sCSypyB0l}ai36Hw_-#IkhKHJ)U@ld$7Ng~R&i>0SU#|C# zmjAVZ`$-2&QmufQunbzWR4abVL)8D^PLGVNG|?1G;a36x4{BzOoxqV5FB@KzE*$y9 F{{$AQr>_72 delta 2675 zcmeHITTB#J7@o7U!`^q+YP%F@nbztq4Yc4^(`dmWkU&xdabxL&(qU)R$zEpNnX$n( z*HNZPKkxYDnxu&+M&G>|@{9&F(q# zpYMFUi)W`lDi8gZ#!v+cq3L+b%JS!(BuTDPx`m3Fe6=&e6 zq#SgRQyW3*7HPq&c0D}9W?FS1?C>y-0xKO7xx=(a>=Ju|Y?j`Y&uwr{fzj0Lf^zZ9 zPDjT-(lqiONtH;YY(ZxgLImu}V7tId44+@MA-8&qpFV=p2vd$mHt6GfREm0r39*9k zoP2_`c$7L&-_g)q-{IW0eS7Y_GC3{XN+@^x*6v}Aa!LliS`3)Ri(#k6R)LgFE?i3X z4J-3gONl;Z@MQYVStP}yg~>jaM8No z*#9A}vv1xEPD{`Ub{O(h6sp1+wHRZd82T;7joBJhVneC;^&AL3nX+%m@4TkEIxok$ zFO~S2EIv6rymarn5zgwGU>cN$)#L`pm4*4#*yZHlEmYgt&WhR=L|T-D)diG$6Hd=1 zBT>rH7GwiiN!vsGk&G-z;0E3w^syq#s6!2Oz{C1bzpx*H7C8a_iNEl_9x14RZgK{` zNbc6FUV>qUq8m0XwMlD!iji+yhb&jkPt7N?U*s-~*`m3LS)%)a;WfS9<$~wynBtZ| zZd=iJjAk_WX@2mp_ol4}4Jg#xnh(v@{%9@Nt0+WKo}(DE?$xQNDii|1<&x`mAF=@> z{G!b(Z?yeHj>Jl>stw|%8O-{`(rucNtshUA04^uIHv!Pdtp6M^05hg9kG4hkLBIbM zc!GZe*7DyO&@?Ua03%JZG5A0WcZhYc(^~>A!C}!3v@kAKqgX8*^S%s!kjfC{uhJ=i z8tIcQ1Y#clEU3{&L#U?6@E>-42}Tf$7-=DIn_Z@d#3Fh)MlO#;Khl!R#6I~|-K35o zm+|k{op;@N3vY7aCRlgg%$>9Dyy|7P+IchXdn2Z`nQ`4HW=!Zt4FiS&B`P+74ISq^?8-=w(3Qo&GObgN#nV7f V Date: Tue, 29 Aug 2023 09:04:40 +0800 Subject: [PATCH 5/5] chore(*): update js version & update db default data --- db/database.db | Bin 53248 -> 53248 bytes frontend/app.html | 4 ++-- frontend/index.html | 2 +- frontend/requirement.html | 4 ++-- frontend/setting.html | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/db/database.db b/db/database.db index 471e4f70d2ae53662acda6bec5b9a39759798188..2dfc222eed620b00159bc9ed974d8dd78c464b87 100644 GIT binary patch delta 62 zcmZozz}&Ead4e=!_(U0J#_){^OZ1spcwTL0H%R4SVPIgWn_OVi$;dJJm(5NfxyAMo QkeqI}gpp&jjs1}c0BV2~vH$=8 delta 62 zcmZozz}&Ead4e=!=tLQ3#?XxkOZ1spd2%+h8>I5E)Nu1LOfInLWMr89%VsB#++zC( QNKUs~!pN}M#{S3z09cw7C;$Ke diff --git a/frontend/app.html b/frontend/app.html index 51e5009c0..7bd35eef6 100644 --- a/frontend/app.html +++ b/frontend/app.html @@ -15,8 +15,8 @@ - - + + diff --git a/frontend/index.html b/frontend/index.html index d654f8503..80902bda8 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -15,7 +15,7 @@ - + diff --git a/frontend/requirement.html b/frontend/requirement.html index 18e09c9e1..c737a0f94 100644 --- a/frontend/requirement.html +++ b/frontend/requirement.html @@ -15,8 +15,8 @@ - - + + diff --git a/frontend/setting.html b/frontend/setting.html index 38f539fae..ffec3f3e1 100644 --- a/frontend/setting.html +++ b/frontend/setting.html @@ -15,8 +15,8 @@ - - + +