feat: merge teacher

This commit is contained in:
莘权 马 2023-08-22 22:34:39 +08:00
commit 01c487fb6a
32 changed files with 1578 additions and 38 deletions

View file

@ -0,0 +1,51 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time : 2023/8/8
@Author : mashenquan
@File : test_meta_action.py
"""
from typing import Dict
from pydantic import BaseModel
from metagpt.actions.meta_action import MetaAction
from metagpt.roles.uml_meta_role_options import MetaActionOptions
def test_meta_action_create():
class Inputs(BaseModel):
options: Dict
kwargs: Dict
expect_class_name: str
expect_prompt: str
inputs = [
{
"options": {
"topic": "TOPIC_A",
"name": "A",
"language": "XX",
"template_ix": 0,
"statements": ["Statement A", "Statement B"],
"template": "{statements}",
"rsp_begin_tag": "",
"rsp_end_tag": ""
},
"kwargs": {},
"expect_class_name": "TOPIC_A",
"expect_prompt": "\n".join(["Statement A", "Statement B"]),
}
]
for i in inputs:
seed = Inputs(**i)
opt = MetaActionOptions(**seed.options)
act = MetaAction(opt, **seed.kwargs)
assert seed.expect_prompt == act.prompt
t = MetaAction.get_action_type(seed.expect_class_name)
assert t.__name__ == seed.expect_class_name
if __name__ == '__main__':
test_meta_action_create()

View file

@ -4,7 +4,7 @@
#
from tests.metagpt.roles.ui_role import UIDesign
llm_resp= '''
llm_resp = '''
# UI Design Description
```The user interface for the snake game will be designed in a way that is simple, clean, and intuitive. The main elements of the game such as the game grid, snake, food, score, and game over message will be clearly defined and easy to understand. The game grid will be centered on the screen with the score displayed at the top. The game controls will be intuitive and easy to use. The design will be modern and minimalist with a pleasing color scheme.```
@ -100,6 +100,7 @@ body {
font-size: 3em;
'''
def test_ui_design_parse_css():
ui_design_work = UIDesign(name="UI design action")
@ -161,7 +162,7 @@ def test_ui_design_parse_css():
transform: translate(-50%, -50%);
font-size: 3em;
'''
assert ui_design_work.parse_css_code(context=llm_resp)==css
assert ui_design_work.parse_css_code(context=llm_resp) == css
def test_ui_design_parse_html():
@ -185,7 +186,4 @@ def test_ui_design_parse_html():
</body>
</html>
'''
assert ui_design_work.parse_css_code(context=llm_resp)==html
assert ui_design_work.parse_css_code(context=llm_resp) == html

View file

@ -4,6 +4,7 @@
@Time : 2023/5/11 17:45
@Author : alexanderwu
@File : test_write_code.py
@Modified By: mashenquan, 2023-8-1, fix-bug: `filename` of `write_code.run()` is missing.
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
"""
import pytest
@ -22,8 +23,7 @@ async def test_write_code():
cost_manager = CostManager(**conf.runtime_options)
llm = LLM(options=conf.runtime_options, cost_manager=cost_manager)
write_code = WriteCode(options=conf.runtime_options, name="write_code", llm=llm)
code = await write_code.run(api_design, "filename")
code = await write_code.run(context=api_design, filename="test")
logger.info(code)
# 我们不能精确地预测生成的代码,但我们可以检查某些关键字

View file

