Merge pull request #606 from better629/feat_basemodel

Feat add basemodel of other roles/actions and fix examples
This commit is contained in:
geekan 2023-12-22 22:59:58 +08:00 committed by GitHub
commit 41a174399e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 253 additions and 198 deletions

View file

@ -55,16 +55,13 @@ class CreateAgent(Action):
class AgentCreator(Role):
def __init__(
self,
name: str = "Matrix",
profile: str = "AgentCreator",
agent_template: str = MULTI_ACTION_AGENT_CODE_EXAMPLE,
**kwargs,
):
super().__init__(name, profile, **kwargs)
name: str = "Matrix"
profile: str = "AgentCreator"
agent_template: str = MULTI_ACTION_AGENT_CODE_EXAMPLE
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([CreateAgent])
self.agent_template = agent_template
async def _act(self) -> Message:
logger.info(f"{self._setting}: to do {self._rc.todo}({self._rc.todo.name})")
@ -86,10 +83,6 @@ if __name__ == "__main__":
creator = AgentCreator(agent_template=agent_template)
# msg = """Write an agent called SimpleTester that will take any code snippet (str)
# and return a testing code (str) for testing
# the given code snippet. Use pytest as the testing framework."""
msg = """
Write an agent called SimpleTester that will take any code snippet (str) and do the following:
1. write a testing code (str) for testing the given code snippet, save the testing code as a .py file in the current working directory;

View file

@ -10,9 +10,8 @@ import subprocess
import fire
from metagpt.actions import Action
from metagpt.llm import LLM
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.roles.role import Role, RoleReactMode
from metagpt.schema import Message
@ -23,8 +22,7 @@ class SimpleWriteCode(Action):
your code:
"""
def __init__(self, name: str = "SimpleWriteCode", context=None, llm: LLM = None):
super().__init__(name, context, llm)
name: str = "SimpleWriteCode"
async def run(self, instruction: str):
prompt = self.PROMPT_TEMPLATE.format(instruction=instruction)
@ -44,8 +42,7 @@ class SimpleWriteCode(Action):
class SimpleRunCode(Action):
def __init__(self, name: str = "SimpleRunCode", context=None, llm: LLM = None):
super().__init__(name, context, llm)
name: str = "SimpleRunCode"
async def run(self, code_text: str):
result = subprocess.run(["python3", "-c", code_text], capture_output=True, text=True)
@ -55,13 +52,11 @@ class SimpleRunCode(Action):
class SimpleCoder(Role):
def __init__(
self,
name: str = "Alice",
profile: str = "SimpleCoder",
**kwargs,
):
super().__init__(name, profile, **kwargs)
name: str = "Alice"
profile: str = "SimpleCoder"
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([SimpleWriteCode])
async def _act(self) -> Message:
@ -76,15 +71,13 @@ class SimpleCoder(Role):
class RunnableCoder(Role):
def __init__(
self,
name: str = "Alice",
profile: str = "RunnableCoder",
**kwargs,
):
super().__init__(name, profile, **kwargs)
name: str = "Alice"
profile: str = "RunnableCoder"
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([SimpleWriteCode, SimpleRunCode])
self._set_react_mode(react_mode="by_order")
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
async def _act(self) -> Message:
logger.info(f"{self._setting}: to do {self._rc.todo}({self._rc.todo.name})")

View file

