metagpt框架学习 使用ai一键生成故事的插图

本文介绍了如何使用Metagpt框架编写Python脚本,对故事进行分段、创建人物角色描述,整理图片描述,最终生成故事插图的过程,展示了通过编程实现的AI辅助内容创作方法。
摘要由CSDN通过智能技术生成

前言

个人学习的笔记,简单的小程序,使用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目录,里面会保存我们生成的插画

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值