@ -0,0 +1,67 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time : 2023/7/28 17:25
@Author : mashenquan
@File : test_write_teaching_plan.py
"""
import asyncio
from typing import Optional
from pydantic import BaseModel
from langchain.llms.base import LLM
from metagpt.actions.write_teaching_plan import WriteTeachingPlanPart
from metagpt.config import Config
from metagpt.schema import Message
class MockWriteTeachingPlanPart(WriteTeachingPlanPart):
def __init__(self, options, name: str = '', context=None, llm: LLM = None, topic="", language="Chinese"):
super().__init__(options, name, context, llm, topic, language)
async def _aask(self, prompt: str, system_msgs: Optional[list[str]] = None) -> str:
return f"{WriteTeachingPlanPart.DATA_BEGIN_TAG}\nprompt\n{WriteTeachingPlanPart.DATA_END_TAG}"
async def mock_write_teaching_plan_part():
class Inputs(BaseModel):
input: str
name: str
topic: str
language: str
inputs = [
{
"input": "AABBCC",
"name": "A",
"topic": WriteTeachingPlanPart.COURSE_TITLE,
"language": "C"
},
{
"input": "DDEEFFF",
"name": "A1",
"topic": "B1",
"language": "C1"
}
]
for i in inputs:
seed = Inputs(**i)
options = Config().runtime_options
act = MockWriteTeachingPlanPart(options=options, name=seed.name, topic=seed.topic, language=seed.language)
await act.run([Message(content="")])
assert act.topic == seed.topic
assert str(act) == seed.topic
assert act.name == seed.name
assert act.rsp == "# prompt" if seed.topic == WriteTeachingPlanPart.COURSE_TITLE else "prompt"
def test_suite():
loop = asyncio.get_event_loop()
task = loop.create_task(mock_write_teaching_plan_part())
loop.run_until_complete(task)
if __name__ == '__main__':
test_suite()

View file

@ -0,0 +1,94 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time : 2023/8/8
@Author : mashenquan
@File : test_fork_meta_role.py
"""
from typing import Dict
from pydantic import BaseModel
from metagpt.config import Config
from metagpt.provider.openai_api import CostManager
from metagpt.roles.fork_meta_role import ForkMetaRole
def test_creat_role():
class Inputs(BaseModel):
role: Dict
action_count: int
inputs = [
{
"role": {
"role_type": "fork",
"name": "Lily",
"profile": "{teaching_language} Teacher",
"goal": "writing a {language} teaching plan part by part",
"constraints": "writing in {language}",
"role": "You are a {teaching_language} Teacher, named Lily, your goal is writing a {"
"teaching_language} teaching plan part by part, and the constraint is writing in {language}.",
"desc": "",
"output_filename": "teaching_plan_demo.md",
"requirement": ["TeachingPlanRequirement"],
"templates": [
"Do not refer to the context of the previous conversation records, start the conversation "
"anew.\n\nFormation: \"Capacity and role\" defines the role you are currently playing;\n\t\"["
"LESSON_BEGIN]\" and \"[LESSON_END]\" tags enclose the content of textbook;\n\t\"Statement\" "
"defines the work detail you need to complete at this stage;\n\t\"Answer options\" defines the "
"format requirements for your responses;\n\t\"Constraint\" defines the conditions that your "
"responses must comply with.\n\n{statements}\nConstraint: Writing in {language}.\nAnswer options: "
"Encloses the lesson title with \"[TEACHING_PLAN_BEGIN]\" and \"[TEACHING_PLAN_END]\" tags.\n["
"LESSON_BEGIN]\n{lesson}\n[LESSON_END]",
"Do not refer to the context of the previous conversation records, start the conversation "
"anew.\n\nFormation: \"Capacity and role\" defines the role you are currently playing;\n\t\"["
"LESSON_BEGIN]\" and \"[LESSON_END]\" tags enclose the content of textbook;\n\t\"Statement\" "
"defines the work detail you need to complete at this stage;\n\t\"Answer options\" defines the "
"format requirements for your responses;\n\t\"Constraint\" defines the conditions that your "
"responses must comply with.\n\nCapacity and role: {role}\nStatement: Write the \"{topic}\" part "
"of teaching plan, WITHOUT ANY content unrelated to \"{topic}\"!!\n{statements}\nAnswer options: "
"Enclose the teaching plan content with \"[TEACHING_PLAN_BEGIN]\" and \"[TEACHING_PLAN_END]\" "
"tags.\nAnswer options: Using proper markdown format from second-level header "
"format.\nConstraint: Writing in {language}.\n[LESSON_BEGIN]\n{lesson}\n[LESSON_END] "
],
"actions": [
{
"name": "",
"topic": "Title",
"language": "Chinese",
"statements": [
"Statement: Find and return the title of the lesson only with \"# \" prefixed, without "
"anything else."],
"template_ix": 0},
{
"name": "",
"topic": "Teaching Hours",
"language": "Chinese",
"statements": [],
"template_ix": 1,
"rsp_begin_tag": "[TEACHING_PLAN_BEGIN]",
"rsp_end_tag": "[TEACHING_PLAN_END]"}
]
},
"action_count": 2
}
]
for i in inputs:
seed = Inputs(**i)
kwargs = {
"teaching_language": "AA",
"language": "BB"
}
runtime_options = Config().runtime_options
cost_manager = CostManager(options=runtime_options)
role = ForkMetaRole(runtime_options=runtime_options, cost_manager=cost_manager, role_options=seed.role, **kwargs)
assert role.action_count == 2
assert "{" not in role.profile
assert "{" not in role.goal
assert "{" not in role.constraints
if __name__ == '__main__':
test_creat_role()

View file