@ -8,7 +8,6 @@ import re
import fire
from metagpt.actions import Action, UserRequirement
from metagpt.llm import LLM
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.schema import Message
@ -28,9 +27,7 @@ class SimpleWriteCode(Action):
Return ```python your_code_here ``` with NO other texts,
your code:
"""
def __init__(self, name: str = "SimpleWriteCode", context=None, llm: LLM = None):
super().__init__(name, context, llm)
name: str = "SimpleWriteCode"
async def run(self, instruction: str):
prompt = self.PROMPT_TEMPLATE.format(instruction=instruction)
@ -43,13 +40,11 @@ class SimpleWriteCode(Action):
class SimpleCoder(Role):
def __init__(
self,
name: str = "Alice",
profile: str = "SimpleCoder",
**kwargs,
):
super().__init__(name, profile, **kwargs)
name: str = "Alice"
profile: str = "SimpleCoder"
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._watch([UserRequirement])
self._init_actions([SimpleWriteCode])
@ -62,8 +57,7 @@ class SimpleWriteTest(Action):
your code:
"""
def __init__(self, name: str = "SimpleWriteTest", context=None, llm: LLM = None):
super().__init__(name, context, llm)
name: str = "SimpleWriteTest"
async def run(self, context: str, k: int = 3):
prompt = self.PROMPT_TEMPLATE.format(context=context, k=k)
@ -76,13 +70,11 @@ class SimpleWriteTest(Action):
class SimpleTester(Role):
def __init__(
self,
name: str = "Bob",
profile: str = "SimpleTester",
**kwargs,
):
super().__init__(name, profile, **kwargs)
name: str = "Bob"
profile: str = "SimpleTester"
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([SimpleWriteTest])
# self._watch([SimpleWriteCode])
self._watch([SimpleWriteCode, SimpleWriteReview]) # feel free to try this too
@ -106,8 +98,7 @@ class SimpleWriteReview(Action):
Review the test cases and provide one critical comments:
"""
def __init__(self, name: str = "SimpleWriteReview", context=None, llm: LLM = None):
super().__init__(name, context, llm)
name: str = "SimpleWriteReview"
async def run(self, context: str):
prompt = self.PROMPT_TEMPLATE.format(context=context)
@ -118,13 +109,11 @@ class SimpleWriteReview(Action):
class SimpleReviewer(Role):
def __init__(
self,
name: str = "Charlie",
profile: str = "SimpleReviewer",
**kwargs,
):
super().__init__(name, profile, **kwargs)
name: str = "Charlie"
profile: str = "SimpleReviewer"
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([SimpleWriteReview])
self._watch([SimpleWriteTest])
@ -147,7 +136,7 @@ async def main(
)
team.invest(investment=investment)
team.start_project(idea)
team.run_project(idea)
await team.run(n_round=n_round)

View file

@ -10,7 +10,7 @@
import asyncio
from pathlib import Path
from metagpt.roles.invoice_ocr_assistant import InvoiceOCRAssistant
from metagpt.roles.invoice_ocr_assistant import InvoiceOCRAssistant, InvoicePath
from metagpt.schema import Message
@ -26,7 +26,7 @@ async def main():
for path in absolute_file_paths:
role = InvoiceOCRAssistant()
await role.run(Message(content="Invoicing date", instruct_content={"file_path": path}))
await role.run(Message(content="Invoicing date", instruct_content=InvoicePath(file_path=path)))
if __name__ == "__main__":

View file

@ -9,9 +9,9 @@ async def main():
# Serper API
# await Searcher(engine=SearchEngineType.SERPER_GOOGLE).run(question)
# SerpAPI
# await Searcher(engine=SearchEngineType.SERPAPI_GOOGLE).run(question)
await Searcher(engine=SearchEngineType.SERPAPI_GOOGLE).run(question)
# Google API
await Searcher(engine=SearchEngineType.DIRECT_GOOGLE).run(question)
# await Searcher(engine=SearchEngineType.DIRECT_GOOGLE).run(question)
if __name__ == "__main__":

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,10 @@ 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)
language: str = "ch"
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 +175,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: str = "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: dict = dict()
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,14 +7,35 @@
@File : invoice_ocr_assistant.py
"""
import json
from pathlib import Path
from typing import Optional
import pandas as pd
from pydantic import BaseModel
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
class InvoicePath(BaseModel):
file_path: Path = ""
class OCRResults(BaseModel):
ocr_result: str = "[]"
class InvoiceData(BaseModel):
invoice_data: list[dict] = []
class ReplyData(BaseModel):
content: str = ""
class InvoiceOCRAssistant(Role):
"""Invoice OCR assistant, support OCR text recognition of invoice PDF, png, jpg, and zip files,
generate a table for the payee, city, total amount, and invoicing date of the invoice,
@ -28,21 +49,19 @@ 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)
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._init_actions([InvoiceOCR])
self.language = language
self.filename = ""
self.origin_query = ""
self.orc_data = None
self._set_react_mode(react_mode="by_order")
self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)
async def _act(self) -> Message:
"""Perform an action as determined by the role.
@ -54,7 +73,8 @@ class InvoiceOCRAssistant(Role):
todo = self._rc.todo
if isinstance(todo, InvoiceOCR):
self.origin_query = msg.content
file_path = msg.instruct_content.get("file_path")
invoice_path: InvoicePath = msg.instruct_content
file_path = invoice_path.file_path
self.filename = file_path.name
if not file_path:
raise Exception("Invoice file not uploaded")
@ -69,17 +89,23 @@ class InvoiceOCRAssistant(Role):
self._rc.todo = None
content = INVOICE_OCR_SUCCESS
resp = OCRResults(ocr_result=json.dumps(resp))
msg = Message(content=content, instruct_content=resp)
self._rc.memory.add(msg)
return await super().react()
elif isinstance(todo, GenerateTable):
ocr_results = msg.instruct_content
resp = await todo.run(ocr_results, self.filename)
ocr_results: OCRResults = msg.instruct_content
resp = await todo.run(json.loads(ocr_results.ocr_result), self.filename)
# Convert list to Markdown format string
df = pd.DataFrame(resp)
markdown_table = df.to_markdown(index=False)
content = f"{markdown_table}\n\n\n"
resp = InvoiceData(invoice_data=resp)
else:
resp = await todo.run(self.origin_query, self.orc_data)
content = resp
resp = ReplyData(content=resp)
msg = Message(content=content, instruct_content=resp)
self._rc.memory.add(msg)

