mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-05-11 08:42:38 +02:00
add write_review action and its test
This commit is contained in:
parent
1ab0ae99a9
commit
6959d40e6d
4 changed files with 119 additions and 3 deletions
|
|
@ -41,10 +41,10 @@ Fill in the above nodes based on the format example.
|
|||
"""
|
||||
|
||||
|
||||
def dict_to_markdown(d, prefix="-", postfix="\n"):
|
||||
def dict_to_markdown(d, prefix="##", kv_sep="\n", postfix="\n"):
|
||||
markdown_str = ""
|
||||
for key, value in d.items():
|
||||
markdown_str += f"{prefix} {key}: {value}{postfix}"
|
||||
markdown_str += f"{prefix}{key}{kv_sep}{value}{postfix}"
|
||||
return markdown_str
|
||||
|
||||
|
||||
|
|
|
|||
40
metagpt/actions/write_review.py
Normal file
40
metagpt/actions/write_review.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Author : alexanderwu
|
||||
@File : write_review.py
|
||||
"""
|
||||
from typing import List
|
||||
|
||||
from metagpt.actions import Action
|
||||
from metagpt.actions.action_node import ActionNode
|
||||
|
||||
# from metagpt.llm import LLM
|
||||
|
||||
REVIEW = ActionNode(
|
||||
key="Review",
|
||||
expected_type=List[str],
|
||||
instruction="Act as an experienced Reviewer and review the given output. Ask a series of critical questions, "
|
||||
"concisely and clearly, to help the writer improve their work.",
|
||||
example=[
|
||||
"This is a good PRD, but I think it can be improved by adding more details.",
|
||||
],
|
||||
)
|
||||
|
||||
LGTM = ActionNode(
|
||||
key="LGTM",
|
||||
expected_type=str,
|
||||
instruction="If the output is good enough, give a LGTM (Looks Good To Me) to the writer, "
|
||||
"else LBTM (Looks Bad To Me).",
|
||||
example="LGTM",
|
||||
)
|
||||
|
||||
WRITE_REVIEW_NODE = ActionNode.from_children("WRITE_REVIEW_NODE", [REVIEW, LGTM])
|
||||
|
||||
|
||||
class WriteReview(Action):
|
||||
"""This class allows LLM to further mine noteworthy details based on specific "##TOPIC"(discussion topic) and
|
||||
"##RECORD" (discussion records), thereby deepening the discussion."""
|
||||
|
||||
async def run(self, context):
|
||||
return await WRITE_REVIEW_NODE.fill(context=context, llm=self.llm, schema="markdown")
|
||||
|
|
@ -18,7 +18,7 @@ import os
|
|||
import platform
|
||||
import re
|
||||
import typing
|
||||
from typing import List, Tuple, Union
|
||||
from typing import List, Tuple, Union, get_args, get_origin
|
||||
|
||||
import aiofiles
|
||||
import loguru
|
||||
|
|
@ -129,8 +129,31 @@ class OutputParser:
|
|||
parsed_data[block] = content
|
||||
return parsed_data
|
||||
|
||||
@staticmethod
|
||||
def extract_content(text, tag="CONTENT"):
|
||||
# Use regular expression to extract content between [CONTENT] and [/CONTENT]
|
||||
extracted_content = re.search(rf"\[{tag}\](.*?)\[/{tag}\]", text, re.DOTALL)
|
||||
|
||||
if extracted_content:
|
||||
return extracted_content.group(1).strip()
|
||||
else:
|
||||
return "No content found between [CONTENT] and [/CONTENT] tags."
|
||||
|
||||
@staticmethod
|
||||
def is_supported_list_type(i):
|
||||
origin = get_origin(i)
|
||||
if origin is not List:
|
||||
return False
|
||||
|
||||
args = get_args(i)
|
||||
if args == (str,) or args == (Tuple[str, str],) or args == (List[str],):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def parse_data_with_mapping(cls, data, mapping):
|
||||
data = cls.extract_content(text=data)
|
||||
block_dict = cls.parse_blocks(data)
|
||||
parsed_data = {}
|
||||
for block, content in block_dict.items():
|
||||
|
|
|
|||
53
tests/metagpt/actions/test_write_review.py
Normal file
53
tests/metagpt/actions/test_write_review.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2023/12/20 15:01
|
||||
@Author : alexanderwu
|
||||
@File : test_write_review.py
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from metagpt.actions.write_review import WriteReview
|
||||
|
||||
CONTEXT = """
|
||||
{
|
||||
"Language": "zh_cn",
|
||||
"Programming Language": "Python",
|
||||
"Original Requirements": "写一个简单的2048",
|
||||
"Project Name": "game_2048",
|
||||
"Product Goals": [
|
||||
"创建一个引人入胜的用户体验",
|
||||
"确保高性能",
|
||||
"提供可定制的功能"
|
||||
],
|
||||
"User Stories": [
|
||||
"作为用户,我希望能够选择不同的难度级别",
|
||||
"作为玩家,我希望在每局游戏结束后能看到我的得分"
|
||||
],
|
||||
"Competitive Analysis": [
|
||||
"Python Snake Game: 界面简单,缺乏高级功能"
|
||||
],
|
||||
"Competitive Quadrant Chart": "quadrantChart\n title \"Reach and engagement of campaigns\"\n x-axis \"Low Reach\" --> \"High Reach\"\n y-axis \"Low Engagement\" --> \"High Engagement\"\n quadrant-1 \"我们应该扩展\"\n quadrant-2 \"需要推广\"\n quadrant-3 \"重新评估\"\n quadrant-4 \"可能需要改进\"\n \"Campaign A\": [0.3, 0.6]\n \"Campaign B\": [0.45, 0.23]\n \"Campaign C\": [0.57, 0.69]\n \"Campaign D\": [0.78, 0.34]\n \"Campaign E\": [0.40, 0.34]\n \"Campaign F\": [0.35, 0.78]\n \"Our Target Product\": [0.5, 0.6]",
|
||||
"Requirement Analysis": "产品应该用户友好。",
|
||||
"Requirement Pool": [
|
||||
[
|
||||
"P0",
|
||||
"主要代码..."
|
||||
],
|
||||
[
|
||||
"P0",
|
||||
"游戏算法..."
|
||||
]
|
||||
],
|
||||
"UI Design draft": "基本功能描述,简单的风格和布局。",
|
||||
"Anything UNCLEAR": "..."
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_write_review():
|
||||
write_review = WriteReview()
|
||||
review = await write_review.run(CONTEXT)
|
||||
assert review.instruct_content
|
||||
assert review.get("LGTM") in ["LGTM", "LBTM"]
|
||||
Loading…
Add table
Add a link
Reference in a new issue