@ -0,0 +1,101 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time : 2023/7/27 13:25
@Author : mashenquan
@File : test_teacher.py
"""
from typing import Dict, Optional
from pydantic import BaseModel
from metagpt.config import Config
from metagpt.provider.openai_api import CostManager
from metagpt.roles.teacher import Teacher
def test_init():
class Inputs(BaseModel):
name: str
profile: str
goal: str
constraints: str
desc: str
kwargs: 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",
"kwargs": {"language": "CN", "key1": "HaHa", "something_big": "sleep", "teaching_language": "EN"},
"desc": "aaa{language}",
"expect_desc": "aaaCN"
},
{
"name": "Lily{language}",
"expect_name": "Lily{language}",
"profile": "X {teaching_language}",
"expect_profile": "X {teaching_language}",
"goal": "Do {something_big}, {language}",
"expect_goal": "Do {something_big}, {language}",
"constraints": "Do in {key1}, {language}",
"expect_constraints": "Do in {key1}, {language}",
"kwargs": {},
"desc": "aaa{language}",
"expect_desc": "aaa{language}"
},
]
for i in inputs:
seed = Inputs(**i)
options = Config().runtime_options
cost_manager = CostManager(options=options)
teacher = Teacher(options=options, cost_manager=cost_manager, name=seed.name, profile=seed.profile,
goal=seed.goal, constraints=seed.constraints,
desc=seed.desc, **seed.kwargs)
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()
test_new_file_name()

View file

@ -0,0 +1,61 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time : 2023/8/8
@Author : mashenquan
@File : test_uml_meta_role_factory.py
"""
from typing import List, Dict
from pydantic import BaseModel
from metagpt.roles.uml_meta_role_factory import UMLMetaRoleFactory
def test_create_roles():
class Inputs(BaseModel):
roles: List
kwargs: Dict
inputs = [
{
"roles": [
{
"role_type": "fork",
"name": "Lily",
"profile": "{teaching_language} Teacher",
"goal": "writing a {language} teaching plan part by part",
"constraints": "writing in {language}",
"role": "You are a {teaching_language} Teacher, named Lily.",
"desc": "",
"output_filename": "teaching_plan_demo.md",
"requirement": ["TeachingPlanRequirement"],
"templates": ["Do 1 {statements}", "Do 2 {statements}"],
"actions": [
{
"name": "",
"topic": "Title",
"language": "Chinese",
"statements": ["statement 1", "statement 2"]}
],
"template_ix": 0
}
],
"kwargs": {
"teaching_language": "AA",
"language": "BB",
}
}
]
for i in inputs:
seed = Inputs(**i)
roles = UMLMetaRoleFactory.create_roles(seed.roles, **seed.kwargs)
assert len(roles) == 1
assert "{" not in roles[0].profile
assert "{" not in roles[0].goal
assert roles[0].action_count == 1
if __name__ == '__main__':
test_create_roles()

View file

@ -0,0 +1,40 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time : 2023/8/8
@Author : mashenquan
@File : test_uml_meta_role_options.py
"""
from typing import List
from pydantic import BaseModel
from metagpt.roles.uml_meta_role_options import MetaActionOptions
def test_set_default_template():
class Inputs(BaseModel):
statements: List
template: str
expect_prompt: str
inputs = [
{
"statements": ["Statement: 1", "Statement: 2"],
"template": "{statements}",
"expect_prompt": "Statement: 1\nStatement: 2"
}
]
for i in inputs:
seed = Inputs(**i)
opt = MetaActionOptions(topic="", statements=seed.statements)
assert opt.template == ""
opt.set_default_template(seed.template)
assert opt.template == seed.template
kwargs = {}
assert opt.format_prompt(**kwargs) == seed.expect_prompt
if __name__ == '__main__':
test_set_default_template()

View file

@ -4,23 +4,46 @@
@Time : 2023/7/1 22:50
@Author : alexanderwu
@File : test_azure_tts.py
@Modified By: mashenquan, 2023-8-9, add more text formatting options
@Modified By: mashenquan, 2023-8-17, move to `tools` folder.
"""
import sys
from pathlib import Path
sys.path.append(str(Path(__file__).resolve().parent.parent.parent.parent)) # fix-bug: No module named 'metagpt'
from metagpt.const import WORKSPACE_ROOT
from metagpt.tools.azure_tts import AzureTTS
from metagpt.utils.common import initialize_environment
def test_azure_tts():
azure_tts = AzureTTS("azure_tts")
azure_tts.synthesize_speech(
"zh-CN",
"zh-CN-YunxiNeural",
"Boy",
"你好,我是卡卡",
"output.wav")
initialize_environment()
azure_tts = AzureTTS()
text = """
女儿看见父亲走了进来问道
<mstts:express-as role="YoungAdultFemale" style="calm">
您来的挺快的怎么过来的
</mstts:express-as>
父亲放下手提包
<mstts:express-as role="OlderAdultMale" style="calm">
Writing a binary file in Python is similar to writing a regular text file, but you'll work with bytes instead of strings.”
</mstts:express-as>
"""
path = WORKSPACE_ROOT / "tts"
path.mkdir(exist_ok=True, parents=True)
filename = path / "girl.wav"
result = azure_tts.synthesize_speech(
lang="zh-CN",
voice="zh-CN-XiaomoNeural",
text=text,
output_file=str(filename))
print(result)
# 运行需要先配置 SUBSCRIPTION_KEY
# TODO: 这里如果要检验还要额外加上对应的asr才能确保前后生成是接近一致的但现在还没有
if __name__ == '__main__':
test_azure_tts()