上一篇中,AI生成web应用初步解决了简单web应用生成,但是存在两方面的问题
1) 无法向AI提供增量需求,特别是一个对话结束之后,只能把全部需求(包括新需求)再描述一遍
2) 无法用AI对存量代码进行修改,代码存在一定的不稳定性
当然解决的思路很简单,只要能让ai能读入单个文件,然后就可以通过对话驱动AI修改代码了,问题在于千问(Qwen)大模型不能读取本地文件… 怎么办,换个思路,读取本地文件根本不需要AI,只需要程序读取后喂给AI即可, 所以对单个文件的修改和保存可以归纳为:
主人: 要求打开本地指定代码
小助手: 打开本地指定代码,并反显
主人:要求结合这段代码和新需求,增加一个功能
小助手: 将这段代码和新需求提交给AI,并反显AI给出的建议
主人: 要求修改
小助手:将修改要求提交给AI,并反显AI给出的建议
主人:要求合并代码
小助手:将合并代码的要求提交AI,并反显
主人: 要求保存代码
小助手:将AI给的代码提取保持
主人:退出对话
小助手:结束对话
实际上我们只要设计一个代理小助手,他要做的事情分为两类,一类是基本确定的事情,可以用格式化对话,正则表达式提取关键信息,形成操作方法,一类是需要转交给AI进行处理的方法,于是做了个小助手程序assist.py(省略 import和 API Key,请自行补充)
class Assistant:
def __init__(self):
self.last_content = ""
self.last_AI_message = ""
self.python_path = "/home/cfets/gitea/pyWebTest1/example/server/"
self.html_path = "/home/cfets/gitea/pyWebTest1/example/templates/"
self.js_path = "/home/cfets/gitea/pyWebTest1/example/static/"
def setLastContent(self, content):
self.last_content = content
def setLastAImessage(self, message):
self.last_AI_message = message
def getLastContent(self):
return self.last_content
def getLastAImessage(self):
return self.last_AI_message
def genAImessage(self, newMsg):
return newMsg + self.last_content
# 打开文件
def openFile(self, programmingName):
file_suffix = programmingName.split(".")[-1]
match file_suffix:
case "py":
resources_file = self.python_path + programmingName
case "html":
resources_file = self.html_path + programmingName
case "javascript":
resources_file = self.js_path + programmingName
try:
with open(resources_file, "r", encoding="utf-8") as f:
content = f.read()
self.setLastContent(content)
except Exception as e:
print('Error: %s' % e)
content = '打开文件失败: %s' % e
finally:
return content
# 保存文件
def saveFile(self, replyMessages):
python_content = re.findall(r'```python(.*?)```', replyMessages, re.DOTALL)
self.saveCode("python", python_content)
html_content = re.findall(r'```html(.*?)```', replyMessages, re.DOTALL)
self.saveCode("html", html_content)
js_content = re.findall(r'```javascript(.*?)```', replyMessages, re.DOTALL)
self.saveCode("javascript", js_content)
# 保存文件原子操作
def saveCode(self, programmingName, content_list):
# 生成版本号
code_file = ""
res_content = ""
now_time = time.strftime('%Y-%m-%d_%H:%M:%S', time.localtime())
i = random.randint(1, 100)
match programmingName:
case "python":
code_file = self.python_path + "pyTest_" + now_time + '_' + str(i) + ".py"
case "html":
code_file = self.html_path + "htmlTest_" + now_time + '_' + str(i) + ".html"
case "javascript":
code_file = self.js_path + "script_" + now_time + '_' + str(i) + ".js"
# 保存至文件
if code_file != "":
try:
content = content_list[0]
with open(code_file, 'w') as f:
f.write(content)
res_content = "保存成功"
except Exception as e:
print('Error: %s' % e)
res_content = '保存失败: %s' % e
else:
res_content = "保存失败: 未找到文件类型"
return res_content
# 提交AI对话
def conversation_ask(self, message):
# 组成对话内容
ai_message = message + self.last_content
messages = [{'role': Role.USER, 'content': ai_message}]
# 提交对话
responses = Generation.call(Generation.Models.qwen_max, messages=messages, result_format='message', stream=True,
incremental_output=True)
print('from AI:', end='')
whole_message = ''
for response in responses:
if response.status_code == HTTPStatus.OK:
whole_message += response.output.choices[0]['message']['content']
print(response.output.choices[0]['message']['content'], end='')
else:
print('Request id: %s, Status code: %s, error code: %s, error message: %s' % (
response.request_id, response.status_code,
response.code, response.message
))
print('\n')
messages.append({'role': 'assistant', 'content': whole_message})
self.setLastAImessage(whole_message)
return whole_message
Assistant小助手程序主要实现,打开文件、保存文件、提交AI并处理AI回复等功能,注意小助手会hold住前一次的输入内容,以实现打开文件获取内容并向AI提交,并会hold住AI回复的内容以备主人要求保存文件
主程序如下:
# AI对话
def conversation_mutual():
# 初始化小助手
assistant = Assistant()
while True:
message = input('master:')
pattern = r'打开(.*?)文件'
if re.search(pattern, message, re.DOTALL):
programmingName = re.findall(pattern, message, re.DOTALL)[0]
content = assistant.openFile(programmingName)
print('小助手:', end='')
print(content, end='')
else:
pattern = r'保存(.*?)文件'
if re.search(pattern, message, re.DOTALL):
assistant.saveFile(assistant.getLastAImessage())
print('小助手:', end='')
print('保存完毕', end='')
else:
pattern = r'结束(.*?)对话'
if re.search(pattern, message, re.DOTALL):
break
else:
assistant.conversation_ask(message)
print('\n')
if __name__ == '__main__':
conversation_mutual()
主程序就是实现了和小助手的格式化对话,即需要
1) 输入:打开XXXX文件,小助手就会打开XXXX文件
2) 输入: 保存文件,小助手就会按预设文件名和路径的提取内容,保存文件
3)输入: 结束对话,小助手就会结束对话
我们看一下效果,执行主程序
看一下修改功能:
1 打开源代码(小助手: 显示的是格式化对话执行结果)
2 给出修改建议
要求:修改建议,1 ak.stock_zh_a_spot() 请用akshare的ak.stock_zh_a_spot_em()接口替代
可以看到已经修改(from AI: 来自于AI信息的建议)
3 保存文件: 这是格式化文件操作
4 修改落地后的文件
5 然后,我们新增一个功能
要求:新增功能能够通过localhost:5000/index的方式,跳转访问前台网页请, 并合并上次生成的代码,给出完整python文件(最好是加上这段,否则AI可能在代码省略以“原有代码…”表述)
6 保存文件
7 文件落地,两个功能都有了
那么这些修改直接用通义灵码直接在代码中修改是否可行?
用通义灵码生成**“新增路由,用于访问前端网页”**的需求,如下
感觉有点不是一步到位… 总体上说通义灵码,续写代码,看接口意义和解释非常好,但是要理解一个功能点并直接生成,稍微有点不足。
我觉得可以综合应用,小助手agent方式和通义灵码进行编码,可能更好一些
后续我们会尝试让小助手变得更智能一些,并和更多AI结合,使她的功能更强大