让 AI 帮我干活的一天

需求

AI 生成结果代码

Agent 过程

流程图

代码实现

文档工具类代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from docx import Document
import fitz # PyMuPDF
import PyPDF2
import subprocess
import os

class FileUtils:
# 读取txt文件
def read_txt_file(self, file_path):
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
return content

# 写入txt文件
def write_to_txt_file(self, file_path, content):
with open(file_path, 'w', encoding='utf-8') as file:
file.write(content)

# 读取markdown文件
def read_md_file(self, file_path):
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
return content

# 下载飞书在线文档,并转换为 md 文档 , 这里使用了feishu2md的开源项目,可以在github上搜索到
def donwlode_feishu_doc(self, feishu_file_url):
# 执行命令 feishu2md dl feishu_file_url
file_path = "D:/python_code/tool-service/temp/"
file_name = self.extract_token_from_feishu_url(feishu_file_url)
subprocess.run(['feishu2md', 'dl', '-o', f'{file_path}{file_name}', feishu_file_url])
return file_name

# 提取出飞书文档url中的token
def extract_token_from_feishu_url(self, feishu_file_url):
# 提取出飞书文档url中的token
token = feishu_file_url.split('?')[0].split('/')[-1]
return token

# 读取指定目录下的文件。
def read_file_in_dir(self, dir_path):
file_list = []
for root, dirs, files in os.walk(dir_path):
for file in files:
file_list.append(os.path.join(root, file))
return file_list

def is_file_exist(self, file_path):
if os.path.exists(file_path):
return True
else:
return False

Agent 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
from typing import Annotated, Literal

from autogen import ConversableAgent
from pydantic import BaseModel, Field

from autogent_test.file_utils import FileUtils
from setting import config
import os

# 使用llm的配置
llm_config = config.get("GPT4o")

file_util = FileUtils()
CodeTypeOperator = Literal["controller", "service", "dao", "mappings", "repository", "dto", "vo"]

base_file_path = "D:/python_code/tool-service/temp/"
# 项目根目录
project_base_path = "D:/my_code/aidemo/aidemo/"
# 代码根目录
project_code_path = "D:/my_code/aidemo/aidemo/src/main/java/com/niuwa/aidemo/"
# 开发人员提示词
dev_prompt = f"""
你是一名资深的Java开发工程师,请根据需求开发文档的地址,按照要求完成开发任务,并输出对应的实现代码
## 开发任务
1. 根据表结构设计,完成 entity 类的创建
2. 接口开发:根据接口开发文档,完成以下层次的代码开发:
- mappings.xml层
- dao层
- service层
- controller层
- repository层
- vo层
4. VO类:开发过程中需要用到VO(视图对象),请创建单独的类,并进行引用。
5. 如果有不知道这些类的代码如何写,则可以查看一些对应的代码模板
## 代码规范要求
1. 实体类:实体类的属性需要使用 `@ApiModelProperty` 进行说明。
2. Controller层:
使用 `@GetMapping` 和 `@PostMapping` 指定路径。
使用 `@ApiOperation` 说明方法的作用。
使用 `@RequestBody` 和 `@RequestParam` 标识参数信息。
3. 配置文件:不需要输出 `application.properties` 和 `pom.xml` 的配置信息。
4. 启动类和Swagger配置:不需要输出启动类和Swagger配置。
5. 方法返回值:方法的返回值最好使用DTO类进行返回(最好能复用),不要使用Map,防止其他开发人员不了解返回值的内容。
6. SERVICE层:不需要使用接口,直接使用实现类即可。
## 技术要求
1. 开发框架:使用Spring Boot。
2. 数据库:使用MySQL。
3. 持久化层:使用MyBatis框架。
4. 插件:引入了Lombok插件。
## 项目工程路径说明
1. 项目的根目录:{project_base_path}
2. 代码的根目录:{project_code_path}
3. controller层代码目录:{project_code_path}/web
4. service层代码目录:{project_code_path}/application/command
5. Repository层代码目录:{project_code_path}/domain/repository
6. dao层代码目录:{project_code_path}/infrastructure/dao
7. mappings.xml层代码目录:{project_base_path}/src/main/resources/mappings
8. entity层代码目录:{project_code_path}/domain/model/entity
9. vo层代码目录:{project_code_path}/dto/viewobject

## 任务结束标识
如果你确保所有的代码已经开发完成,并且写入文件,则可以输出"TERMINATE",表示已经结束开发。
"""


