add non-software role/action BaseModel

This commit is contained in:
better629 2023-12-22 13:47:44 +08:00 committed by geekan
parent 8d20af119c
commit c97b54e0ea
16 changed files with 162 additions and 121 deletions

View file

@ -1,8 +1,12 @@
import traceback
from pathlib import Path
from pydantic import Field
from metagpt.actions.write_code import WriteCode
from metagpt.llm import LLM
from metagpt.logs import logger
from metagpt.provider.base_gpt_api import BaseGPTAPI
from metagpt.schema import Message
from metagpt.utils.highlight import highlight
@ -27,8 +31,9 @@ def run(*args) -> pd.DataFrame:
class CloneFunction(WriteCode):
def __init__(self, name="CloneFunction", context: list[Message] = None, llm=None):
super().__init__(name, context, llm)
name: str = "CloneFunction"
context: list[Message] = []
llm: BaseGPTAPI = Field(default_factory=LLM)
def _save(self, code_path, code):
if isinstance(code_path, str):

View file

@ -5,12 +5,20 @@
@Author : alexanderwu
@File : design_api_review.py
"""
from typing import Optional
from pydantic import Field
from metagpt.actions.action import Action
from metagpt.llm import LLM
from metagpt.provider.base_gpt_api import BaseGPTAPI
class DesignReview(Action):
def __init__(self, name, context=None, llm=None):
super().__init__(name, context, llm)
name: str = "DesignReview"
context: Optional[str] = None
llm: BaseGPTAPI = Field(default_factory=LLM)
async def run(self, prd, api_design):
prompt = (

View file

@ -5,13 +5,19 @@
@Author : femto Zheng
@File : execute_task.py
"""
from pydantic import Field
from metagpt.actions import Action
from metagpt.llm import LLM
from metagpt.provider.base_gpt_api import BaseGPTAPI
from metagpt.schema import Message
class ExecuteTask(Action):
def __init__(self, name="ExecuteTask", context: list[Message] = None, llm=None):
super().__init__(name, context, llm)
name: str = "ExecuteTask"
context: list[Message] = []
llm: BaseGPTAPI = Field(default_factory=LLM)
def run(self, *args, **kwargs):
pass

View file

@ -21,5 +21,7 @@ class GenerateQuestions(Action):
"""This class allows LLM to further mine noteworthy details based on specific "##TOPIC"(discussion topic) and
"##RECORD" (discussion records), thereby deepening the discussion."""
name: str = "GenerateQuestions"
async def run(self, context):
return await QUESTIONS.fill(context=context, llm=self.llm)

View file