View file

@ -4,7 +4,6 @@
the `cause_by` value in the `Message` to a string to support the new message distribution feature.
"""
import asyncio
from pydantic import BaseModel
@ -13,7 +12,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 +24,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 _act(self) -> Message:
logger.info(f"{self._setting}: to do {self._rc.todo}({self._rc.todo.name})")
@ -107,7 +105,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

@ -208,8 +208,7 @@ class Role(BaseModel):
if "actions" in kwargs:
self._init_actions(kwargs["actions"])
if "watch" in kwargs:
self._watch(kwargs["watch"])
self._watch(kwargs.get("watch") or [UserRequirement])
def __init_subclass__(cls, **kwargs: Any) -> None:
super().__init_subclass__(**kwargs)
@ -482,6 +481,7 @@ class Role(BaseModel):
async def _act_by_order(self) -> Message:
"""switch action each time by order defined in _init_actions, i.e. _act (Action1) -> _act (Action2) -> ..."""
start_idx = self._rc.state if self._rc.state >= 0 else 0 # action to run from recovered state
rsp = Message(content="No actions taken yet") # return default message if _actions=[]
for i in range(start_idx, len(self._states)):
self._set_state(i)
rsp = await self._act()

View file

@ -7,13 +7,19 @@
@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 import Kernel
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
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 semantic_kernel.planning.basic_planner import BasicPlanner, Plan
from metagpt.actions import UserRequirement
from metagpt.actions.execute_task import ExecuteTask
from metagpt.llm import LLM
from metagpt.logs import logger
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 +36,33 @@ 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 = ""
plan: Plan = None
planner_cls: BasicPlanner = BasicPlanner
planner: BasicPlanner = Field(default_factory=BasicPlanner)
llm: BaseGPTAPI = Field(default_factory=LLM)
kernel: Kernel = Field(default_factory=Kernel)
import_semantic_skill_from_directory: str = ""
import_skill: dict[str, SKFunctionBase] = dict()
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.

View file

@ -21,12 +21,14 @@ def make_sk_kernel():
if CONFIG.openai_api_type == "azure":
kernel.add_chat_service(
"chat_completion",
AzureChatCompletion(CONFIG.deployment_name, CONFIG.openai_base_url, CONFIG.openai_api_key),
AzureChatCompletion(
deployment_name=CONFIG.deployment_name, endpoint=CONFIG.openai_base_url, api_key=CONFIG.openai_api_key
),
)
else:
kernel.add_chat_service(
"chat_completion",
OpenAIChatCompletion(CONFIG.openai_api_model, CONFIG.openai_api_key),
OpenAIChatCompletion(model_id=CONFIG.openai_api_model, api_key=CONFIG.openai_api_key),
)
return kernel

View file

@ -7,12 +7,13 @@
@File : test_invoice_ocr_assistant.py
"""
import json
from pathlib import Path
import pandas as pd
import pytest
from metagpt.roles.invoice_ocr_assistant import InvoiceOCRAssistant
from metagpt.roles.invoice_ocr_assistant import InvoiceOCRAssistant, InvoicePath
from metagpt.schema import Message
@ -55,8 +56,8 @@ async def test_invoice_ocr_assistant(
):
invoice_path = Path.cwd() / invoice_path
role = InvoiceOCRAssistant()
await role.run(Message(content=query, instruct_content={"file_path": invoice_path}))
await role.run(Message(content=query, instruct_content=InvoicePath(file_path=invoice_path)))
invoice_table_path = Path.cwd() / invoice_table_path
df = pd.read_excel(invoice_table_path)
dict_result = df.to_dict(orient="records")
assert dict_result == expected_result
assert json.dumps(dict_result) == json.dumps(expected_result)