mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-05-21 14:05:17 +02:00
feat: + education industry
This commit is contained in:
parent
8cc8b80e49
commit
9d1a261bf6
9 changed files with 498 additions and 17 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -163,3 +163,6 @@ workspace/*
|
|||
*.mmd
|
||||
tmp
|
||||
output.wav
|
||||
|
||||
# output folder
|
||||
output
|
||||
|
|
|
|||
134
metagpt/actions/write_teaching_plan.py
Normal file
134
metagpt/actions/write_teaching_plan.py
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2023/5/11 14:43
|
||||
@Author : mashenquan
|
||||
@File : write_teaching_plan.py
|
||||
"""
|
||||
from langchain.llms.base import LLM
|
||||
from metagpt.logs import logger
|
||||
from metagpt.actions import Action
|
||||
from metagpt.schema import Message
|
||||
|
||||
|
||||
class TeachingPlanRequirement(Action):
|
||||
"""Teaching Plan Requirement without any implementation details"""
|
||||
|
||||
async def run(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class WriteTeachingPlanPart(Action):
|
||||
"""Write Teaching Plan Part"""
|
||||
|
||||
def __init__(self, name: str = '', context=None, llm: LLM = None, topic="", language="Chinese"):
|
||||
"""
|
||||
|
||||
Args:
|
||||
name: action name
|
||||
context: context
|
||||
llm: object of :class:`LLM`
|
||||
topic: topic part of teaching plan
|
||||
"""
|
||||
super().__init__(name, context, llm)
|
||||
self.topic = topic
|
||||
self.language = language
|
||||
self.rsp = None
|
||||
|
||||
async def run(self, *args, **kwargs):
|
||||
if len(args) < 1 or len(args[0]) < 1 or not isinstance(args[0][0], Message):
|
||||
raise ValueError("Invalid args, a tuple of List[Message] is expected")
|
||||
|
||||
statements = self.TOPIC_STATEMENTS.get(self.topic, [])
|
||||
formatter = self.PROMPT_TITLE_TEMPLATE if self.topic == self.COURSE_TITLE else self.PROMPT_TEMPLATE
|
||||
prompt = formatter.format(formation=self.FORMATION,
|
||||
role=self.prefix,
|
||||
statements="\n".join(statements),
|
||||
lesson=args[0][0].content,
|
||||
topic=self.topic,
|
||||
language=self.language)
|
||||
|
||||
logger.debug(prompt)
|
||||
rsp = await self._aask(prompt=prompt)
|
||||
logger.debug(rsp)
|
||||
self._set_result(rsp)
|
||||
return self.rsp
|
||||
|
||||
def _set_result(self, rsp):
|
||||
if self.DATA_BEGIN_TAG in rsp:
|
||||
ix = rsp.index(self.DATA_BEGIN_TAG)
|
||||
rsp = rsp[ix + len(self.DATA_BEGIN_TAG):]
|
||||
if self.DATA_END_TAG in rsp:
|
||||
ix = rsp.index(self.DATA_END_TAG)
|
||||
rsp = rsp[0:ix]
|
||||
self.rsp = rsp.strip()
|
||||
if self.topic != self.COURSE_TITLE:
|
||||
return
|
||||
if '#' not in self.rsp or self.rsp.index('#') != 0:
|
||||
self.rsp = "# " + self.rsp
|
||||
|
||||
def __str__(self):
|
||||
"""str()时返回`topic`"""
|
||||
return self.topic
|
||||
|
||||
def __repr__(self):
|
||||
"""调试时返回`topic`"""
|
||||
return self.topic
|
||||
|
||||
FORMATION = """
|
||||
"\tCapacity and role" defines the role you are currently playing;
|
||||
"\t[LESSON_BEGIN]" and "[LESSON_END]" tags enclose the content of textbook;
|
||||
"\tStatement" defines the work detail you need to complete at this stage;
|
||||
"\tAnswer options" defines the format requirements for your responses;
|
||||
"\tConstraint" defines the conditions that your responses must comply with.
|
||||
"""
|
||||
COURSE_TITLE = "Title"
|
||||
TOPICS = [COURSE_TITLE, "Teaching Hours", "Teaching Objectives", "Teaching Content",
|
||||
"Teaching Methods and Strategies", "Learning Activities",
|
||||
"Teaching Time Allocation", "Assessment and Feedback", "Teaching Summary and Improvement"]
|
||||
|
||||
TOPIC_STATEMENTS = {
|
||||
COURSE_TITLE: ["Statement: Find and return the title of the lesson only in markdown first-level header format, "
|
||||
"without anything else."],
|
||||
"Teaching Content": [
|
||||
"Statement: \"Teaching Content\" must include vocabulary, analysis, and examples of various grammar "
|
||||
"structures that appear in the textbook, as well as the listening materials and key points.",
|
||||
"Statement: \"Teaching Content\" must include more examples."],
|
||||
"Teaching Time Allocation": [
|
||||
"Statement: \"Teaching Time Allocation\" must include how much time is allocated to each "
|
||||
"part of the textbook content."],
|
||||
"Teaching Methods and Strategies": [
|
||||
"Statement: \"Teaching Methods and Strategies\" must include teaching focus, difficulties, materials, "
|
||||
"procedures, in detail."
|
||||
]
|
||||
}
|
||||
|
||||
# Teaching plan title
|
||||
PROMPT_TITLE_TEMPLATE = """
|
||||
Do not refer to the context of the previous conversation records, start the conversation anew.\n\n
|
||||
Formation: {formation}\n\n
|
||||
{statements}\n
|
||||
Constraint: Writing in {language}.\n
|
||||
Answer options: Encloses the lesson title with "[TEACHING_PLAN_BEGIN]" and "[TEACHING_PLAN_END]" tags.\n
|
||||
[LESSON_BEGIN]\n
|
||||
{lesson}\n
|
||||
[LESSON_END]
|
||||
"""
|
||||
|
||||
# Teaching plan parts:
|
||||
PROMPT_TEMPLATE = """
|
||||
Do not refer to the context of the previous conversation records, start the conversation anew.\n\n
|
||||
Formation: {formation}\n\n
|
||||
Capacity and role: {role}\n
|
||||
Statement: Write the "{topic}" part of teaching plan, WITHOUT ANY content unrelated to "{topic}"!!\n
|
||||
{statements}\n
|
||||
Answer options: Enclose the teaching plan content with "[TEACHING_PLAN_BEGIN]" and "[TEACHING_PLAN_END]" tags.\n
|
||||
Answer options: Using proper markdown format from second-level header format.\n
|
||||
Constraint: Writing in {language}.\n
|
||||
[LESSON_BEGIN]\n
|
||||
{lesson}\n
|
||||
[LESSON_END]
|
||||
"""
|
||||
|
||||
DATA_BEGIN_TAG = "[TEACHING_PLAN_BEGIN]"
|
||||
DATA_END_TAG = "[TEACHING_PLAN_END]"
|
||||
|
|
@ -4,12 +4,13 @@
|
|||
@Time : 2023/5/5 23:08
|
||||
@Author : alexanderwu
|
||||
@File : openai.py
|
||||
@Modified By: mashenquan, 2023-07-27, + try except.
|
||||
"""
|
||||
import asyncio
|
||||
import time
|
||||
from functools import wraps
|
||||
from typing import NamedTuple
|
||||
|
||||
import traceback
|
||||
import openai
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
|
|
@ -30,7 +31,9 @@ def retry(max_retries):
|
|||
for i in range(max_retries):
|
||||
try:
|
||||
return await f(*args, **kwargs)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
error_str = traceback.format_exc()
|
||||
logger.warning(f"Exception occurred: {str(e)}, stack:{error_str}. Retrying...")
|
||||
if i == max_retries - 1:
|
||||
raise
|
||||
await asyncio.sleep(2 ** i)
|
||||
|
|
@ -148,10 +151,15 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter):
|
|||
self.rpm = int(config.get("RPM", 10))
|
||||
|
||||
async def _achat_completion_stream(self, messages: list[dict]) -> str:
|
||||
response = await openai.ChatCompletion.acreate(
|
||||
**self._cons_kwargs(messages),
|
||||
stream=True
|
||||
)
|
||||
try:
|
||||
response = await openai.ChatCompletion.acreate(
|
||||
**self._cons_kwargs(messages),
|
||||
stream=True
|
||||
)
|
||||
except Exception as e:
|
||||
error_str = traceback.format_exc()
|
||||
logger.error(f"Exception:{e}, stack:{error_str}")
|
||||
raise e
|
||||
|
||||
# create variables to collect the stream of chunks
|
||||
collected_chunks = []
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
@Time : 2023/5/11 14:42
|
||||
@Author : alexanderwu
|
||||
@File : role.py
|
||||
@Modified By: mashenquan, 2023-07-27, :class:`Role` + properties.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import traceback
|
||||
from typing import Iterable, Type
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
|
@ -92,13 +94,22 @@ class RoleContext(BaseModel):
|
|||
class Role:
|
||||
"""角色/代理"""
|
||||
|
||||
def __init__(self, name="", profile="", goal="", constraints="", desc=""):
|
||||
def __init__(self, name="", profile="", goal="", constraints="", desc="", *args, **kwargs):
|
||||
# Enable parameter configurability
|
||||
name = Role.format_value(name, kwargs)
|
||||
profile = Role.format_value(profile, kwargs)
|
||||
goal = Role.format_value(goal, kwargs)
|
||||
constraints = Role.format_value(constraints, kwargs)
|
||||
desc = Role.format_value(desc, kwargs)
|
||||
|
||||
# Initialize
|
||||
self._llm = LLM()
|
||||
self._setting = RoleSetting(name=name, profile=profile, goal=goal, constraints=constraints, desc=desc)
|
||||
self._states = []
|
||||
self._actions = []
|
||||
self._role_id = str(self._setting)
|
||||
self._rc = RoleContext()
|
||||
self._options = Role.supply_options(kwargs)
|
||||
|
||||
def _reset(self):
|
||||
self._states = []
|
||||
|
|
@ -136,6 +147,26 @@ class Role:
|
|||
"""获取角色描述(职位)"""
|
||||
return self._setting.profile
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return role `name`, read only"""
|
||||
return self._setting.name
|
||||
|
||||
@property
|
||||
def desc(self):
|
||||
"""Return role `desc`, read only"""
|
||||
return self._setting.desc
|
||||
|
||||
@property
|
||||
def goal(self):
|
||||
"""Return role `goal`, read only"""
|
||||
return self._setting.goal
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
"""Return role `constraints`, read only"""
|
||||
return self._setting.constraints
|
||||
|
||||
def _get_prefix(self):
|
||||
"""获取角色前缀"""
|
||||
if self._setting.desc:
|
||||
|
|
@ -164,7 +195,8 @@ class Role:
|
|||
# history=self.history)
|
||||
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
response = await self._rc.todo.run(self._rc.important_memory)
|
||||
requirement = self._rc.important_memory
|
||||
response = await self._rc.todo.run(requirement)
|
||||
# logger.info(response)
|
||||
if isinstance(response, ActionOutput):
|
||||
msg = Message(content=response.content, instruct_content=response.instruct_content,
|
||||
|
|
@ -238,3 +270,33 @@ class Role:
|
|||
# 将回复发布到环境,等待下一个订阅者处理
|
||||
self._publish_message(rsp)
|
||||
return rsp
|
||||
|
||||
@staticmethod
|
||||
def supply_options(options):
|
||||
"""Supply missing options"""
|
||||
ret = Role.__DEFAULT_OPTIONS__.copy()
|
||||
if not options:
|
||||
return ret
|
||||
ret.update(options)
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def format_value(value, options):
|
||||
"""Fill parameters inside `value` with `options`.
|
||||
"""
|
||||
if "{" not in value:
|
||||
return value
|
||||
|
||||
options = Role.supply_options(options)
|
||||
try:
|
||||
return value.format(**options)
|
||||
except KeyError as e:
|
||||
logger.warning(f"Parameter is missing:{e}")
|
||||
for k, v in options.items():
|
||||
value = value.replace("{" + f"{k}" + "}", v)
|
||||
return value
|
||||
|
||||
__DEFAULT_OPTIONS__ = {
|
||||
"teaching_language": "English",
|
||||
"language": "Chinese"
|
||||
}
|
||||
96
metagpt/roles/teacher.py
Normal file
96
metagpt/roles/teacher.py
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2023/5/23 17:25
|
||||
@Author : mashenquan
|
||||
@File : teacher.py
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
import aiofiles
|
||||
|
||||
from metagpt.actions.write_teaching_plan import WriteTeachingPlanPart, TeachingPlanRequirement
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import Message
|
||||
from metagpt.logs import logger
|
||||
import re
|
||||
|
||||
|
||||
class Teacher(Role):
|
||||
"""Support configurable teacher roles,
|
||||
with native and teaching languages being replaceable through configurations."""
|
||||
def __init__(self, name='Lily', profile='{teaching_language} Teacher',
|
||||
goal='writing a {language} teaching plan part by part',
|
||||
constraints='writing in {language}', desc="", *args, **kwargs):
|
||||
super().__init__(name=name, profile=profile, goal=goal, constraints=constraints, desc=desc, *args, **kwargs)
|
||||
actions = []
|
||||
for topic in WriteTeachingPlanPart.TOPICS:
|
||||
act = WriteTeachingPlanPart(topic=topic, llm=self._llm)
|
||||
actions.append(act)
|
||||
self._init_actions(actions)
|
||||
self._watch({TeachingPlanRequirement})
|
||||
|
||||
async def _think(self) -> None:
|
||||
"""Everything will be done part by part."""
|
||||
if self._rc.todo is None:
|
||||
self._set_state(0)
|
||||
return
|
||||
|
||||
if self._rc.state + 1 < len(self._states):
|
||||
self._set_state(self._rc.state + 1)
|
||||
else:
|
||||
self._rc.todo = None
|
||||
|
||||
async def _react(self) -> Message:
|
||||
ret = Message(content="")
|
||||
while True:
|
||||
await self._think()
|
||||
if self._rc.todo is None:
|
||||
break
|
||||
logger.debug(f"{self._setting}: {self._rc.state=}, will do {self._rc.todo}")
|
||||
msg = await self._act()
|
||||
if ret.content != '':
|
||||
ret.content += "\n\n\n"
|
||||
ret.content += msg.content
|
||||
logger.info(ret.content)
|
||||
await self.save(ret.content)
|
||||
return ret
|
||||
|
||||
async def save(self, content):
|
||||
"""Save teaching plan"""
|
||||
filename = Teacher.new_file_name(self.course_title)
|
||||
pathname = Path(__file__).resolve().parent.parent.parent / "output"
|
||||
pathname.mkdir(exist_ok=True)
|
||||
pathname = pathname / filename
|
||||
try:
|
||||
async with aiofiles.open(str(pathname), mode='w', encoding='utf-8') as writer:
|
||||
await writer.write(content)
|
||||
except Exception as e:
|
||||
logger.error(f'Save failed:{e}')
|
||||
logger.info(f"Save to:{pathname}")
|
||||
|
||||
@staticmethod
|
||||
def new_file_name(lesson_title, ext=".md"):
|
||||
"""Create a related file name based on `lesson_title` and `ext`."""
|
||||
# 定义需要替换的特殊字符
|
||||
illegal_chars = r'[#@$%!*&\\/:*?"<>|\n\t \']'
|
||||
# 将特殊字符替换为下划线
|
||||
filename = re.sub(illegal_chars, '_', lesson_title) + ext
|
||||
return re.sub(r'_+', '_', filename)
|
||||
|
||||
@property
|
||||
def course_title(self):
|
||||
"""Return course title of teaching plan"""
|
||||
default_title = "teaching_plan"
|
||||
for act in self._actions:
|
||||
if act.topic != WriteTeachingPlanPart.COURSE_TITLE:
|
||||
continue
|
||||
if act.rsp is None:
|
||||
return default_title
|
||||
title = act.rsp.lstrip("# \n")
|
||||
if '\n' in title:
|
||||
ix = title.index('\n')
|
||||
title = title[0: ix]
|
||||
return title
|
||||
|
||||
return default_title
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
@Time : 2023/5/12 00:30
|
||||
@Author : alexanderwu
|
||||
@File : software_company.py
|
||||
@Modified By: mashenquan, 2023-07-27, Add `role` & `cause_by` parameters to `start_project()`.
|
||||
"""
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
|
@ -42,10 +43,10 @@ class SoftwareCompany(BaseModel):
|
|||
if CONFIG.total_cost > CONFIG.max_budget:
|
||||
raise NoMoneyException(CONFIG.total_cost, f'Insufficient funds: {CONFIG.max_budget}')
|
||||
|
||||
def start_project(self, idea):
|
||||
def start_project(self, idea, role="BOSS", cause_by=BossRequirement):
|
||||
"""Start a project from publishing boss requirement."""
|
||||
self.idea = idea
|
||||
self.environment.publish_message(Message(role="BOSS", content=idea, cause_by=BossRequirement))
|
||||
self.environment.publish_message(Message(role=role, content=idea, cause_by=cause_by))
|
||||
|
||||
def _save(self):
|
||||
logger.info(self.json())
|
||||
|
|
|
|||
|
|
@ -35,3 +35,4 @@ tqdm==4.64.0
|
|||
anthropic==0.3.6
|
||||
typing-inspect==0.8.0
|
||||
typing_extensions==4.5.0
|
||||
aiofiles
|
||||
96
startup.py
96
startup.py
|
|
@ -1,15 +1,23 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Modified By: mashenquan, 2023-07-27, +industry concept
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from pathlib import Path
|
||||
import aiofiles
|
||||
import fire
|
||||
|
||||
from metagpt.logs import logger
|
||||
from metagpt.actions.write_teaching_plan import TeachingPlanRequirement
|
||||
from metagpt.roles import Architect, Engineer, ProductManager, ProjectManager
|
||||
from metagpt.roles.teacher import Teacher
|
||||
from metagpt.software_company import SoftwareCompany
|
||||
|
||||
|
||||
async def startup(idea: str, investment: float = 3.0, n_round: int = 5, code_review: bool = False):
|
||||
"""Run a startup. Be a boss."""
|
||||
async def software_startup(investment: float = 3.0, n_round: int = 5, code_review: bool = False, *args, **kwargs):
|
||||
"""Run a startup. Be a boss in software industry."""
|
||||
idea = kwargs['idea'] # Your innovative idea, such as "Creating a snake game."
|
||||
company = SoftwareCompany()
|
||||
company.hire([ProductManager(),
|
||||
Architect(),
|
||||
|
|
@ -20,16 +28,90 @@ async def startup(idea: str, investment: float = 3.0, n_round: int = 5, code_rev
|
|||
await company.run(n_round=n_round)
|
||||
|
||||
|
||||
def main(idea: str, investment: float = 3.0, n_round: int = 5, code_review: bool = False):
|
||||
async def education_startup(investment: float = 3.0, n_round: int = 5, code_review: bool = False, *args, **kwargs):
|
||||
"""Run a startup. Be a teacher in education industry."""
|
||||
|
||||
demo_lesson = """
|
||||
UNIT 1 Making New Friends
|
||||
TOPIC 1 Welcome to China!
|
||||
Section A
|
||||
|
||||
1a Listen and number the following names.
|
||||
Jane Mari Kangkang Michael
|
||||
Look, listen and understand. Then practice the conversation.
|
||||
Work in groups. Introduce yourself using
|
||||
I ’m ... Then practice 1a
|
||||
with your own hometown or the following places.
|
||||
|
||||
1b Listen and number the following names
|
||||
Jane Michael Maria Kangkang
|
||||
1c Work in groups. Introduce yourself using I ’m ... Then practice 1a with your own hometown or the following places.
|
||||
China the USA the UK Hong Kong Beijing
|
||||
|
||||
2a Look, listen and understand. Then practice the conversation
|
||||
Hello!
|
||||
Hello!
|
||||
Hello!
|
||||
Hello! Are you Maria?
|
||||
No, I’m not. I’m Jane.
|
||||
Oh, nice to meet you, Jane
|
||||
Nice to meet you, too.
|
||||
Hi, Maria!
|
||||
Hi, Kangkang!
|
||||
Welcome to China!
|
||||
Thanks.
|
||||
|
||||
2b Work in groups. Make up a conversation with your own name and the
|
||||
following structures.
|
||||
A: Hello! / Good morning! / Hi! I’m ... Are you ... ?
|
||||
B: ...
|
||||
|
||||
3a Listen, say and trace
|
||||
Aa Bb Cc Dd Ee Ff Gg
|
||||
|
||||
3b Listen and number the following letters. Then circle the letters withthe same sound as Bb.
|
||||
Aa Bb Cc Dd Ee Ff Gg
|
||||
|
||||
3c Match the big letters with the small ones. Then write them on the lines.
|
||||
"""
|
||||
|
||||
lesson = ""
|
||||
lesson_file = kwargs.get('lesson_file')
|
||||
if lesson_file is not None and Path(lesson_file).exists():
|
||||
async with aiofiles.open(lesson_file, mode="r", encoding="utf-8") as reader:
|
||||
lesson = await reader.read()
|
||||
logger.info(f"Course content: {lesson}")
|
||||
if not lesson:
|
||||
logger.info("No course content provided, using the demo course.")
|
||||
lesson = demo_lesson
|
||||
|
||||
company = SoftwareCompany()
|
||||
company.hire([Teacher(*args, **kwargs)])
|
||||
company.invest(investment)
|
||||
company.start_project(lesson, role="Teacher", cause_by=TeachingPlanRequirement)
|
||||
await company.run(n_round=1)
|
||||
|
||||
|
||||
def main(investment: float = 3.0, n_round: int = 5, code_review: bool = False, *args, **kwargs):
|
||||
"""
|
||||
We are a software startup comprised of AI. By investing in us, you are empowering a future filled with limitless possibilities.
|
||||
:param idea: Your innovative idea, such as "Creating a snake game."
|
||||
:param investment: As an investor, you have the opportunity to contribute a certain dollar amount to this AI company.
|
||||
:param n_round:
|
||||
:param code_review: Whether to use code review.
|
||||
:param args: Parameters passed in format: `python your_script.py arg1 arg2 arg3`
|
||||
:param kwargs: Parameters passed in format: `python your_script.py a--param1=value1 --param2=value2`
|
||||
:return:
|
||||
"""
|
||||
asyncio.run(startup(idea, investment, n_round, code_review))
|
||||
industry = kwargs.get("industry", "software")
|
||||
industries = {
|
||||
"software": software_startup,
|
||||
"education": education_startup,
|
||||
}
|
||||
startup = industries.get(industry)
|
||||
if startup is None:
|
||||
print(f"Available industries:{list(industries.keys())}")
|
||||
return
|
||||
asyncio.run(startup(investment, n_round, code_review, *args, **kwargs))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
94
tests/metagpt/roles/test_teacher.py
Normal file
94
tests/metagpt/roles/test_teacher.py
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2023/5/23 17:25
|
||||
@Author : mashenquan
|
||||
@File : teacher.py
|
||||
"""
|
||||
|
||||
from typing import Dict, Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
from metagpt.roles.teacher import Teacher
|
||||
|
||||
|
||||
def test_init():
|
||||
class Inputs(BaseModel):
|
||||
name: str
|
||||
profile: str
|
||||
goal: str
|
||||
constraints: str
|
||||
desc: str
|
||||
options: Optional[Dict] = None
|
||||
expect_name: str
|
||||
expect_profile: str
|
||||
expect_goal: str
|
||||
expect_constraints: str
|
||||
expect_desc: str
|
||||
|
||||
inputs = [
|
||||
{
|
||||
"name": "Lily{language}",
|
||||
"expect_name": "LilyCN",
|
||||
"profile": "X {teaching_language}",
|
||||
"expect_profile": "X EN",
|
||||
"goal": "Do {something_big}, {language}",
|
||||
"expect_goal": "Do sleep, CN",
|
||||
"constraints": "Do in {key1}, {language}",
|
||||
"expect_constraints": "Do in HaHa, CN",
|
||||
"options": {"language": "CN", "key1": "HaHa", "something_big": "sleep", "teaching_language": "EN"},
|
||||
"desc": "aaa{language}",
|
||||
"expect_desc": "aaaCN"
|
||||
},
|
||||
{
|
||||
"name": "Lily{language}",
|
||||
"expect_name": "LilyChinese",
|
||||
"profile": "X {teaching_language}",
|
||||
"expect_profile": "X English",
|
||||
"goal": "Do {something_big}, {language}",
|
||||
"expect_goal": "Do {something_big}, Chinese",
|
||||
"constraints": "Do in {key1}, {language}",
|
||||
"expect_constraints": "Do in {key1}, Chinese",
|
||||
"desc": "aaa{language}",
|
||||
"expect_desc": "aaaChinese"
|
||||
},
|
||||
]
|
||||
|
||||
for i in inputs:
|
||||
seed = Inputs(**i)
|
||||
teacher = Teacher(name=seed.name, profile=seed.profile, goal=seed.goal, constraints=seed.constraints,
|
||||
desc=seed.desc, options=seed.options)
|
||||
assert teacher.name == seed.expect_name
|
||||
assert teacher.desc == seed.expect_desc
|
||||
assert teacher.profile == seed.expect_profile
|
||||
assert teacher.goal == seed.expect_goal
|
||||
assert teacher.constraints == seed.expect_constraints
|
||||
assert teacher.course_title == "teaching_plan"
|
||||
|
||||
|
||||
def test_new_file_name():
|
||||
class Inputs(BaseModel):
|
||||
lesson_title: str
|
||||
ext: str
|
||||
expect: str
|
||||
|
||||
inputs = [
|
||||
{
|
||||
"lesson_title": "# @344\n12",
|
||||
"ext": ".md",
|
||||
"expect": "_344_12.md"
|
||||
},
|
||||
{
|
||||
"lesson_title": "1#@$%!*&\\/:*?\"<>|\n\t \'1",
|
||||
"ext": ".cc",
|
||||
"expect": "1_1.cc"
|
||||
}
|
||||
]
|
||||
for i in inputs:
|
||||
seed = Inputs(**i)
|
||||
result = Teacher.new_file_name(seed.lesson_title, seed.ext)
|
||||
assert result == seed.expect
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_init()
|
||||
Loading…
Add table
Add a link
Reference in a new issue