@ -12,17 +12,21 @@ import os
import zipfile
from datetime import datetime
from pathlib import Path
from typing import Optional
import pandas as pd
from paddleocr import PaddleOCR
from pydantic import Field
from metagpt.actions import Action
from metagpt.const import INVOICE_OCR_TABLE_PATH
from metagpt.llm import LLM
from metagpt.logs import logger
from metagpt.prompts.invoice_ocr import (
EXTRACT_OCR_MAIN_INFO_PROMPT,
REPLY_OCR_QUESTION_PROMPT,
)
from metagpt.provider.base_gpt_api import BaseGPTAPI
from metagpt.utils.common import OutputParser
from metagpt.utils.file import File
@ -36,8 +40,9 @@ class InvoiceOCR(Action):
"""
def __init__(self, name: str = "", *args, **kwargs):
super().__init__(name, *args, **kwargs)
name: str = "InvoiceOCR"
context: Optional[str] = None
llm: BaseGPTAPI = Field(default_factory=LLM)
@staticmethod
async def _check_file_type(file_path: Path) -> str:
@ -125,9 +130,9 @@ class GenerateTable(Action):
"""
def __init__(self, name: str = "", language: str = "ch", *args, **kwargs):
super().__init__(name, *args, **kwargs)
self.language = language
name: str = "GenerateTable"
context: Optional[str] = None
llm: BaseGPTAPI = Field(default_factory=LLM)
async def run(self, ocr_results: list, filename: str, *args, **kwargs) -> dict[str, str]:
"""Processes OCR results, extracts invoice information, generates a table, and saves it as an Excel file.
@ -169,9 +174,10 @@ class ReplyQuestion(Action):
"""
def __init__(self, name: str = "", language: str = "ch", *args, **kwargs):
super().__init__(name, *args, **kwargs)
self.language = language
name: str = "ReplyQuestion"
context: Optional[str] = None
llm: BaseGPTAPI = Field(default_factory=LLM)
language: str = "ch"
async def run(self, query: str, ocr_result: list, *args, **kwargs) -> str:
"""Reply to questions based on ocr results.

View file

@ -19,5 +19,7 @@ Attention: Provide as markdown block as the format above, at least 10 questions.
class PrepareInterview(Action):
name: str = "PrepareInterview"
async def run(self, context):
return await QUESTIONS.fill(context=context, llm=self.llm)

View file

@ -3,13 +3,15 @@
from __future__ import annotations
import asyncio
from typing import Callable
from typing import Callable, Optional, Union
from pydantic import parse_obj_as
from pydantic import Field, parse_obj_as
from metagpt.actions import Action
from metagpt.config import CONFIG
from metagpt.llm import LLM
from metagpt.logs import logger
from metagpt.provider.base_gpt_api import BaseGPTAPI
from metagpt.tools.search_engine import SearchEngine
from metagpt.tools.web_browser_engine import WebBrowserEngine, WebBrowserEngineType
from metagpt.utils.common import OutputParser
@ -78,17 +80,12 @@ above. The report must meet the following requirements:
class CollectLinks(Action):
"""Action class to collect links from a search engine."""
def __init__(
self,
name: str = "",
*args,
rank_func: Callable[[list[str]], None] | None = None,
**kwargs,
):
super().__init__(name, *args, **kwargs)
self.desc = "Collect links from a search engine."
self.search_engine = SearchEngine()
self.rank_func = rank_func
name: str = "CollectLinks"
context: Optional[str] = None
llm: BaseGPTAPI = Field(default_factory=LLM)
desc: str = "Collect links from a search engine."
search_engine: SearchEngine = Field(default_factory=SearchEngine)
rank_func: Union[Callable[[list[str]], None], None] = None
async def run(
self,
@ -178,20 +175,20 @@ class CollectLinks(Action):
class WebBrowseAndSummarize(Action):
"""Action class to explore the web and provide summaries of articles and webpages."""
def __init__(
self,
*args,
browse_func: Callable[[list[str]], None] | None = None,
**kwargs,
):
super().__init__(*args, **kwargs)
name: str = "WebBrowseAndSummarize"
context: Optional[str] = None
llm: BaseGPTAPI = Field(default_factory=LLM)
desc = "Explore the web and provide summaries of articles and webpages."
browse_func = Union[Callable[[list[str]], None], None] = None
web_browser_engine: WebBrowserEngine = WebBrowserEngine(
engine=WebBrowserEngineType.CUSTOM if browse_func else None,
run_func=browse_func,
)
def __init__(self, **kwargs):
super().__init__(**kwargs)
if CONFIG.model_for_researcher_summary:
self.llm.model = CONFIG.model_for_researcher_summary
self.web_browser_engine = WebBrowserEngine(
engine=WebBrowserEngineType.CUSTOM if browse_func else None,
run_func=browse_func,
)
self.desc = "Explore the web and provide summaries of articles and webpages."
async def run(
self,
@ -247,8 +244,12 @@ class WebBrowseAndSummarize(Action):
class ConductResearch(Action):
"""Action class to conduct research and generate a research report."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
name: str = "ConductResearch"
context: Optional[str] = None
llm: BaseGPTAPI = Field(default_factory=LLM)
def __init__(self, **kwargs):
super().__init__(**kwargs)
if CONFIG.model_for_researcher_report:
self.llm.model = CONFIG.model_for_researcher_report

View file

