前言
个人学习的笔记,简单的小程序,使用metagpt框架生成一个故事的插图
正文
工作逻辑如下:
1.对故事进行分段
一个故事咱们必须先用ai对这个故事进行分段,代码如下,我设定的py文件名为SplitParagraphs
from builtins import str
from metagpt.actions import Action
from metagpt.actions.action_node import ActionNode
from metagpt.roles.role import Role, RoleReactMode
DIRECTORY_STRUCTION = """
你现在是一个读者,你要对下方文字进行分割
"""
Content = """
故事如下
{story}
对于这个故事
1.输出语言为中文
2.对每句完整的话进行分割,对句号和分段进行分割
3.严格按照字典格式进行回答,如{{"partition":[{{"person":[{{"person1","person2}}],"content":"content1"}}]}}
4.person为一个存放集合,用于存放这个分段中出现的所有人物
5.不要有空格和换行
"""
# 实例化一个ActionNode,输入对应的参数
DIRECTORY_WRITE = ActionNode(
# ActionNode的名称
key="Partition",
# 期望输出的格式
expected_type=str,
# 命令文本
instruction=DIRECTORY_STRUCTION,
# 例子输入,在这里我们可以留空
example="",
)
class Partition(Action):
async def run(self, story: str, *args, **kwargs) -> dict:
prompt = Content.format(story=story)
resp_node = await DIRECTORY_WRITE.fill(context=prompt, llm=self.llm, schema="raw")
# # 选取ActionNode.content,获得我们期望的返回信息
resp = resp_node.content
dictionary = eval(resp)
return dictionary
class PartitionActionNode(Role):
name: str = "PartitionActionNode"
profile: str = "reader"
story: str = ""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([Partition()])
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
async def _act(self) -> dict:
todo = self.rc.todo
story = self.get_memories(k=1)[0]
resp = await todo.run(story=story.content)
return resp
async def main(story):
role = PartitionActionNode()
return_code = await role.run(story)
print(type(return_code))
print(return_code)
return return_code
2.对故事的人物进行构建
我们需要生成图片之前,对人物进行统一构建,不然会ai对于同一人物,没有任何相同的地方,代码如下,我设定的py文件名字为Get_Person
from builtins import str
from metagpt.actions import Action
from metagpt.actions.action_node import ActionNode
from metagpt.roles.role import Role, RoleReactMode
DIRECTORY_STRUCTION = """
你现在是一个读者,你要对下方文字中的人物进行设计
"""
Content = """
故事如下
{story}
对于这个故事
1.输出语言为中文
2.分析故事中出现的每一个人,并随机返回每一个人的特征,如,性别,发色,年龄,例如:一个头发颜色为xxx色,眼睛为xxx色的小孩子,不要存在可能等不确定的字样,是什么颜色是你说的算
3.严格按照字典格式进行回答,如{{"person":[{{"name":"name1","features":"features1"}},{{"name":"name2","features":"features2"}}]}}
4.name存放这个人的姓名,features存放这个人的特征
5.不要有多余的空格或换行符
"""
# 实例化一个ActionNode,输入对应的参数
DIRECTORY_WRITE = ActionNode(
# ActionNode的名称
key="Partition",
# 期望输出的格式
expected_type=str,
# 命令文本
instruction=DIRECTORY_STRUCTION,
# 例子输入,在这里我们可以留空
example="",
)
class Person(Action):
async def run(self, story: str, *args, **kwargs) -> dict:
prompt = Content.format(story=story)
resp_node = await DIRECTORY_WRITE.fill(context=prompt, llm=self.llm, schema="raw")
# # 选取ActionNode.content,获得我们期望的返回信息
resp = resp_node.content
dictionary = eval(resp)
return dictionary
class PersonActionNode(Role):
name: str = "PersonActionNode"
profile: str = "reader"
story: str = ""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([Person()])
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
async def _act(self) -> dict:
todo = self.rc.todo
story = self.get_memories(k=1)[0]
resp = await todo.run(story=story.content)
return resp
async def main(story:str):
role = PersonActionNode()
return_code = await role.run(story)
return return_code
3.整理人物形象
我们让ai生成出来的人物形象无法直接使用,我们需要进行处理,代码如下,我设定的py文件名为Conformity_Preson
import asyncio
from builtins import str
from metagpt.actions import Action
from metagpt.actions.action_node import ActionNode
from metagpt.logs import logger
from metagpt.roles.role import Role, RoleReactMode
from metagpt.schema import Message
DIRECTORY_STRUCTION = """
你现在是一个读者,你要对下方文字中的人物进行设计
"""
Content = """
信息如下:
{Information}
1.对传入的数据进行整合
2.例如,传入的数据为:{{'name': '孔融', 'features': '一个黑发,年幼的小男孩,大约六岁,眼睛明亮'}},那么返回的结果:{{"data":"孔融是一个黑发,大约六岁,眼睛明亮,年幼的小男孩"}}
3.返回的结果为一个字典,不要有其他的任何内容和符号和换行
"""
# 实例化一个ActionNode,输入对应的参数
DIRECTORY_WRITE = ActionNode(
# ActionNode的名称
key="Conformity_Preson",
# 期望输出的格式
expected_type=str,
# 命令文本
instruction=DIRECTORY_STRUCTION,
# 例子输入,在这里我们可以留空
example="",
)
class Conformity_Preson(Action):
async def run(self, Information: str, *args, **kwargs) -> str:
prompt = Content.format(Information=Information)
# prompt = Content.format(story=story)
# print(prompt)
resp_node = await DIRECTORY_WRITE.fill(context=prompt, llm=self.llm, schema="raw")
# # 选取ActionNode.content,获得我们期望的返回信息
resp = resp_node.content
# print(resp)
# return OutputParser.extract_struct(resp, dict)
return resp
class Conformity_PresonActionNode(Role):
name: str = "PersonActionNode"
profile: str = "reader"
story: str = ""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([Conformity_Preson()])
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
async def _act(self) -> Message:
todo = self.rc.todo
Information = self.get_memories(k=1)[0]
resp = await todo.run(Information=Information.content)
return Message(content=resp, role=self.profile)
async def main(Information :str):
# Information :str = "{'name': '孔融', 'features': '一个黑发,年幼,大约六七岁的小孩子,眼睛明亮'}"
role = Conformity_PresonActionNode()
# await role.run(story)
return_code = await role.run(Information)
return return_code.content
4.整理图片描述
我们整理每个人物的形象和对故事进行分段之后,生成几张图片就已经确定,这个时候我们需要生成对这张图片的描述,由步骤1和步骤.得到的东西交给ai整理可以生成图片描述,代码如下,我设定的py文件名为Get_Picture_Description
import asyncio
from builtins import str
from metagpt.actions import Action
from metagpt.actions.action_node import ActionNode
from metagpt.logs import logger
from metagpt.roles.role import Role, RoleReactMode
from metagpt.schema import Message
DIRECTORY_STRUCTION = """
你现在是一个动画设计这,你要对下方文字设计个图片
"""
Content = """
内容如下:
{content}
所有人物形象如下:
{All_Persona}
当前图片有的人物为:
{Current_Person}
对于这个图片的描述:
1.输出语言为中文
2.根据给的内容,进行设计一个图片,例如:一个什么颜色头发的孩子正在做什么动作
3.严格按照字典格式进行回答,如{{"data":"description"}}
4.description为对这个图片的描述
5.不要有多余的空格或换行符
"""
# 实例化一个ActionNode,输入对应的参数
DIRECTORY_WRITE = ActionNode(
# ActionNode的名称
key="Partition",
# 期望输出的格式
expected_type=str,
# 命令文本
instruction=DIRECTORY_STRUCTION,
# 例子输入,在这里我们可以留空
example="",
)
class Get_Picture_Description(Action):
async def run(self, content: str, All_Persona: str,Current_Person:str, *args, **kwargs) -> str:
prompt = Content.format(content=content,All_Persona = All_Persona,Current_Person = Current_Person)
# print(prompt)
resp_node = await DIRECTORY_WRITE.fill(context=prompt, llm=self.llm, schema="raw")
# # 选取ActionNode.content,获得我们期望的返回信息
resp = resp_node.content
# print(resp)
# return OutputParser.extract_struct(resp, dict)
return resp
class Get_Picture_DescriptionActionNode(Role):
name: str = "PersonActionNode"
profile: str = "reader"
story: str = ""
content:str = ""
All_Persona:str = ""
Current_Person:str = ""
def __init__(self,content: str, All_Persona: str,Current_Person:str, **kwargs):
super().__init__(**kwargs)
self._init_actions([Get_Picture_Description()])
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
self.content = content
self.All_Persona = All_Persona
self.Current_Person = Current_Person
async def _act(self) -> Message:
todo = self.rc.todo
resp = await todo.run(content=self.content, All_Persona=self.All_Persona,Current_Person=self.Current_Person)
return Message(content=resp, role=self.profile)
async def main(content:str,All_Persona:str,Current_Person:str):
role = Get_Picture_DescriptionActionNode(content = content,All_Persona = All_Persona,Current_Person = Current_Person)
# await role.run(story)
return_code = await role.run("1")
return return_code
5.生成图片
不多说,调用api接口生成图片
智谱ai的文档
我的py文件名为Get_Image
import asyncio
from metagpt.actions import Action
from metagpt.logs import logger
from metagpt.roles.role import Role, RoleReactMode
from metagpt.schema import Message
from zhipuai import ZhipuAI
client = ZhipuAI(api_key="***") # 这个不能给你们看
# 生成图片
class WriteContentWithActionNode(Action):
Prompt :str = """
{content}
"""
async def run(self, content: str, *args, **kwargs) -> str:
prompt = self.Prompt.format(content=content)
print(prompt)
response = client.images.generations(
model="cogview-3", # 填写需要调用的模型名称
prompt=prompt,
)
print(response.data[0].url)
return response.data[0].url
class TutorialAssistantWithActionNode(Role):
name: str = "Stitch"
profile: str = "Tutorial Assistant"
topic: str = ""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([WriteContentWithActionNode()])
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
async def _act(self) -> str:
todo = self.rc.todo
msg = self.get_memories(k=1)[0]
resp = await todo.run(content=msg.content)
print(type(resp))
print(resp)
return resp
async def main(content:str):
role = TutorialAssistantWithActionNode()
data = await role.run(content)
return data
6.保存文件至本地
我的py文件名为Download_Image
import requests
import os
# 下载图片
def Download(name,url):
r = requests.get(url)
folder_path = "./illustration" # 指定文件夹路径
file_name = name # 文件名
if not os.path.exists(folder_path):
os.makedirs(folder_path)
file_path = os.path.join(folder_path, file_name) # 构建完整的文件路径
with open(file_path, "wb") as f:
f.write(r.content)
7.运行
import asyncio
import re
import Get_Person,Conformity_Preson,Get_Picture_Description,Get_Image,Download_Image
import SplitParagraphs
story: str = "一天,父亲的朋友带了一盘梨子,给孔融兄弟们吃。父亲叫孔融分梨,孔融挑了个最小的梨子,其余按照长幼顺序分给兄弟。孔融说:“我年纪小,应该吃小的梨,大梨该给哥哥们。”父亲听后十分惊喜,又问:“那弟弟也比你小啊?” 孔融说:“因为弟弟比我小,所以我也应该让着他。”孔融让梨的故事,很快传遍了汉朝。小孔融也成了许多父母教育子女的好例子。一天,父亲的朋友带了一盘梨子,给孔融兄弟们吃。父亲叫孔融分梨,孔融挑了个最小的梨子,其余按照长幼顺序分给兄弟。孔融说:“我年纪小,应该吃小的梨,大梨该给哥哥们。”父亲听后十分惊喜,又问:“那弟弟也比你小啊?” 孔融说:“因为弟弟比我小,所以我也应该让着他。”孔融让梨的故事,很快传遍了汉朝。小孔融也成了许多父母教育子女的好例子。"
async def main():
# 获取人物信息
dictionary = await Get_Person.main(story)
# 获取分段
context2 = await SplitParagraphs.main(story)
context4 = ""
for dir in dictionary.get("person"):
context3 = await Conformity_Preson.main(Information=str(dir))
pattern = r'{"data":(.*)}'
match1 = re.search(pattern, context3)
code_text1 = match1.group(1) if match1 else context3
pattern1 = r'"(.*)"'
match = re.search(pattern1, code_text1)
code_text = match.group(1) if match else code_text1
context4 += code_text
context4 += "\n"
AllLink:str=""
for index,dir in enumerate (context2.get("partition")):
Imagedescription= await Get_Picture_Description.main(content=dir.get("content"),All_Persona=context4,Current_Person=dir.get("person"))
Imagedescription1 = Imagedescription.content
dictionary = eval(Imagedescription1)
Imaged = dictionary.get("data")
link = await Get_Image.main(content=Imaged)
AllLink += dir.get("content")
index_name = str(index+1)
name = "第{index_name}张图片.png"
prompt = name.format(index_name=index_name)
Download_Image.Download(prompt,link)
AllLink += "\n"
AllLink += link
AllLink += "\n"
print("--------最终内容---------")
print(AllLink)
if __name__ == '__main__':
asyncio.run(main())
运行之后,会自动在当前目录生成一个./illustration
目录,里面会保存我们生成的插画