class ReadFeishuDocInput(BaseModel):
feishu_file_url: Annotated[str, Field(description="飞书文档地址")]

class WriteCodeInput(BaseModel):
file_name: Annotated[str, Field(description="代码文件名称,不包含扩展名")]
code_content: Annotated[str, Field(description="具体的代码实现内容")]
code_type: Annotated[
CodeTypeOperator, "代码类型选项,dao\service\controller\mappings\repository\vo\entity这些类型,会被写入到不同的文件中"]

class ReadCodeTemplateInput(BaseModel):
code_type: Annotated[
CodeTypeOperator, "代码类型选项,dao\service\controller\mappings\repository\vo\entity这些类型,返回对应类型代码的模板"]


# 读取飞书需求文档内容""
def read_feishu_doc(input: Annotated[ReadFeishuDocInput, "输入飞书文档地址,返回飞书文档内容"]) -> str:
# 下载飞书文档
file_path_name = file_util.donwlode_feishu_doc(input.feishu_file_url)
doc_file = file_util.read_file_in_dir(f'{base_file_path}{file_path_name}')[0]
content = file_util.read_md_file(doc_file)
return content


# 写代码到文件
def write_code(input: Annotated[WriteCodeInput, "将代码写入到具体的文件中,并返回文件路径"]) -> str:
if input.code_type == "controller":
file_path = f"{project_code_path}/web/{input.file_name}.java"
elif input.code_type == "service":
file_path = f"{project_code_path}/application/command/{input.file_name}.java"
elif input.code_type == "repository":
file_path = f"{project_code_path}/domain/repository/{input.file_name}.java"
elif input.code_type == "dao":
file_path = f"{project_code_path}/infrastructure/dao/{input.file_name}.java"
elif input.code_type == "mappings":
file_path = f"{project_base_path}/src/main/resources/mappings/{input.file_name}.xml"
elif input.code_type == 'vo':
file_path = f"{project_code_path}/dto/viewobject/{input.file_name}.java"
elif input.code_type == 'entity':
file_path = f"{project_code_path}/domain/model/entity/{input.file_name}.java"
elif input.code_type == 'dto':
file_path = f"{project_code_path}/dto/{input.file_name}.java"

if not file_util.is_file_exist(file_path):
# 创建文件路径
directory = os.path.dirname(file_path)
# 如果目录不存在,则创建目录
if not os.path.exists(directory):
os.makedirs(directory)
file_util.write_to_txt_file(file_path, input.code_content)
return file_path


# 开始写代码。
def main(feishu_file_url):
assistant = ConversableAgent(
"assistant",
system_message=dev_prompt,
llm_config={"config_list": [llm_config]},
human_input_mode="NEVER", # Never ask for human input.
)

human_proxy = ConversableAgent(
"human_proxy",
llm_config=False, # no LLM used for human proxy
is_termination_msg=lambda msg: msg.get("content") is not None and "TERMINATE" in msg["content"],
human_input_mode="NEVER", # always ask for human input
)

# Register the tool signature with the assistant agent.
assistant.register_for_llm(name="read_feishu_doc", description="根据提供的飞书在线文档URL,读取并返回文档内容")(read_feishu_doc)
assistant.register_for_llm(name="write_code", description="将生成的代码写入对应的文件中,需要传入文件名称、代码内容和代码类型")(write_code)

# Register the tool function with the user proxy agent.
human_proxy.register_for_execution(name="read_feishu_doc")(read_feishu_doc)
human_proxy.register_for_execution(name="write_code")(write_code)

# 开始提问
human_proxy.initiate_chat(assistant, message=f"需求文档地址为:{feishu_file_url}")


main("<飞书云文档>")