@ -22,9 +22,13 @@ This script uses the 'fire' library to create a command-line interface. It gener
the specified docstring style and adds them to the code.
"""
import ast
from typing import Literal
from typing import Literal, Optional
from pydantic import Field
from metagpt.actions.action import Action
from metagpt.llm import LLM
from metagpt.provider.base_gpt_api import BaseGPTAPI
from metagpt.utils.common import OutputParser
from metagpt.utils.pycst import merge_docstring
@ -157,9 +161,9 @@ class WriteDocstring(Action):
desc: A string describing the action.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.desc = "Write docstring for code."
desc: str = "Write docstring for code."
context: Optional[str] = None
llm: BaseGPTAPI = Field(default_factory=LLM)
async def run(
self,

View file

@ -6,8 +6,12 @@
"""
from typing import List
from pydantic import Field
from metagpt.actions import Action
from metagpt.actions.action_node import ActionNode
from metagpt.llm import LLM
from metagpt.provider.base_gpt_api import BaseGPTAPI
REVIEW = ActionNode(
key="Review",
@ -33,5 +37,8 @@ WRITE_REVIEW_NODE = ActionNode.from_children("WRITE_REVIEW_NODE", [REVIEW, LGTM]
class WriteReview(Action):
"""Write a review for the given context."""
name: str = "WriteReview"
llm: BaseGPTAPI = Field(default_factory=LLM)
async def run(self, context):
return await WRITE_REVIEW_NODE.fill(context=context, llm=self.llm, schema="json")

View file

@ -9,8 +9,12 @@
from typing import Dict
from pydantic import Field
from metagpt.actions import Action
from metagpt.llm import LLM
from metagpt.prompts.tutorial_assistant import CONTENT_PROMPT, DIRECTORY_PROMPT
from metagpt.provider.base_gpt_api import BaseGPTAPI
from metagpt.utils.common import OutputParser
@ -22,9 +26,9 @@ class WriteDirectory(Action):
language: The language to output, default is "Chinese".
"""
def __init__(self, name: str = "", language: str = "Chinese", *args, **kwargs):
super().__init__(name, *args, **kwargs)
self.language = language
name: str = "WriteDirectory"
llm: BaseGPTAPI = Field(default_factory=LLM)
language: str = "Chinese"
async def run(self, topic: str, *args, **kwargs) -> Dict:
"""Execute the action to generate a tutorial directory according to the topic.
@ -49,10 +53,10 @@ class WriteContent(Action):
language: The language to output, default is "Chinese".
"""
def __init__(self, name: str = "", directory: str = "", language: str = "Chinese", *args, **kwargs):
super().__init__(name, *args, **kwargs)
self.language = language
self.directory = directory
name: str = "WriteContent"
llm: BaseGPTAPI = Field(default_factory=LLM)
directory: str = ""
language: str = "Chinese"
async def run(self, topic: str, *args, **kwargs) -> str:
"""Execute the action to write document content according to the directory and topic.

View file

@ -29,8 +29,4 @@ class CustomerService(Sales):
name: str = "Xiaomei"
profile: str = "Human customer service"
desc: str = DESC
store: Optional[str] = None
def __init__(self, **kwargs):
super().__init__(**kwargs)

View file

@ -7,11 +7,13 @@
@File : invoice_ocr_assistant.py
"""
from typing import Optional
import pandas as pd
from metagpt.actions.invoice_ocr import GenerateTable, InvoiceOCR, ReplyQuestion
from metagpt.prompts.invoice_ocr import INVOICE_OCR_SUCCESS
from metagpt.roles import Role
from metagpt.roles.role import Role, RoleReactMode
from metagpt.schema import Message
@ -28,21 +30,18 @@ class InvoiceOCRAssistant(Role):
language: The language in which the invoice table will be generated.
"""
def __init__(
self,
name: str = "Stitch",
profile: str = "Invoice OCR Assistant",
goal: str = "OCR identifies invoice files and generates invoice main information table",
constraints: str = "",
language: str = "ch",
):
super().__init__(name, profile, goal, constraints)
self._init_actions([InvoiceOCR])
self.language = language
self.filename = ""
self.origin_query = ""
self.orc_data = None
self._set_react_mode(react_mode="by_order")
name: str = "Stitch"
profile: str = "Invoice OCR Assistant"
goal: str = "OCR identifies invoice files and generates invoice main information table"
constraints: str = ""
language: str = "ch"
filename: str = ""
origin_query: str = ""
orc_data: Optional[list] = None
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
async def _act(self) -> Message:
"""Perform an action as determined by the role.

View file

@ -13,7 +13,7 @@ from metagpt.actions import Action, CollectLinks, ConductResearch, WebBrowseAndS
from metagpt.actions.research import get_research_system_text
from metagpt.const import RESEARCH_PATH
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.roles.role import Role, RoleReactMode
from metagpt.schema import Message
@ -25,21 +25,20 @@ class Report(BaseModel):
class Researcher(Role):
def __init__(
self,
name: str = "David",
profile: str = "Researcher",
goal: str = "Gather information and conduct research",
constraints: str = "Ensure accuracy and relevance of information",
language: str = "en-us",
**kwargs,
):
super().__init__(name, profile, goal, constraints, **kwargs)
self._init_actions([CollectLinks(name), WebBrowseAndSummarize(name), ConductResearch(name)])
self._set_react_mode(react_mode="by_order")
self.language = language
if language not in ("en-us", "zh-cn"):
logger.warning(f"The language `{language}` has not been tested, it may not work.")
name: str = "David"
profile: str = "Researcher"
goal: str = "Gather information and conduct research"
constraints: str = "Ensure accuracy and relevance of information"
language: str = "en-us"
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions(
[CollectLinks(name=self.name), WebBrowseAndSummarize(name=self.name), ConductResearch(name=self.name)]
)
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
if self.language not in ("en-us", "zh-cn"):
logger.warning(f"The language `{self.language}` has not been tested, it may not work.")
async def _think(self) -> bool:
if self._rc.todo is None:
@ -118,7 +117,7 @@ if __name__ == "__main__":
import fire
async def main(topic: str, language="en-us"):
role = Researcher(topic, language=language)
role = Researcher(language=language)
await role.run(topic)
fire.Fire(main)

View file

@ -22,7 +22,6 @@ class Sales(Role):
" I don't know, and I won't tell you that this is from the knowledge base,"
"but pretend to be what I know. Note that each of my replies will be replied in the tone of a "
"professional guide"
store: Optional[str] = None
def __init__(self, **kwargs):

View file

@ -7,13 +7,16 @@
@Modified By: mashenquan, 2023-11-1. In accordance with Chapter 2.2.1 and 2.2.2 of RFC 116, utilize the new message
distribution feature for message filtering.
"""
from pydantic import Field
from semantic_kernel.planning import SequentialPlanner
from semantic_kernel.planning.action_planner.action_planner import ActionPlanner
from semantic_kernel.planning.basic_planner import BasicPlanner
from metagpt.actions import UserRequirement
from metagpt.actions.execute_task import ExecuteTask
from metagpt.logs import logger
from metagpt.llm import LLM
from metagpt.provider.base_gpt_api import BaseGPTAPI
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.utils.make_sk_kernel import make_sk_kernel
@ -30,27 +33,28 @@ class SkAgent(Role):
constraints (str): Constraints for the SkAgent.
"""
def __init__(
self,
name: str = "Sunshine",
profile: str = "sk_agent",
goal: str = "Execute task based on passed in task description",
constraints: str = "",
planner_cls=BasicPlanner,
) -> None:
name: str = "Sunshine"
profile: str = "sk_agent"
goal: str = "Execute task based on passed in task description"
constraints: str = ""
planner_cls: BasicPlanner = BasicPlanner
planner: BasicPlanner = Field(default_factory=BasicPlanner)
llm: BaseGPTAPI = Field(default_factory=LLM)
def __init__(self, **kwargs) -> None:
"""Initializes the Engineer role with given attributes."""
super().__init__(name, profile, goal, constraints)
super().__init__(**kwargs)
self._init_actions([ExecuteTask()])
self._watch([UserRequirement])
self.kernel = make_sk_kernel()
# how funny the interface is inconsistent
if planner_cls == BasicPlanner:
self.planner = planner_cls()
elif planner_cls in [SequentialPlanner, ActionPlanner]:
self.planner = planner_cls(self.kernel)
if self.planner_cls == BasicPlanner:
self.planner = self.planner_cls()
elif self.planner_cls in [SequentialPlanner, ActionPlanner]:
self.planner = self.planner_cls(self.kernel)
else:
raise f"Unsupported planner of type {planner_cls}"
raise Exception(f"Unsupported planner of type {self.planner_cls}")
self.import_semantic_skill_from_directory = self.kernel.import_semantic_skill_from_directory
self.import_skill = self.kernel.import_skill

View file

@ -12,7 +12,7 @@ from typing import Dict
from metagpt.actions.write_tutorial import WriteContent, WriteDirectory
from metagpt.const import TUTORIAL_PATH
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.roles.role import Role, RoleReactMode
from metagpt.schema import Message
from metagpt.utils.file import File
@ -28,21 +28,20 @@ class TutorialAssistant(Role):
language: The language in which the tutorial documents will be generated.
"""
def __init__(
self,
name: str = "Stitch",
profile: str = "Tutorial Assistant",
goal: str = "Generate tutorial documents",
constraints: str = "Strictly follow Markdown's syntax, with neat and standardized layout",
language: str = "Chinese",
):
super().__init__(name, profile, goal, constraints)
self._init_actions([WriteDirectory(language=language)])
self.topic = ""
self.main_title = ""
self.total_content = ""
self.language = language
self._set_react_mode(react_mode="by_order")
name: str = "Stitch"
profile: str = "Tutorial Assistant"
goal: str = "Generate tutorial documents"
constraints: str = "Strictly follow Markdown's syntax, with neat and standardized layout"
language: str = "Chinese"
topic = ""
main_title = ""
total_content = ""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([WriteDirectory(language=self.language)])
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
async def _handle_directory(self, titles: Dict) -> Message:
"""Handle the directories for the tutorial document.