mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-05 14:55:18 +02:00
feat: replaced with OPTIONS
This commit is contained in:
parent
3a1ebf19b7
commit
143ffb0c2c
39 changed files with 144 additions and 252 deletions
|
|
@ -4,7 +4,7 @@
|
|||
@Time : 2023/5/11 14:43
|
||||
@Author : alexanderwu
|
||||
@File : action.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
@Modified By: mashenquan, 2023/8/20. Add function return annotations.
|
||||
"""
|
||||
from abc import ABC
|
||||
from typing import Optional
|
||||
|
|
@ -12,15 +12,16 @@ from typing import Optional
|
|||
from tenacity import retry, stop_after_attempt, wait_fixed
|
||||
|
||||
from metagpt.actions.action_output import ActionOutput
|
||||
from metagpt.config import Config
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.utils.common import OutputParser
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
class Action(ABC):
|
||||
def __init__(self, options=None, name: str = '', context=None, llm=None):
|
||||
self.options = options or Config().runtime_options
|
||||
def __init__(self, name: str = '', context=None, llm: LLM = None):
|
||||
self.name: str = name
|
||||
if llm is None:
|
||||
llm = LLM()
|
||||
self.llm = llm
|
||||
self.context = context
|
||||
self.prefix = ""
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
@Time : 2023/7/11 10:03
|
||||
@Author : chengmaoyu
|
||||
@File : action_output
|
||||
@Modified By: mashenquan, 2023/8/20. Allow 'instruct_content' to be blank.
|
||||
"""
|
||||
|
||||
from typing import Dict, Type, Optional
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
@Time : 2023/5/19 12:01
|
||||
@Author : alexanderwu
|
||||
@File : analyze_dep_libs.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
|
||||
from metagpt.actions import Action
|
||||
|
|
@ -27,8 +26,8 @@ Focus only on the names of shared dependencies, do not add any other explanation
|
|||
|
||||
|
||||
class AnalyzeDepLibs(Action):
|
||||
def __init__(self, options, name, context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name, context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
self.desc = "根据上下文,分析程序运行依赖库"
|
||||
|
||||
async def run(self, requirement, filepaths_string):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
@Time : 2023/5/11 17:46
|
||||
@Author : alexanderwu
|
||||
@File : debug_error.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
import re
|
||||
|
||||
|
|
@ -26,8 +25,8 @@ Now you should start rewriting the code:
|
|||
## file name of the code to rewrite: Write code with triple quoto. Do your best to implement THIS IN ONLY ONE FILE.
|
||||
"""
|
||||
class DebugError(Action):
|
||||
def __init__(self, options, name="DebugError", context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name="DebugError", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
# async def run(self, code, error):
|
||||
# prompt = f"Here is a piece of Python code:\n\n{code}\n\nThe following error occurred during execution:" \
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
@Author : alexanderwu
|
||||
@File : design_api.py
|
||||
@Modified By: mashenquan, 2023-8-9, align `run` parameters with the parent :class:`Action` class.
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
|
@ -92,8 +91,8 @@ OUTPUT_MAPPING = {
|
|||
|
||||
|
||||
class WriteDesign(Action):
|
||||
def __init__(self, options, name, context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name, context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
self.desc = "Based on the PRD, think about the system design, and design the corresponding APIs, " \
|
||||
"data structures, library tables, processes, and paths. Please provide your design, feedback " \
|
||||
"clearly and in detail."
|
||||
|
|
@ -108,15 +107,15 @@ class WriteDesign(Action):
|
|||
def _save_prd(self, docs_path, resources_path, prd):
|
||||
prd_file = docs_path / 'prd.md'
|
||||
quadrant_chart = CodeParser.parse_code(block="Competitive Quadrant Chart", text=prd)
|
||||
mermaid_to_file(options=self.options, mermaid_code=quadrant_chart, output_file_without_suffix=resources_path / 'competitive_analysis')
|
||||
mermaid_to_file(quadrant_chart, resources_path / 'competitive_analysis')
|
||||
logger.info(f"Saving PRD to {prd_file}")
|
||||
prd_file.write_text(prd)
|
||||
|
||||
def _save_system_design(self, docs_path, resources_path, content):
|
||||
data_api_design = CodeParser.parse_code(block="Data structures and interface definitions", text=content)
|
||||
seq_flow = CodeParser.parse_code(block="Program call flow", text=content)
|
||||
mermaid_to_file(options=self.options, mermaid_code=data_api_design, output_file_without_suffix=resources_path / 'data_api_design')
|
||||
mermaid_to_file(options=self.options, mermaid_code=seq_flow, output_file_without_suffix=resources_path / 'seq_flow')
|
||||
mermaid_to_file(data_api_design, resources_path / 'data_api_design')
|
||||
mermaid_to_file(seq_flow, resources_path / 'seq_flow')
|
||||
system_design_file = docs_path / 'system_design.md'
|
||||
logger.info(f"Saving System Designs to {system_design_file}")
|
||||
system_design_file.write_text(content)
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@
|
|||
@Time : 2023/5/11 19:31
|
||||
@Author : alexanderwu
|
||||
@File : design_api_review.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
from metagpt.actions.action import Action
|
||||
|
||||
|
||||
class DesignReview(Action):
|
||||
def __init__(self, options, name, context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name, context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, prd, api_design):
|
||||
prompt = f"Here is the Product Requirement Document (PRD):\n\n{prd}\n\nHere is the list of APIs designed " \
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
@Time : 2023/5/19 11:50
|
||||
@Author : alexanderwu
|
||||
@File : design_filenames.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
from metagpt.actions import Action
|
||||
from metagpt.logs import logger
|
||||
|
|
@ -16,8 +15,8 @@ Do not add any other explanations, just return a Python string list."""
|
|||
|
||||
|
||||
class DesignFilenames(Action):
|
||||
def __init__(self, options, name, context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name, context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
self.desc = "Based on the PRD, consider system design, and carry out the basic design of the corresponding " \
|
||||
"APIs, data structures, and database tables. Please give your design, feedback clearly and in detail."
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
@Author : alexanderwu
|
||||
@File : project_management.py
|
||||
@Modified By: mashenquan, 2023-8-9, align `run` parameters with the parent :class:`Action` class.
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
from typing import List, Tuple
|
||||
|
||||
|
|
@ -105,8 +104,8 @@ OUTPUT_MAPPING = {
|
|||
|
||||
class WriteTasks(Action):
|
||||
|
||||
def __init__(self, options, name="CreateTasks", context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name="CreateTasks", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
def _save(self, context, rsp):
|
||||
ws_name = CodeParser.parse_str(block="Python package name", text=context[-1].content)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
|
@ -13,6 +9,7 @@ from typing import Callable
|
|||
from pydantic import parse_obj_as
|
||||
|
||||
from metagpt.actions import Action
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.logs import logger
|
||||
from metagpt.tools.search_engine import SearchEngine
|
||||
from metagpt.tools.web_browser_engine import WebBrowserEngine, WebBrowserEngineType
|
||||
|
|
@ -82,15 +79,14 @@ class CollectLinks(Action):
|
|||
"""Action class to collect links from a search engine."""
|
||||
def __init__(
|
||||
self,
|
||||
options,
|
||||
name: str = "",
|
||||
*args,
|
||||
rank_func: Callable[[list[str]], None] | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(options=options, name=name, *args, **kwargs)
|
||||
super().__init__(name, *args, **kwargs)
|
||||
self.desc = "Collect links from a search engine."
|
||||
self.search_engine = SearchEngine(options=options)
|
||||
self.search_engine = SearchEngine()
|
||||
self.rank_func = rank_func
|
||||
|
||||
async def run(
|
||||
|
|
@ -130,7 +126,7 @@ class CollectLinks(Action):
|
|||
remove.pop()
|
||||
if len(remove) == 0:
|
||||
break
|
||||
prompt = reduce_message_length(gen_msg(), self.llm.model, system_text, self.options.get("max_tokens_rsp"))
|
||||
prompt = reduce_message_length(gen_msg(), self.llm.model, system_text, CONFIG.max_tokens_rsp)
|
||||
logger.debug(prompt)
|
||||
queries = await self._aask(prompt, [system_text])
|
||||
try:
|
||||
|
|
@ -182,10 +178,9 @@ class WebBrowseAndSummarize(Action):
|
|||
**kwargs,
|
||||
):
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.options.get("model_for_researcher_summary"):
|
||||
self.llm.model = self.options.get("model_for_researcher_summary")
|
||||
if CONFIG.model_for_researcher_summary:
|
||||
self.llm.model = CONFIG.model_for_researcher_summary
|
||||
self.web_browser_engine = WebBrowserEngine(
|
||||
options=self.options,
|
||||
engine=WebBrowserEngineType.CUSTOM if browse_func else None,
|
||||
run_func=browse_func,
|
||||
)
|
||||
|
|
@ -218,8 +213,7 @@ class WebBrowseAndSummarize(Action):
|
|||
for u, content in zip([url, *urls], contents):
|
||||
content = content.inner_text
|
||||
chunk_summaries = []
|
||||
for prompt in generate_prompt_chunk(content, prompt_template, self.llm.model, system_text,
|
||||
self.options.get("max_tokens_rsp")):
|
||||
for prompt in generate_prompt_chunk(content, prompt_template, self.llm.model, system_text, CONFIG.max_tokens_rsp):
|
||||
logger.debug(prompt)
|
||||
summary = await self._aask(prompt, [system_text])
|
||||
if summary == "Not relevant.":
|
||||
|
|
@ -245,8 +239,8 @@ class ConductResearch(Action):
|
|||
"""Action class to conduct research and generate a research report."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.options.get("model_for_researcher_report"):
|
||||
self.llm.model = self.options.get("model_for_researcher_report")
|
||||
if CONFIG.model_for_researcher_report:
|
||||
self.llm.model = CONFIG.model_for_researcher_report
|
||||
|
||||
async def run(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
@Time : 2023/5/11 17:46
|
||||
@Author : alexanderwu
|
||||
@File : run_code.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
|
|
@ -58,8 +57,8 @@ standard errors: {errs};
|
|||
|
||||
|
||||
class RunCode(Action):
|
||||
def __init__(self, options, name="RunCode", context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name="RunCode", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
@classmethod
|
||||
async def run_text(cls, code) -> Tuple[str, str]:
|
||||
|
|
|
|||
|
|
@ -101,16 +101,16 @@ You are a member of a professional butler team and will provide helpful suggesti
|
|||
|
||||
|
||||
class SearchAndSummarize(Action):
|
||||
def __init__(self, options, name="", context=None, llm=None, engine=None, search_func=None):
|
||||
self.engine = engine or options.get("search_engine")
|
||||
def __init__(self, name="", context=None, llm=None, engine=None, search_func=None):
|
||||
self.engine = engine or CONFIG.search_engine
|
||||
|
||||
try:
|
||||
self.search_engine = SearchEngine(options=options, engine=self.engine, run_func=search_func)
|
||||
self.search_engine = SearchEngine(self.engine, run_func=search_func)
|
||||
except pydantic.ValidationError:
|
||||
self.search_engine = None
|
||||
|
||||
self.result = ""
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, context: list[Message], system_text=SEARCH_AND_SUMMARIZE_SYSTEM) -> str:
|
||||
if self.search_engine is None:
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2023/8/28
|
||||
@Author : mashenquan
|
||||
@File : skill_action.py
|
||||
@Desc : Call learned skill
|
||||
"""
|
||||
|
||||
import ast
|
||||
import importlib
|
||||
|
||||
|
|
@ -7,8 +16,8 @@ from metagpt.logs import logger
|
|||
|
||||
|
||||
class ArgumentsParingAction(Action):
|
||||
def __init__(self, options, last_talk: str, skill: Skill, context=None, llm=None, **kwargs):
|
||||
super(ArgumentsParingAction, self).__init__(options=options, name='', context=context, llm=llm)
|
||||
def __init__(self, last_talk: str, skill: Skill, context=None, llm=None, **kwargs):
|
||||
super(ArgumentsParingAction, self).__init__(name='', context=context, llm=llm)
|
||||
self.skill = skill
|
||||
self.ask = last_talk
|
||||
self.rsp = None
|
||||
|
|
@ -59,15 +68,15 @@ class ArgumentsParingAction(Action):
|
|||
|
||||
|
||||
class SkillAction(Action):
|
||||
def __init__(self, options, skill: Skill, args: dict, context=None, llm=None, **kwargs):
|
||||
super(SkillAction, self).__init__(options=options, name='', context=context, llm=llm)
|
||||
def __init__(self, skill: Skill, args: dict, context=None, llm=None, **kwargs):
|
||||
super(SkillAction, self).__init__(name='', context=context, llm=llm)
|
||||
self._skill = skill
|
||||
self._args = args
|
||||
self.rsp = None
|
||||
|
||||
async def run(self, *args, **kwargs) -> str | ActionOutput | None:
|
||||
"""Run action"""
|
||||
self.rsp = self.find_and_call_function(self._skill.name, args=self._args, **self.options)
|
||||
self.rsp = self.find_and_call_function(self._skill.name, args=self._args, **kwargs)
|
||||
return ActionOutput(content=self.rsp, instruct_content=self._skill.json())
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
@Time : 2023/5/11 17:45
|
||||
@Author : alexanderwu
|
||||
@File : write_code.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
from metagpt.actions import WriteDesign
|
||||
from metagpt.actions.action import Action
|
||||
|
|
@ -44,8 +43,8 @@ ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenc
|
|||
|
||||
|
||||
class WriteCode(Action):
|
||||
def __init__(self, options, name="WriteCode", context: list[Message] = None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name="WriteCode", context: list[Message] = None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
def _is_invalid(self, filename):
|
||||
return any(i in filename for i in ["mp3", "wav"])
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
@Time : 2023/5/11 17:45
|
||||
@Author : alexanderwu
|
||||
@File : write_code_review.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
|
||||
from metagpt.actions.action import Action
|
||||
|
|
@ -63,8 +62,8 @@ FORMAT_EXAMPLE = """
|
|||
|
||||
|
||||
class WriteCodeReview(Action):
|
||||
def __init__(self, options, name="WriteCodeReview", context: list[Message] = None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name="WriteCodeReview", context: list[Message] = None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
@retry(stop=stop_after_attempt(2), wait=wait_fixed(1))
|
||||
async def write_code(self, prompt):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
@Time : 2023/5/11 17:45
|
||||
@Author : alexanderwu
|
||||
@File : write_prd.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
from typing import List, Tuple
|
||||
|
||||
|
|
@ -128,11 +127,11 @@ OUTPUT_MAPPING = {
|
|||
|
||||
|
||||
class WritePRD(Action):
|
||||
def __init__(self, options, name="", context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name="", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def run(self, requirements, *args, **kwargs) -> ActionOutput:
|
||||
sas = SearchAndSummarize(options=self.options, llm=self.llm)
|
||||
sas = SearchAndSummarize()
|
||||
# rsp = await sas.run(context=requirements, system_text=SEARCH_AND_SUMMARIZE_SYSTEM_EN_US)
|
||||
rsp = ""
|
||||
info = f"### Search Results\n{sas.result}\n\n### Search Summary\n{rsp}"
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@
|
|||
@Time : 2023/5/11 17:45
|
||||
@Author : alexanderwu
|
||||
@File : write_prd_review.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
from metagpt.actions.action import Action
|
||||
|
||||
|
||||
class WritePRDReview(Action):
|
||||
def __init__(self, options, name, context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name, context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
self.prd = None
|
||||
self.desc = "Based on the PRD, conduct a PRD Review, providing clear and detailed feedback"
|
||||
self.prd_review_prompt_template = """
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class WriteTeachingPlanPart(Action):
|
|||
statements = []
|
||||
from metagpt.roles import Role
|
||||
for p in statement_patterns:
|
||||
s = Role.format_value(p, kwargs)
|
||||
s = Role.format_value(p)
|
||||
statements.append(s)
|
||||
formatter = self.PROMPT_TITLE_TEMPLATE if self.topic == self.COURSE_TITLE else self.PROMPT_TEMPLATE
|
||||
prompt = formatter.format(formation=self.FORMATION,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
@Time : 2023/5/11 17:45
|
||||
@Author : alexanderwu
|
||||
@File : write_test.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.utils.common import CodeParser
|
||||
|
|
@ -31,8 +30,8 @@ you should correctly import the necessary classes based on these file locations!
|
|||
|
||||
|
||||
class WriteTest(Action):
|
||||
def __init__(self, options, name="WriteTest", context=None, llm=None):
|
||||
super().__init__(options=options, name=name, context=context, llm=llm)
|
||||
def __init__(self, name="WriteTest", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
async def write_code(self, prompt):
|
||||
code_rsp = await self._aask(prompt)
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2023/8/20
|
||||
@Author : mashenquan
|
||||
@File : skill_metadata.py
|
||||
@Desc : Defines metadata for the `skill`.
|
||||
Depending on the context and specific circumstances, skills may have different effects.
|
||||
For example:
|
||||
Proprietor: "Skill of the proprietor entity."
|
||||
Holder: "Skill of the holder entity."
|
||||
Possessor: "Skill of the possessor entity."
|
||||
Controller: "Skill of the controller entity."
|
||||
Owner: "Skill of the owner entity."
|
||||
"""
|
||||
|
||||
|
||||
def skill_metadata(name, description, requisite):
|
||||
def decorator(func):
|
||||
func.skill_name = name
|
||||
func.skill_description = description
|
||||
func.skill_requisite = requisite
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
|
@ -6,16 +6,11 @@
|
|||
@File : text_to_embedding.py
|
||||
@Desc : Text-to-Embedding skill, which provides text-to-embedding functionality.
|
||||
"""
|
||||
import os
|
||||
|
||||
from metagpt.learn.skill_metadata import skill_metadata
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.tools.openai_text_to_embedding import oas3_openai_text_to_embedding
|
||||
from metagpt.utils.common import initialize_environment
|
||||
|
||||
|
||||
@skill_metadata(name="Text to Embedding",
|
||||
description="Convert the text into embeddings.",
|
||||
requisite="`OPENAI_API_KEY`")
|
||||
async def text_to_embedding(text, model="text-embedding-ada-002", openai_api_key="", **kwargs):
|
||||
"""Text to embedding
|
||||
|
||||
|
|
@ -24,7 +19,6 @@ async def text_to_embedding(text, model="text-embedding-ada-002", openai_api_key
|
|||
:param openai_api_key: OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`
|
||||
:return: A json object of :class:`ResultEmbedding` class if successful, otherwise `{}`.
|
||||
"""
|
||||
initialize_environment()
|
||||
if os.environ.get("OPENAI_API_KEY") or openai_api_key:
|
||||
if CONFIG.OPENAI_API_KEY or openai_api_key:
|
||||
return await oas3_openai_text_to_embedding(text, model=model, openai_api_key=openai_api_key)
|
||||
raise EnvironmentError
|
||||
|
|
|
|||
|
|
@ -8,15 +8,11 @@
|
|||
"""
|
||||
import os
|
||||
|
||||
from metagpt.learn.skill_metadata import skill_metadata
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.tools.metagpt_text_to_image import oas3_metagpt_text_to_image
|
||||
from metagpt.tools.openai_text_to_image import oas3_openai_text_to_image
|
||||
from metagpt.utils.common import initialize_environment
|
||||
|
||||
|
||||
@skill_metadata(name="Text to image",
|
||||
description="Create a drawing based on the text.",
|
||||
requisite="`OPENAI_API_KEY` or `METAGPT_TEXT_TO_IMAGE_MODEL`")
|
||||
async def text_to_image(text, size_type: str = "512x512", openai_api_key="", model_url="", **kwargs):
|
||||
"""Text to image
|
||||
|
||||
|
|
@ -26,13 +22,12 @@ async def text_to_image(text, size_type: str = "512x512", openai_api_key="", mod
|
|||
:param model_url: MetaGPT model url
|
||||
:return: The image data is returned in Base64 encoding.
|
||||
"""
|
||||
initialize_environment()
|
||||
image_declaration = "data:image/png;base64,"
|
||||
if os.environ.get("METAGPT_TEXT_TO_IMAGE_MODEL_URL") or model_url:
|
||||
if CONFIG.METAGPT_TEXT_TO_IMAGE_MODEL_URL or model_url:
|
||||
data = await oas3_metagpt_text_to_image(text, size_type, model_url)
|
||||
return image_declaration + data if data else ""
|
||||
|
||||
if os.environ.get("OPENAI_API_KEY") or openai_api_key:
|
||||
if CONFIG.OPENAI_API_KEY or openai_api_key:
|
||||
data = await oas3_openai_text_to_image(text, size_type, openai_api_key)
|
||||
return image_declaration + data if data else ""
|
||||
|
||||
|
|
|
|||
|
|
@ -6,16 +6,14 @@
|
|||
@File : text_to_speech.py
|
||||
@Desc : Text-to-Speech skill, which provides text-to-speech functionality
|
||||
"""
|
||||
import os
|
||||
|
||||
from metagpt.learn.skill_metadata import skill_metadata
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
|
||||
from metagpt.tools.azure_tts import oas3_azsure_tts
|
||||
from metagpt.utils.common import initialize_environment
|
||||
|
||||
|
||||
@skill_metadata(name="Text to speech",
|
||||
description="Text-to-speech",
|
||||
requisite="`AZURE_TTS_SUBSCRIPTION_KEY` and `AZURE_TTS_REGION`")
|
||||
|
||||
async def text_to_speech(text, lang="zh-CN", voice="zh-CN-XiaomoNeural", style="affectionate", role="Girl",
|
||||
subscription_key="", region="", **kwargs):
|
||||
"""Text to speech
|
||||
|
|
@ -31,9 +29,8 @@ async def text_to_speech(text, lang="zh-CN", voice="zh-CN-XiaomoNeural", style="
|
|||
:return: Returns the Base64-encoded .wav file data if successful, otherwise an empty string.
|
||||
|
||||
"""
|
||||
initialize_environment()
|
||||
audio_declaration = "data:audio/wav;base64,"
|
||||
if (os.environ.get("AZURE_TTS_SUBSCRIPTION_KEY") and os.environ.get("AZURE_TTS_REGION")) or \
|
||||
if (CONFIG.AZURE_TTS_SUBSCRIPTION_KEY and CONFIG.AZURE_TTS_REGION) or \
|
||||
(subscription_key and region):
|
||||
data = await oas3_azsure_tts(text, lang, voice, style, role, subscription_key, region)
|
||||
return audio_declaration + data if data else data
|
||||
|
|
|
|||
20
metagpt/llm.py
Normal file
20
metagpt/llm.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2023/5/11 14:45
|
||||
@Author : alexanderwu
|
||||
@File : llm.py
|
||||
"""
|
||||
|
||||
from metagpt.provider.anthropic_api import Claude2 as Claude
|
||||
from metagpt.provider.openai_api import OpenAIGPTAPI as LLM
|
||||
|
||||
DEFAULT_LLM = LLM()
|
||||
CLAUDE_LLM = Claude()
|
||||
|
||||
|
||||
async def ai_func(prompt):
|
||||
"""使用LLM进行QA
|
||||
QA with LLMs
|
||||
"""
|
||||
return await DEFAULT_LLM.aask(prompt)
|
||||
|
|
@ -4,15 +4,14 @@
|
|||
@Time : 2023/5/11 14:42
|
||||
@Author : alexanderwu
|
||||
@File : manager.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation.
|
||||
"""
|
||||
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.logs import logger
|
||||
from metagpt.schema import Message
|
||||
|
||||
|
||||
class Manager:
|
||||
def __init__(self, llm):
|
||||
def __init__(self, llm: LLM = LLM()):
|
||||
self.llm = llm # Large Language Model
|
||||
self.role_directions = {
|
||||
"BOSS": "Product Manager",
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
@Time : 2023/5/11 14:43
|
||||
@Author : alexanderwu
|
||||
@File : architect.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation;
|
||||
Change cost control from global to company level.
|
||||
"""
|
||||
|
||||
from metagpt.actions import WriteDesign, WritePRD
|
||||
|
|
@ -14,8 +12,8 @@ from metagpt.roles import Role
|
|||
|
||||
class Architect(Role):
|
||||
"""Architect: Listen to PRD, responsible for designing API, designing code files"""
|
||||
def __init__(self, options, cost_manager, name="Bob", profile="Architect", goal="Design a concise, usable, complete python system",
|
||||
def __init__(self, name="Bob", profile="Architect", goal="Design a concise, usable, complete python system",
|
||||
constraints="Try to specify good open source tools as much as possible"):
|
||||
super().__init__(name=name, profile=profile, goal=goal, constraints=constraints, options=options, cost_manager=cost_manager)
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
self._init_actions([WriteDesign])
|
||||
self._watch({WritePRD})
|
||||
|
|
|
|||
|
|
@ -26,11 +26,9 @@ DESC = """
|
|||
class CustomerService(Sales):
|
||||
def __init__(
|
||||
self,
|
||||
options,
|
||||
cost_manager,
|
||||
name="Xiaomei",
|
||||
profile="Human customer service",
|
||||
desc=DESC,
|
||||
store=None
|
||||
):
|
||||
super().__init__(options=options, cost_manager=cost_manager, name=name, profile=profile, desc=desc, store=store)
|
||||
super().__init__(name, profile, desc=desc, store=store)
|
||||
|
|
|
|||
|
|
@ -47,10 +47,10 @@ async def gather_ordered_k(coros, k) -> list:
|
|||
|
||||
|
||||
class Engineer(Role):
|
||||
def __init__(self, options, cost_manager, name="Alex", profile="Engineer", goal="Write elegant, readable, extensible, efficient code",
|
||||
def __init__(self, name="Alex", profile="Engineer", goal="Write elegant, readable, extensible, efficient code",
|
||||
constraints="The code you write should conform to code standard like PEP8, be modular, easy to read and maintain",
|
||||
n_borg=1, use_code_review=False):
|
||||
super().__init__(name=name, profile=profile, goal=goal, constraints=constraints, options=options, cost_manager=cost_manager)
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
self._init_actions([WriteCode])
|
||||
self.use_code_review = use_code_review
|
||||
if self.use_code_review:
|
||||
|
|
@ -131,7 +131,7 @@ class Engineer(Role):
|
|||
async def _act_sp(self) -> Message:
|
||||
code_msg_all = [] # gather all code info, will pass to qa_engineer for tests later
|
||||
for todo in self.todos:
|
||||
code = await WriteCode(options=self.options, llm=self._llm).run(
|
||||
code = await WriteCode().run(
|
||||
context=self._rc.history,
|
||||
filename=todo
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,16 +4,14 @@
|
|||
@Time : 2023/5/11 14:43
|
||||
@Author : alexanderwu
|
||||
@File : product_manager.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation;
|
||||
Change cost control from global to company level.
|
||||
"""
|
||||
from metagpt.actions import BossRequirement, WritePRD
|
||||
from metagpt.roles import Role
|
||||
|
||||
|
||||
class ProductManager(Role):
|
||||
def __init__(self, options, cost_manager, name="Alice", profile="Product Manager", goal="Efficiently create a successful product",
|
||||
def __init__(self, name="Alice", profile="Product Manager", goal="Efficiently create a successful product",
|
||||
constraints=""):
|
||||
super().__init__(name=name, profile=profile, goal=goal, constraints=constraints, options=options, cost_manager=cost_manager)
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
self._init_actions([WritePRD])
|
||||
self._watch([BossRequirement])
|
||||
|
|
|
|||
|
|
@ -4,16 +4,14 @@
|
|||
@Time : 2023/5/11 15:04
|
||||
@Author : alexanderwu
|
||||
@File : project_manager.py
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation;
|
||||
Change cost control from global to company level.
|
||||
"""
|
||||
from metagpt.actions import WriteDesign, WriteTasks
|
||||
from metagpt.roles import Role
|
||||
|
||||
|
||||
class ProjectManager(Role):
|
||||
def __init__(self, options, cost_manager, name="Eve", profile="Project Manager",
|
||||
def __init__(self, name="Eve", profile="Project Manager",
|
||||
goal="Improve team efficiency and deliver with quality and quantity", constraints=""):
|
||||
super().__init__(name=name, profile=profile, goal=goal, constraints=constraints, options=options, cost_manager=cost_manager)
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
self._init_actions([WriteTasks])
|
||||
self._watch([WriteDesign])
|
||||
|
|
|
|||
|
|
@ -20,15 +20,13 @@ from metagpt.utils.special_tokens import FILENAME_CODE_SEP, MSG_SEP
|
|||
class QaEngineer(Role):
|
||||
def __init__(
|
||||
self,
|
||||
options,
|
||||
cost_manager,
|
||||
name="Edward",
|
||||
profile="QaEngineer",
|
||||
goal="Write comprehensive and robust tests to ensure codes will work as expected without bugs",
|
||||
constraints="The test code you write should conform to code standard like PEP8, be modular, easy to read and maintain",
|
||||
test_round_allowed=5,
|
||||
):
|
||||
super().__init__(name=name, profile=profile, goal=goal, constraints=constraints, options=options, cost_manager=cost_manager)
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
self._init_actions(
|
||||
[WriteTest]
|
||||
) # FIXME: a bit hack here, only init one action to circumvent _think() logic, will overwrite _think() in future updates
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@ class Report(BaseModel):
|
|||
class Researcher(Role):
|
||||
def __init__(
|
||||
self,
|
||||
options,
|
||||
cost_manager,
|
||||
name: str = "David",
|
||||
profile: str = "Researcher",
|
||||
goal: str = "Gather information and conduct research",
|
||||
|
|
@ -35,11 +33,8 @@ class Researcher(Role):
|
|||
language: str = "en-us",
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(options=options, cost_manager=cost_manager, name=name, profile=profile, goal=goal, constraints=constraints, **kwargs)
|
||||
self._init_actions([
|
||||
CollectLinks(options=options, name=name),
|
||||
WebBrowseAndSummarize(options=options, name=name),
|
||||
ConductResearch(options=options, name=name)])
|
||||
super().__init__(name, profile, goal, constraints, **kwargs)
|
||||
self._init_actions([CollectLinks(name), WebBrowseAndSummarize(name), ConductResearch(name)])
|
||||
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.")
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@
|
|||
@Time : 2023/5/11 14:42
|
||||
@Author : alexanderwu
|
||||
@File : role.py
|
||||
@Modified By: mashenquan, 2023-8-7, :class:`Role` + properties.
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation;
|
||||
Change cost control from global to company level.
|
||||
@Modified By: mashenquan, 2023-8-7, Support template-style variables, such as '{teaching_language} Teacher'.
|
||||
@Modified By: mashenquan, 2023/8/22. A definition has been provided for the return value of _think: returning false indicates that further reasoning cannot continue.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
|
@ -15,7 +13,8 @@ from typing import Iterable, Type, Dict
|
|||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from metagpt.config import Config
|
||||
from metagpt.config import Config, CONFIG
|
||||
from metagpt.const import OPTIONS
|
||||
from metagpt.provider.openai_api import OpenAIGPTAPI as LLM, CostManager
|
||||
from metagpt.actions import Action, ActionOutput
|
||||
from metagpt.logs import logger
|
||||
|
|
@ -74,13 +73,12 @@ class RoleContext(BaseModel):
|
|||
todo: Action = Field(default=None)
|
||||
watch: set[Type[Action]] = Field(default_factory=set)
|
||||
news: list[Type[Message]] = Field(default=[])
|
||||
options: Dict
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
def check(self, role_id: str):
|
||||
if self.options.get("long_term_memory"):
|
||||
if CONFIG.long_term_memory:
|
||||
self.long_term_memory.recover_memory(role_id, self)
|
||||
self.memory = self.long_term_memory # use memory to act as long_term_memory for unify operation
|
||||
|
||||
|
|
@ -102,26 +100,20 @@ class RoleContext(BaseModel):
|
|||
class Role:
|
||||
"""Role/Proxy"""
|
||||
|
||||
def __init__(self, options=None, cost_manager=None, name="", profile="", goal="", constraints="", desc="", *args, **kwargs):
|
||||
options = options or Config().runtime_options
|
||||
cost_manager = cost_manager or CostManager(*options)
|
||||
|
||||
self._options = Role.supply_options(options=kwargs, default_options=options)
|
||||
|
||||
name = Role.format_value(name, self._options)
|
||||
profile = Role.format_value(profile, self._options)
|
||||
goal = Role.format_value(goal, self._options)
|
||||
constraints = Role.format_value(constraints, self._options)
|
||||
desc = Role.format_value(desc, self._options)
|
||||
|
||||
self._cost_manager = cost_manager
|
||||
self._llm = LLM(options=self._options, cost_manager=cost_manager)
|
||||
def __init__(self, name="", profile="", goal="", constraints="", desc="", *args, **kwargs):
|
||||
# Replace template-style variables, such as '{teaching_language} Teacher'.
|
||||
name = Role.format_value(name)
|
||||
profile = Role.format_value(profile)
|
||||
goal = Role.format_value(goal)
|
||||
constraints = Role.format_value(constraints)
|
||||
desc = Role.format_value(desc)
|
||||
|
||||
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(options=self._options)
|
||||
self._rc = RoleContext()
|
||||
|
||||
def _reset(self):
|
||||
self._states = []
|
||||
|
|
@ -131,7 +123,7 @@ class Role:
|
|||
self._reset()
|
||||
for idx, action in enumerate(actions):
|
||||
if not isinstance(action, Action):
|
||||
i = action(options=self._options, name="", llm=self._llm)
|
||||
i = action("", llm=self._llm)
|
||||
else:
|
||||
i = action
|
||||
i.set_prefix(self._get_prefix(), self.profile)
|
||||
|
|
@ -184,14 +176,6 @@ class Role:
|
|||
"""Return number of action"""
|
||||
return len(self._actions)
|
||||
|
||||
@property
|
||||
def options(self):
|
||||
return self._options
|
||||
|
||||
@options.setter
|
||||
def options(self, opts):
|
||||
self._options.update(opts)
|
||||
|
||||
def _get_prefix(self):
|
||||
"""获取角色前缀"""
|
||||
if self._setting.desc:
|
||||
|
|
@ -222,7 +206,7 @@ class Role:
|
|||
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
requirement = self._rc.important_memory or self._rc.prerequisite
|
||||
response = await self._rc.todo.run(requirement, **self._options)
|
||||
response = await self._rc.todo.run(requirement)
|
||||
# logger.info(response)
|
||||
if isinstance(response, ActionOutput):
|
||||
msg = Message(content=response.content, instruct_content=response.instruct_content,
|
||||
|
|
@ -300,23 +284,14 @@ class Role:
|
|||
return rsp
|
||||
|
||||
@staticmethod
|
||||
def supply_options(options, default_options=None):
|
||||
"""Supply missing options"""
|
||||
ret = default_options.copy() if default_options else {}
|
||||
if not options:
|
||||
return ret
|
||||
ret.update(options)
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def format_value(value, opts, default_opts=None):
|
||||
def format_value(value):
|
||||
"""Fill parameters inside `value` with `options`."""
|
||||
if not isinstance(value, str):
|
||||
return value
|
||||
if "{" not in value:
|
||||
return value
|
||||
|
||||
merged_opts = Role.supply_options(opts, default_opts)
|
||||
merged_opts = OPTIONS.get() or {}
|
||||
try:
|
||||
return value.format(**merged_opts)
|
||||
except KeyError as e:
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@ from metagpt.tools import SearchEngineType
|
|||
class Sales(Role):
|
||||
def __init__(
|
||||
self,
|
||||
options,
|
||||
cost_manager,
|
||||
name="Xiaomei",
|
||||
profile="Retail sales guide",
|
||||
desc="I am a sales guide in retail. My name is Xiaomei. I will answer some customer questions next, and I "
|
||||
|
|
@ -25,7 +23,7 @@ class Sales(Role):
|
|||
"professional guide",
|
||||
store=None
|
||||
):
|
||||
super().__init__(options=options, cost_manager=cost_manager, name=name, profile=profile, desc=desc)
|
||||
super().__init__(name, profile, desc=desc)
|
||||
self._set_store(store)
|
||||
|
||||
def _set_store(self, store):
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ from metagpt.tools import SearchEngineType
|
|||
|
||||
|
||||
class Searcher(Role):
|
||||
def __init__(self, options, cost_manager, name='Alice', profile='Smart Assistant', goal='Provide search services for users',
|
||||
def __init__(self, name='Alice', profile='Smart Assistant', goal='Provide search services for users',
|
||||
constraints='Answer is rich and complete', engine=SearchEngineType.SERPAPI_GOOGLE, **kwargs):
|
||||
super().__init__(options=options, cost_manager=cost_manager, name=name, profile=profile, goal=goal, constraints=constraints, **kwargs)
|
||||
super().__init__(name, profile, goal, constraints, **kwargs)
|
||||
self._init_actions([SearchAndSummarize(engine=engine)])
|
||||
|
||||
def set_search_func(self, search_func):
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ import re
|
|||
class Teacher(Role):
|
||||
"""Support configurable teacher roles,
|
||||
with native and teaching languages being replaceable through configurations."""
|
||||
def __init__(self, options, name='Lily', profile='{teaching_language} Teacher',
|
||||
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__(options=options, name=name, profile=profile, goal=goal, constraints=constraints, desc=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(options=options, topic=topic, llm=self._llm)
|
||||
act = WriteTeachingPlanPart(topic=topic, llm=self._llm)
|
||||
actions.append(act)
|
||||
self._init_actions(actions)
|
||||
self._watch({TeachingPlanRequirement})
|
||||
|
|
|
|||
|
|
@ -4,22 +4,16 @@
|
|||
@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()`.
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation;
|
||||
Change cost control from global to company level.
|
||||
"""
|
||||
from typing import Dict
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from metagpt.actions import BossRequirement
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.environment import Environment
|
||||
from metagpt.logs import logger
|
||||
from metagpt.provider.openai_api import CostManager
|
||||
from metagpt.roles import Role
|
||||
from metagpt.schema import Message
|
||||
from metagpt.utils.common import NoMoneyException
|
||||
from metagpt.config import Config
|
||||
|
||||
|
||||
class SoftwareCompany(BaseModel):
|
||||
|
|
@ -30,8 +24,6 @@ class SoftwareCompany(BaseModel):
|
|||
environment: Environment = Field(default_factory=Environment)
|
||||
investment: float = Field(default=10.0)
|
||||
idea: str = Field(default="")
|
||||
options: Dict = Field(default=Config().runtime_options)
|
||||
cost_manager: CostManager = Field(default=CostManager(**Config().runtime_options))
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
|
@ -43,17 +35,17 @@ class SoftwareCompany(BaseModel):
|
|||
def invest(self, investment: float):
|
||||
"""Invest company. raise NoMoneyException when exceed max_budget."""
|
||||
self.investment = investment
|
||||
self.options["max_budget"] = investment
|
||||
CONFIG.max_budget = investment
|
||||
logger.info(f'Investment: ${investment}.')
|
||||
|
||||
def _check_balance(self):
|
||||
if self.total_cost > self.max_budget:
|
||||
raise NoMoneyException(self.total_cost, f'Insufficient funds: {self.max_budget}')
|
||||
if CONFIG.total_cost > CONFIG.max_budget:
|
||||
raise NoMoneyException(CONFIG.total_cost, f'Insufficient funds: {CONFIG.max_budget}')
|
||||
|
||||
def start_project(self, idea, role="BOSS", cause_by=BossRequirement):
|
||||
def start_project(self, idea):
|
||||
"""Start a project from publishing boss requirement."""
|
||||
self.idea = idea
|
||||
self.environment.publish_message(Message(role=role, content=idea, cause_by=cause_by))
|
||||
self.environment.publish_message(Message(role="BOSS", content=idea, cause_by=BossRequirement))
|
||||
|
||||
def _save(self):
|
||||
logger.info(self.json())
|
||||
|
|
@ -67,13 +59,3 @@ class SoftwareCompany(BaseModel):
|
|||
self._check_balance()
|
||||
await self.environment.run()
|
||||
return self.environment.history
|
||||
|
||||
@property
|
||||
def max_budget(self):
|
||||
return self.options.get("max_budget", 0)
|
||||
|
||||
@property
|
||||
def total_cost(self):
|
||||
return self.options.get("total_cost", 0)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ import requests
|
|||
from pydantic import BaseModel
|
||||
import sys
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
|
||||
sys.path.append(str(Path(__file__).resolve().parent.parent.parent)) # fix-bug: No module named 'metagpt'
|
||||
from metagpt.utils.common import initialize_environment
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
|
|
@ -83,12 +84,11 @@ async def oas3_openai_text_to_embedding(text, model="text-embedding-ada-002", op
|
|||
if not text:
|
||||
return ""
|
||||
if not openai_api_key:
|
||||
openai_api_key = os.environ.get("OPENAI_API_KEY")
|
||||
openai_api_key = CONFIG.OPENAI_API_KEY
|
||||
return await OpenAIText2Embedding(openai_api_key).text_2_embedding(text, model=model)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
initialize_environment()
|
||||
loop = asyncio.new_event_loop()
|
||||
v = loop.create_task(oas3_openai_text_to_embedding("Panda emoji"))
|
||||
loop.run_until_complete(v)
|
||||
|
|
|
|||
|
|
@ -259,18 +259,3 @@ def parse_recipient(text):
|
|||
recipient = re.search(pattern, text)
|
||||
return recipient.group(1) if recipient else ""
|
||||
|
||||
|
||||
def initialize_environment(options=None):
|
||||
"""Load `config/config.yaml` to `os.environ`"""
|
||||
if options:
|
||||
for k, v in options.items():
|
||||
os.environ[k] = str(v)
|
||||
return
|
||||
|
||||
yaml_file_path = Path(__file__).resolve().parent.parent.parent / "config/config.yaml"
|
||||
if not yaml_file_path.exists():
|
||||
return
|
||||
with open(str(yaml_file_path), "r") as yaml_file:
|
||||
data = yaml.safe_load(yaml_file)
|
||||
for k, v in data.items():
|
||||
os.environ[k] = str(v)
|
||||
|
|
|
|||
16
startup.py
16
startup.py
|
|
@ -1,10 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Modified By: mashenquan, 2023/8/20. Remove global configuration `CONFIG`, enable configuration support for business isolation;
|
||||
Change cost control from global to company level.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import platform
|
||||
import fire
|
||||
|
|
@ -16,15 +11,14 @@ from metagpt.software_company import SoftwareCompany
|
|||
async def startup(idea: str, investment: float = 3.0, n_round: int = 5,
|
||||
code_review: bool = False, run_tests: bool = False):
|
||||
"""Run a startup. Be a boss."""
|
||||
|
||||
company = SoftwareCompany()
|
||||
company.hire([ProductManager(options=company.options, cost_manager=company.cost_manager),
|
||||
Architect(options=company.options, cost_manager=company.cost_manager),
|
||||
ProjectManager(options=company.options, cost_manager=company.cost_manager),
|
||||
Engineer(n_borg=5, use_code_review=code_review, options=company.options, cost_manager=company.cost_manager)])
|
||||
company.hire([ProductManager(),
|
||||
Architect(),
|
||||
ProjectManager(),
|
||||
Engineer(n_borg=5, use_code_review=code_review)])
|
||||
if run_tests:
|
||||
# developing features: run tests on the spot and identify bugs (bug fixing capability comes soon!)
|
||||
company.hire([QaEngineer(options=company.options, cost_manager=company.cost_manager)])
|
||||
company.hire([QaEngineer()])
|
||||
company.invest(investment)
|
||||
company.start_project(idea)
|
||||
await company.run(n_round=n_round)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue