mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-29 15:59:42 +02:00
修正
This commit is contained in:
parent
315fb65430
commit
041da760e0
147 changed files with 756 additions and 7644 deletions
|
|
@ -8,14 +8,12 @@ if sys.implementation.name == "cpython" and platform.system() == "Windows":
|
|||
if sys.version_info[:2] == (3, 9):
|
||||
from asyncio.proactor_events import _ProactorBasePipeTransport
|
||||
|
||||
|
||||
# https://github.com/python/cpython/pull/92842
|
||||
def pacth_del(self, _warn=warnings.warn):
|
||||
if self._sock is not None:
|
||||
_warn(f"unclosed transport {self!r}", ResourceWarning, source=self)
|
||||
self._sock.close()
|
||||
|
||||
|
||||
_ProactorBasePipeTransport.__del__ = pacth_del
|
||||
|
||||
if sys.version_info >= (3, 9, 0):
|
||||
|
|
|
|||
|
|
@ -51,12 +51,12 @@ class Action(ABC):
|
|||
|
||||
@retry(stop=stop_after_attempt(3), wait=wait_fixed(1))
|
||||
async def _aask_v1(
|
||||
self,
|
||||
prompt: str,
|
||||
output_class_name: str,
|
||||
output_data_mapping: dict,
|
||||
system_msgs: Optional[list[str]] = None,
|
||||
format="markdown", # compatible to original format
|
||||
self,
|
||||
prompt: str,
|
||||
output_class_name: str,
|
||||
output_data_mapping: dict,
|
||||
system_msgs: Optional[list[str]] = None,
|
||||
format="markdown", # compatible to original format
|
||||
) -> ActionOutput:
|
||||
"""Append default prefix"""
|
||||
if not system_msgs:
|
||||
|
|
|
|||
|
|
@ -40,3 +40,4 @@ class ActionOutput:
|
|||
new_class.__validator_check_name = classmethod(check_name)
|
||||
new_class.__root_validator_check_missing_fields = classmethod(check_missing_fields)
|
||||
return new_class
|
||||
|
||||
|
|
@ -10,6 +10,5 @@ from metagpt.actions import Action
|
|||
|
||||
class BossRequirement(Action):
|
||||
"""Boss Requirement without any implementation details"""
|
||||
|
||||
async def run(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import traceback
|
||||
from pathlib import Path
|
||||
import traceback
|
||||
|
||||
from metagpt.actions.write_code import WriteCode
|
||||
from metagpt.logs import logger
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
"""
|
||||
import re
|
||||
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.logs import logger
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.utils.common import CodeParser
|
||||
|
||||
PROMPT_TEMPLATE = """
|
||||
|
|
@ -24,8 +24,6 @@ The message is as follows:
|
|||
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, name="DebugError", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
|
@ -35,17 +33,17 @@ class DebugError(Action):
|
|||
# f"\n\n{error}\n\nPlease try to fix the error in this code."
|
||||
# fixed_code = await self._aask(prompt)
|
||||
# return fixed_code
|
||||
|
||||
|
||||
async def run(self, context):
|
||||
if "PASS" in context:
|
||||
return "", "the original code works fine, no need to debug"
|
||||
|
||||
|
||||
file_name = re.search("## File To Rewrite:\s*(.+\\.py)", context).group(1)
|
||||
|
||||
logger.info(f"Debug and rewrite {file_name}")
|
||||
|
||||
prompt = PROMPT_TEMPLATE.format(context=context)
|
||||
|
||||
|
||||
rsp = await self._aask(prompt)
|
||||
|
||||
code = CodeParser.parse_code(block="", text=rsp)
|
||||
|
|
|
|||
|
|
@ -19,3 +19,4 @@ class DesignReview(Action):
|
|||
|
||||
api_review = await self._aask(prompt)
|
||||
return api_review
|
||||
|
||||
|
|
@ -26,3 +26,4 @@ class DesignFilenames(Action):
|
|||
logger.debug(prompt)
|
||||
logger.debug(design_filenames)
|
||||
return design_filenames
|
||||
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
@File : detail_mining.py
|
||||
"""
|
||||
from metagpt.actions import Action, ActionOutput
|
||||
from metagpt.logs import logger
|
||||
|
||||
PROMPT_TEMPLATE = """
|
||||
##TOPIC
|
||||
|
|
@ -42,7 +43,6 @@ OUTPUT_MAPPING = {
|
|||
class DetailMining(Action):
|
||||
"""This class allows LLM to further mine noteworthy details based on specific "##TOPIC"(discussion topic) and "##RECORD" (discussion records), thereby deepening the discussion.
|
||||
"""
|
||||
|
||||
def __init__(self, name="", context=None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ Requirement: Provide a list of questions for the interviewer to ask the intervie
|
|||
Attention: Provide as markdown block as the format above, at least 10 questions.
|
||||
"""
|
||||
|
||||
|
||||
# prepare for a interview
|
||||
|
||||
|
||||
|
|
@ -39,3 +38,4 @@ class PrepareInterview(Action):
|
|||
prompt = PROMPT_TEMPLATE.format(context=context)
|
||||
question_list = await self._aask_v1(prompt)
|
||||
return question_list
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Callable
|
||||
|
||||
from pydantic import parse_obj_as
|
||||
|
|
@ -59,6 +60,7 @@ a comprehensive summary of the text.
|
|||
{content}
|
||||
'''
|
||||
|
||||
|
||||
CONDUCT_RESEARCH_PROMPT = '''### Reference Information
|
||||
{content}
|
||||
|
||||
|
|
@ -76,13 +78,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,
|
||||
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."
|
||||
|
|
@ -90,11 +91,11 @@ class CollectLinks(Action):
|
|||
self.rank_func = rank_func
|
||||
|
||||
async def run(
|
||||
self,
|
||||
topic: str,
|
||||
decomposition_nums: int = 4,
|
||||
url_per_query: int = 4,
|
||||
system_text: str | None = None,
|
||||
self,
|
||||
topic: str,
|
||||
decomposition_nums: int = 4,
|
||||
url_per_query: int = 4,
|
||||
system_text: str | None = None,
|
||||
) -> dict[str, list[str]]:
|
||||
"""Run the action to collect links.
|
||||
|
||||
|
|
@ -119,16 +120,13 @@ class CollectLinks(Action):
|
|||
|
||||
def gen_msg():
|
||||
while True:
|
||||
search_results = "\n".join(
|
||||
f"#### Keyword: {i}\n Search Result: {j}\n" for (i, j) in zip(keywords, results))
|
||||
prompt = SUMMARIZE_SEARCH_PROMPT.format(decomposition_nums=decomposition_nums,
|
||||
search_results=search_results)
|
||||
search_results = "\n".join(f"#### Keyword: {i}\n Search Result: {j}\n" for (i, j) in zip(keywords, results))
|
||||
prompt = SUMMARIZE_SEARCH_PROMPT.format(decomposition_nums=decomposition_nums, search_results=search_results)
|
||||
yield prompt
|
||||
remove = max(results, key=len)
|
||||
remove.pop()
|
||||
if len(remove) == 0:
|
||||
break
|
||||
|
||||
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])
|
||||
|
|
@ -174,12 +172,11 @@ 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,
|
||||
self,
|
||||
*args,
|
||||
browse_func: Callable[[list[str]], None] | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(*args, **kwargs)
|
||||
if CONFIG.model_for_researcher_summary:
|
||||
|
|
@ -191,11 +188,11 @@ class WebBrowseAndSummarize(Action):
|
|||
self.desc = "Explore the web and provide summaries of articles and webpages."
|
||||
|
||||
async def run(
|
||||
self,
|
||||
url: str,
|
||||
*urls: str,
|
||||
query: str,
|
||||
system_text: str = RESEARCH_BASE_SYSTEM,
|
||||
self,
|
||||
url: str,
|
||||
*urls: str,
|
||||
query: str,
|
||||
system_text: str = RESEARCH_BASE_SYSTEM,
|
||||
) -> dict[str, str]:
|
||||
"""Run the action to browse the web and provide summaries.
|
||||
|
||||
|
|
@ -217,8 +214,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,
|
||||
CONFIG.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.":
|
||||
|
|
@ -242,17 +238,16 @@ 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)
|
||||
if CONFIG.model_for_researcher_report:
|
||||
self.llm.model = CONFIG.model_for_researcher_report
|
||||
|
||||
async def run(
|
||||
self,
|
||||
topic: str,
|
||||
content: str,
|
||||
system_text: str = RESEARCH_BASE_SYSTEM,
|
||||
self,
|
||||
topic: str,
|
||||
content: str,
|
||||
system_text: str = RESEARCH_BASE_SYSTEM,
|
||||
) -> str:
|
||||
"""Run the action to conduct research and generate a research report.
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class RunCode(Action):
|
|||
return stdout.decode("utf-8"), stderr.decode("utf-8")
|
||||
|
||||
async def run(
|
||||
self, code, mode="script", code_file_name="", test_code="", test_file_name="", command=[], **kwargs
|
||||
self, code, mode="script", code_file_name="", test_code="", test_file_name="", command=[], **kwargs
|
||||
) -> str:
|
||||
logger.info(f"Running {' '.join(command)}")
|
||||
if mode == "script":
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ SEARCH_AND_SUMMARIZE_PROMPT = """
|
|||
|
||||
"""
|
||||
|
||||
|
||||
SEARCH_AND_SUMMARIZE_SALES_SYSTEM = """## Requirements
|
||||
1. Please summarize the latest dialogue based on the reference information (secondary) and dialogue history (primary). Do not include text that is irrelevant to the conversation.
|
||||
- The context is for reference only. If it is irrelevant to the user's search request history, please reduce its reference and usage.
|
||||
|
|
@ -139,3 +140,4 @@ class SearchAndSummarize(Action):
|
|||
logger.debug(prompt)
|
||||
logger.debug(result)
|
||||
return result
|
||||
|
||||
|
|
@ -5,14 +5,13 @@
|
|||
@Author : alexanderwu
|
||||
@File : write_code.py
|
||||
"""
|
||||
from tenacity import retry, stop_after_attempt, wait_fixed
|
||||
|
||||
from metagpt.actions import WriteDesign
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.const import WORKSPACE_ROOT
|
||||
from metagpt.logs import logger
|
||||
from metagpt.schema import Message
|
||||
from metagpt.utils.common import CodeParser
|
||||
from tenacity import retry, stop_after_attempt, wait_fixed
|
||||
|
||||
PROMPT_TEMPLATE = """
|
||||
NOTICE
|
||||
|
|
@ -80,3 +79,4 @@ class WriteCode(Action):
|
|||
# code_rsp = await self._aask_v1(prompt, "code_rsp", OUTPUT_MAPPING)
|
||||
# self._save(context, filename, code)
|
||||
return code
|
||||
|
||||
|
|
@ -6,12 +6,11 @@
|
|||
@File : write_code_review.py
|
||||
"""
|
||||
|
||||
from tenacity import retry, stop_after_attempt, wait_fixed
|
||||
|
||||
from metagpt.actions.action import Action
|
||||
from metagpt.logs import logger
|
||||
from metagpt.schema import Message
|
||||
from metagpt.utils.common import CodeParser
|
||||
from tenacity import retry, stop_after_attempt, wait_fixed
|
||||
|
||||
PROMPT_TEMPLATE = """
|
||||
NOTICE
|
||||
|
|
@ -80,3 +79,4 @@ class WriteCodeReview(Action):
|
|||
# code_rsp = await self._aask_v1(prompt, "code_rsp", OUTPUT_MAPPING)
|
||||
# self._save(context, filename, code)
|
||||
return code
|
||||
|
||||
|
|
@ -162,9 +162,9 @@ class WriteDocstring(Action):
|
|||
self.desc = "Write docstring for code."
|
||||
|
||||
async def run(
|
||||
self, code: str,
|
||||
system_text: str = PYTHON_DOCSTRING_SYSTEM,
|
||||
style: Literal["google", "numpy", "sphinx"] = "google",
|
||||
self, code: str,
|
||||
system_text: str = PYTHON_DOCSTRING_SYSTEM,
|
||||
style: Literal["google", "numpy", "sphinx"] = "google",
|
||||
) -> str:
|
||||
"""Writes docstrings for the given code and system text in the specified style.
|
||||
|
||||
|
|
@ -202,7 +202,6 @@ def _simplify_python_code(code: str) -> None:
|
|||
if __name__ == "__main__":
|
||||
import fire
|
||||
|
||||
|
||||
async def run(filename: str, overwrite: bool = False, style: Literal["google", "numpy", "sphinx"] = "google"):
|
||||
with open(filename) as f:
|
||||
code = f.read()
|
||||
|
|
@ -212,5 +211,4 @@ if __name__ == "__main__":
|
|||
f.write(code)
|
||||
return code
|
||||
|
||||
|
||||
fire.Fire(run)
|
||||
|
|
|
|||
|
|
@ -25,3 +25,4 @@ class WritePRDReview(Action):
|
|||
prompt = self.prd_review_prompt_template.format(prd=self.prd)
|
||||
review = await self._aask(prompt)
|
||||
return review
|
||||
|
||||
|
|
@ -65,3 +65,4 @@ class WriteContent(Action):
|
|||
"""
|
||||
prompt = CONTENT_PROMPT.format(topic=topic, language=self.language, directory=self.directory)
|
||||
return await self._aask(prompt=prompt)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ def get_project_root():
|
|||
current_path = Path.cwd()
|
||||
while True:
|
||||
if (
|
||||
(current_path / ".git").exists()
|
||||
or (current_path / ".project_root").exists()
|
||||
or (current_path / ".gitignore").exists()
|
||||
(current_path / ".git").exists()
|
||||
or (current_path / ".project_root").exists()
|
||||
or (current_path / ".gitignore").exists()
|
||||
):
|
||||
return current_path
|
||||
parent_path = current_path.parent
|
||||
|
|
|
|||
|
|
@ -53,3 +53,4 @@ class LocalStore(BaseStore, ABC):
|
|||
@abstractmethod
|
||||
def _write(self, docs, metadatas):
|
||||
raise NotImplementedError
|
||||
|
||||
|
|
@ -10,7 +10,6 @@ import chromadb
|
|||
|
||||
class ChromaStore:
|
||||
"""If inherited from BaseStore, or importing other modules from metagpt, a Python exception occurs, which is strange."""
|
||||
|
||||
def __init__(self, name):
|
||||
client = chromadb.Client()
|
||||
collection = client.create_collection(name)
|
||||
|
|
|
|||
|
|
@ -79,3 +79,4 @@ class Document:
|
|||
return self._get_docs_and_metadatas_by_langchain()
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
|
|
@ -38,11 +38,11 @@ class QdrantStore(BaseStore):
|
|||
raise Exception("please check QdrantConnection.")
|
||||
|
||||
def create_collection(
|
||||
self,
|
||||
collection_name: str,
|
||||
vectors_config: VectorParams,
|
||||
force_recreate=False,
|
||||
**kwargs,
|
||||
self,
|
||||
collection_name: str,
|
||||
vectors_config: VectorParams,
|
||||
force_recreate=False,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
create a collection
|
||||
|
|
@ -97,12 +97,12 @@ class QdrantStore(BaseStore):
|
|||
)
|
||||
|
||||
def search(
|
||||
self,
|
||||
collection_name: str,
|
||||
query: List[float],
|
||||
query_filter: Filter = None,
|
||||
k=10,
|
||||
return_vector=False,
|
||||
self,
|
||||
collection_name: str,
|
||||
query: List[float],
|
||||
query_filter: Filter = None,
|
||||
k=10,
|
||||
return_vector=False,
|
||||
):
|
||||
"""
|
||||
vector search
|
||||
|
|
|
|||
|
|
@ -25,4 +25,4 @@ def print_classes_and_functions(module):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print_classes_and_functions(metagpt)
|
||||
print_classes_and_functions(metagpt)
|
||||
|
|
@ -12,7 +12,6 @@ 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
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ from loguru import logger as _logger
|
|||
|
||||
from metagpt.const import PROJECT_ROOT
|
||||
|
||||
|
||||
def define_log_level(print_level="INFO", logfile_level="DEBUG"):
|
||||
"""调整日志级别到level之上
|
||||
Adjust the log level to above level
|
||||
|
|
@ -22,5 +21,4 @@ def define_log_level(print_level="INFO", logfile_level="DEBUG"):
|
|||
_logger.add(PROJECT_ROOT / 'logs/log.txt', level=logfile_level)
|
||||
return _logger
|
||||
|
||||
|
||||
logger = define_log_level()
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class Manager:
|
|||
# chosen_role_name = self.llm.ask(self.prompt_template.format(context))
|
||||
|
||||
# FIXME: 现在通过简单的字典决定流向,但之后还是应该有思考过程
|
||||
# The direction of flow is now determined by a simple dictionary, but there should still be a thought process afterwards
|
||||
#The direction of flow is now determined by a simple dictionary, but there should still be a thought process afterwards
|
||||
next_role_profile = self.role_directions[message.role]
|
||||
# logger.debug(f"{next_role_profile}")
|
||||
for _, role in roles.items():
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@
|
|||
@File : __init__.py
|
||||
"""
|
||||
|
||||
from metagpt.memory.longterm_memory import LongTermMemory
|
||||
from metagpt.memory.memory import Memory
|
||||
from metagpt.memory.longterm_memory import LongTermMemory
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Memory",
|
||||
|
|
|
|||
|
|
@ -68,3 +68,4 @@ class LongTermMemory(Memory):
|
|||
def clear(self):
|
||||
super(LongTermMemory, self).clear()
|
||||
self.memory_storage.clean()
|
||||
|
||||
|
|
@ -85,3 +85,4 @@ class Memory:
|
|||
continue
|
||||
rsp += self.index[action]
|
||||
return rsp
|
||||
|
||||
|
|
@ -2,16 +2,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# @Desc : the implement of memory storage
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
from pathlib import Path
|
||||
|
||||
from langchain.vectorstores.faiss import FAISS
|
||||
|
||||
from metagpt.const import DATA_PATH, MEM_TTL
|
||||
from metagpt.document_store.faiss_store import FaissStore
|
||||
from metagpt.logs import logger
|
||||
from metagpt.schema import Message
|
||||
from metagpt.utils.serialize import serialize_message, deserialize_message
|
||||
from metagpt.document_store.faiss_store import FaissStore
|
||||
|
||||
|
||||
class MemoryStorage(FaissStore):
|
||||
|
|
@ -104,3 +104,4 @@ class MemoryStorage(FaissStore):
|
|||
|
||||
self.store = None
|
||||
self._initialized = False
|
||||
|
||||
|
|
@ -16,6 +16,7 @@ The requirements of the tree-structure plan are:
|
|||
4. The sub-goals at the bottom level should be basic actions so that I can easily execute them in the game.
|
||||
"""
|
||||
|
||||
|
||||
DECOMPOSE_USER = """USER:
|
||||
The goal is to {goal description}. Generate the plan according to the requirements.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -66,10 +66,9 @@ # PRD
|
|||
return prd
|
||||
```
|
||||
|
||||
|
||||
The main class/function is WritePRD.
|
||||
|
||||
Then you should write:
|
||||
|
||||
This class is designed to generate a PRD based on input requirements. Notably, there's a template prompt with sections
|
||||
for product, function, goals, user scenarios, requirements, constraints, performance metrics. This template gets filled
|
||||
with input requirements and then queries a big language model to produce the detailed PRD.
|
||||
This class is designed to generate a PRD based on input requirements. Notably, there's a template prompt with sections for product, function, goals, user scenarios, requirements, constraints, performance metrics. This template gets filled with input requirements and then queries a big language model to produce the detailed PRD.
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
@File : sales.py
|
||||
"""
|
||||
|
||||
|
||||
SALES_ASSISTANT = """You are a sales assistant helping your sales agent to determine which stage of a sales conversation should the agent move to, or stay at.
|
||||
Following '===' is the conversation history.
|
||||
Use this conversation history to make your decision.
|
||||
|
|
@ -28,6 +29,7 @@ The answer needs to be one number only, no words.
|
|||
If there is no conversation history, output 1.
|
||||
Do not answer anything else nor add anything to you answer."""
|
||||
|
||||
|
||||
SALES = """Never forget your name is {salesperson_name}. You work as a {salesperson_role}.
|
||||
You work at company named {company_name}. {company_name}'s business is the following: {company_business}
|
||||
Company values are the following. {company_values}
|
||||
|
|
@ -52,11 +54,10 @@ Conversation history:
|
|||
{salesperson_name}:
|
||||
"""
|
||||
|
||||
conversation_stages = {
|
||||
'1': "Introduction: Start the conversation by introducing yourself and your company. Be polite and respectful while keeping the tone of the conversation professional. Your greeting should be welcoming. Always clarify in your greeting the reason why you are contacting the prospect.",
|
||||
'2': "Qualification: Qualify the prospect by confirming if they are the right person to talk to regarding your product/service. Ensure that they have the authority to make purchasing decisions.",
|
||||
'3': "Value proposition: Briefly explain how your product/service can benefit the prospect. Focus on the unique selling points and value proposition of your product/service that sets it apart from competitors.",
|
||||
'4': "Needs analysis: Ask open-ended questions to uncover the prospect's needs and pain points. Listen carefully to their responses and take notes.",
|
||||
'5': "Solution presentation: Based on the prospect's needs, present your product/service as the solution that can address their pain points.",
|
||||
'6': "Objection handling: Address any objections that the prospect may have regarding your product/service. Be prepared to provide evidence or testimonials to support your claims.",
|
||||
'7': "Close: Ask for the sale by proposing a next step. This could be a demo, a trial or a meeting with decision-makers. Ensure to summarize what has been discussed and reiterate the benefits."}
|
||||
conversation_stages = {'1' : "Introduction: Start the conversation by introducing yourself and your company. Be polite and respectful while keeping the tone of the conversation professional. Your greeting should be welcoming. Always clarify in your greeting the reason why you are contacting the prospect.",
|
||||
'2': "Qualification: Qualify the prospect by confirming if they are the right person to talk to regarding your product/service. Ensure that they have the authority to make purchasing decisions.",
|
||||
'3': "Value proposition: Briefly explain how your product/service can benefit the prospect. Focus on the unique selling points and value proposition of your product/service that sets it apart from competitors.",
|
||||
'4': "Needs analysis: Ask open-ended questions to uncover the prospect's needs and pain points. Listen carefully to their responses and take notes.",
|
||||
'5': "Solution presentation: Based on the prospect's needs, present your product/service as the solution that can address their pain points.",
|
||||
'6': "Objection handling: Address any objections that the prospect may have regarding your product/service. Be prepared to provide evidence or testimonials to support your claims.",
|
||||
'7': "Close: Ask for the sale by proposing a next step. This could be a demo, a trial or a meeting with decision-makers. Ensure to summarize what has been discussed and reiterate the benefits."}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ summary. Pick a suitable emoji for every bullet point. Your response should be i
|
|||
a YouTube video, use the following text: {{CONTENT}}.
|
||||
"""
|
||||
|
||||
|
||||
# GCP-VertexAI-Text Summarization (SUMMARIZE_PROMPT_2-5 are from this source)
|
||||
# https://github.com/GoogleCloudPlatform/generative-ai/blob/main/language/examples/prompt-design/text_summarization.ipynb
|
||||
# Long documents require a map-reduce process, see the following notebook
|
||||
|
|
@ -38,6 +39,7 @@ Summary:
|
|||
|
||||
"""
|
||||
|
||||
|
||||
SUMMARIZE_PROMPT_3 = """
|
||||
Provide a TL;DR for the following article:
|
||||
|
||||
|
|
@ -51,6 +53,7 @@ Instead of computing on the individual qubits themselves, we will then compute o
|
|||
TL;DR:
|
||||
"""
|
||||
|
||||
|
||||
SUMMARIZE_PROMPT_4 = """
|
||||
Provide a very short summary in four bullet points for the following article:
|
||||
|
||||
|
|
@ -65,6 +68,7 @@ Bulletpoints:
|
|||
|
||||
"""
|
||||
|
||||
|
||||
SUMMARIZE_PROMPT_5 = """
|
||||
Please generate a summary of the following conversation and at the end summarize the to-do's for the support Agent:
|
||||
|
||||
|
|
|
|||
|
|
@ -36,4 +36,4 @@ Strictly limit output according to the following requirements:
|
|||
3. The output must be strictly in the specified language, {language}.
|
||||
4. Do not have redundant output, including concluding remarks.
|
||||
5. Strict requirement not to output the topic "{topic}".
|
||||
"""
|
||||
"""
|
||||
|
|
@ -73,6 +73,7 @@ The action_list can contain arbitrary number of actions. The args of each action
|
|||
6. I will execute your code step by step and give you feedback. If some action fails, I will stop at that action and will not execute its following actions. The feedback will include error messages about the failed action. At that time, you should replan and write the new code just starting from that failed action.
|
||||
"""
|
||||
|
||||
|
||||
SOP_USER = """USER:
|
||||
My current state:
|
||||
- inventory: {inventory}
|
||||
|
|
|
|||
|
|
@ -8,4 +8,5 @@
|
|||
|
||||
from metagpt.provider.openai_api import OpenAIGPTAPI
|
||||
|
||||
|
||||
__all__ = ["OpenAIGPTAPI"]
|
||||
|
|
|
|||
|
|
@ -32,3 +32,4 @@ class Claude2:
|
|||
max_tokens_to_sample=1000,
|
||||
)
|
||||
return res.completion
|
||||
|
||||
|
|
@ -25,3 +25,4 @@ class BaseChatbot(ABC):
|
|||
@abstractmethod
|
||||
def ask_code(self, msgs: list) -> str:
|
||||
"""Ask GPT multiple questions and get a piece of code"""
|
||||
|
||||
|
|
@ -115,3 +115,4 @@ class BaseGPTAPI(BaseChatbot):
|
|||
def messages_to_dict(self, messages):
|
||||
"""objects to [{"role": "user", "content": msg}] etc."""
|
||||
return [i.to_dict() for i in messages]
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ class RateLimiter:
|
|||
self.rpm = rpm
|
||||
|
||||
def split_batches(self, batch):
|
||||
return [batch[i: i + self.rpm] for i in range(0, len(batch), self.rpm)]
|
||||
return [batch[i : i + self.rpm] for i in range(0, len(batch), self.rpm)]
|
||||
|
||||
async def wait_if_needed(self, num_requests):
|
||||
current_time = time.time()
|
||||
|
|
@ -83,9 +83,8 @@ class CostManager(metaclass=Singleton):
|
|||
self.total_prompt_tokens += prompt_tokens
|
||||
self.total_completion_tokens += completion_tokens
|
||||
cost = (
|
||||
prompt_tokens * TOKEN_COSTS[model]["prompt"] + completion_tokens * TOKEN_COSTS[model][
|
||||
"completion"]
|
||||
) / 1000
|
||||
prompt_tokens * TOKEN_COSTS[model]["prompt"] + completion_tokens * TOKEN_COSTS[model]["completion"]
|
||||
) / 1000
|
||||
self.total_cost += cost
|
||||
logger.info(
|
||||
f"Total running cost: ${self.total_cost:.3f} | Max budget: ${CONFIG.max_budget:.3f} | "
|
||||
|
|
|
|||
|
|
@ -6,15 +6,16 @@
|
|||
@File : __init__.py
|
||||
"""
|
||||
|
||||
from metagpt.roles.architect import Architect
|
||||
from metagpt.roles.customer_service import CustomerService
|
||||
from metagpt.roles.engineer import Engineer
|
||||
from metagpt.roles.product_manager import ProductManager
|
||||
from metagpt.roles.project_manager import ProjectManager
|
||||
from metagpt.roles.qa_engineer import QaEngineer
|
||||
from metagpt.roles.role import Role
|
||||
from metagpt.roles.sales import Sales
|
||||
from metagpt.roles.architect import Architect
|
||||
from metagpt.roles.project_manager import ProjectManager
|
||||
from metagpt.roles.product_manager import ProductManager
|
||||
from metagpt.roles.engineer import Engineer
|
||||
from metagpt.roles.qa_engineer import QaEngineer
|
||||
from metagpt.roles.seacher import Searcher
|
||||
from metagpt.roles.sales import Sales
|
||||
from metagpt.roles.customer_service import CustomerService
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Role",
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ class Architect(Role):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "Bob",
|
||||
profile: str = "Architect",
|
||||
goal: str = "Design a concise, usable, complete python system",
|
||||
constraints: str = "Try to specify good open source tools as much as possible",
|
||||
self,
|
||||
name: str = "Bob",
|
||||
profile: str = "Architect",
|
||||
goal: str = "Design a concise, usable, complete python system",
|
||||
constraints: str = "Try to specify good open source tools as much as possible",
|
||||
) -> None:
|
||||
"""Initializes the Architect with given attributes."""
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
|
|
|
|||
|
|
@ -32,3 +32,4 @@ class CustomerService(Sales):
|
|||
store=None
|
||||
):
|
||||
super().__init__(name, profile, desc=desc, store=store)
|
||||
|
||||
|
|
@ -61,13 +61,13 @@ class Engineer(Role):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "Alex",
|
||||
profile: str = "Engineer",
|
||||
goal: str = "Write elegant, readable, extensible, efficient code",
|
||||
constraints: str = "The code should conform to standards like PEP8 and be modular and maintainable",
|
||||
n_borg: int = 1,
|
||||
use_code_review: bool = False,
|
||||
self,
|
||||
name: str = "Alex",
|
||||
profile: str = "Engineer",
|
||||
goal: str = "Write elegant, readable, extensible, efficient code",
|
||||
constraints: str = "The code should conform to standards like PEP8 and be modular and maintainable",
|
||||
n_borg: int = 1,
|
||||
use_code_review: bool = False,
|
||||
) -> None:
|
||||
"""Initializes the Engineer role with given attributes."""
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ class ProductManager(Role):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "Alice",
|
||||
profile: str = "Product Manager",
|
||||
goal: str = "Efficiently create a successful product",
|
||||
constraints: str = "",
|
||||
self,
|
||||
name: str = "Alice",
|
||||
profile: str = "Product Manager",
|
||||
goal: str = "Efficiently create a successful product",
|
||||
constraints: str = "",
|
||||
) -> None:
|
||||
"""
|
||||
Initializes the ProductManager role with given attributes.
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ class ProjectManager(Role):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "Eve",
|
||||
profile: str = "Project Manager",
|
||||
goal: str = "Improve team efficiency and deliver with quality and quantity",
|
||||
constraints: str = "",
|
||||
self,
|
||||
name: str = "Eve",
|
||||
profile: str = "Project Manager",
|
||||
goal: str = "Improve team efficiency and deliver with quality and quantity",
|
||||
constraints: str = "",
|
||||
) -> None:
|
||||
"""
|
||||
Initializes the ProjectManager role with given attributes.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ SUFFIX = """Let's begin!
|
|||
Question: {input}
|
||||
Thoughts: {agent_scratchpad}"""
|
||||
|
||||
|
||||
class PromptString(Enum):
|
||||
REFLECTION_QUESTIONS = "Here are some statements:\n{memory_descriptions}\n\nBased solely on the information above, what are the 3 most prominent high-level questions we can answer about the topic in the statements?\n\n{format_instructions}"
|
||||
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ from metagpt.utils.special_tokens import FILENAME_CODE_SEP, MSG_SEP
|
|||
|
||||
class QaEngineer(Role):
|
||||
def __init__(
|
||||
self,
|
||||
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,
|
||||
self,
|
||||
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, profile, goal, constraints)
|
||||
self._init_actions(
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ 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,
|
||||
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)])
|
||||
|
|
@ -93,10 +93,8 @@ class Researcher(Role):
|
|||
if __name__ == "__main__":
|
||||
import fire
|
||||
|
||||
|
||||
async def main(topic: str, language="en-us"):
|
||||
role = Researcher(topic, language=language)
|
||||
await role.run(topic)
|
||||
|
||||
|
||||
fire.Fire(main)
|
||||
|
|
|
|||
|
|
@ -32,3 +32,4 @@ class Sales(Role):
|
|||
else:
|
||||
action = SearchAndSummarize()
|
||||
self._init_actions([action])
|
||||
|
||||
|
|
@ -23,13 +23,13 @@ class Searcher(Role):
|
|||
constraints (str): Constraints or limitations for the searcher.
|
||||
engine (SearchEngineType): The type of search engine to use.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
name: str = 'Alice',
|
||||
profile: str = 'Smart Assistant',
|
||||
|
||||
def __init__(self,
|
||||
name: str = 'Alice',
|
||||
profile: str = 'Smart Assistant',
|
||||
goal: str = 'Provide search services for users',
|
||||
constraints: str = 'Answer is rich and complete',
|
||||
engine=SearchEngineType.SERPAPI_GOOGLE,
|
||||
constraints: str = 'Answer is rich and complete',
|
||||
engine=SearchEngineType.SERPAPI_GOOGLE,
|
||||
**kwargs) -> None:
|
||||
"""
|
||||
Initializes the Searcher role with given attributes.
|
||||
|
|
@ -53,7 +53,7 @@ class Searcher(Role):
|
|||
"""Performs the search action in a single process."""
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
response = await self._rc.todo.run(self._rc.memory.get(k=0))
|
||||
|
||||
|
||||
if isinstance(response, ActionOutput):
|
||||
msg = Message(content=response.content, instruct_content=response.instruct_content,
|
||||
role=self.profile, cause_by=type(self._rc.todo))
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ class SkAgent(Role):
|
|||
"""
|
||||
|
||||
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,
|
||||
self,
|
||||
name: str = "Sunshine",
|
||||
profile: str = "sk_agent",
|
||||
goal: str = "Execute task based on passed in task description",
|
||||
constraints: str = "",
|
||||
planner_cls=BasicPlanner,
|
||||
) -> None:
|
||||
"""Initializes the Engineer role with given attributes."""
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ class TutorialAssistant(Role):
|
|||
"""
|
||||
|
||||
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",
|
||||
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)])
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ class UserMessage(Message):
|
|||
"""便于支持OpenAI的消息
|
||||
Facilitate support for OpenAI messages
|
||||
"""
|
||||
|
||||
def __init__(self, content: str):
|
||||
super().__init__(content, 'user')
|
||||
|
||||
|
|
@ -60,7 +59,6 @@ class SystemMessage(Message):
|
|||
"""便于支持OpenAI的消息
|
||||
Facilitate support for OpenAI messages
|
||||
"""
|
||||
|
||||
def __init__(self, content: str):
|
||||
super().__init__(content, 'system')
|
||||
|
||||
|
|
@ -70,7 +68,6 @@ class AIMessage(Message):
|
|||
"""便于支持OpenAI的消息
|
||||
Facilitate support for OpenAI messages
|
||||
"""
|
||||
|
||||
def __init__(self, content: str):
|
||||
super().__init__(content, 'assistant')
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@
|
|||
"top_p": 1.0,
|
||||
"presence_penalty": 0.0,
|
||||
"frequency_penalty": 0.0,
|
||||
"stop_sequences": [
|
||||
"##END##"
|
||||
]
|
||||
"stop_sequences": ["##END##"]
|
||||
},
|
||||
"input": {
|
||||
"parameters": [
|
||||
|
|
|
|||
|
|
@ -59,3 +59,4 @@ class SoftwareCompany(BaseModel):
|
|||
self._check_balance()
|
||||
await self.environment.run()
|
||||
return self.environment.history
|
||||
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
@File : __init__.py
|
||||
"""
|
||||
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
import inspect
|
||||
import re
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
from typing import List, Callable
|
||||
from pathlib import Path
|
||||
|
||||
import wrapt
|
||||
import textwrap
|
||||
import inspect
|
||||
from interpreter.interpreter import Interpreter
|
||||
|
||||
from metagpt.actions.clone_function import CloneFunction, run_function_code, run_function_script
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.logs import logger
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.utils.highlight import highlight
|
||||
from metagpt.actions.clone_function import CloneFunction, run_function_code, run_function_script
|
||||
|
||||
|
||||
def extract_python_code(code: str):
|
||||
|
|
@ -36,7 +36,6 @@ def extract_python_code(code: str):
|
|||
|
||||
class OpenCodeInterpreter(object):
|
||||
"""https://github.com/KillianLucas/open-interpreter"""
|
||||
|
||||
def __init__(self, auto_run: bool = True) -> None:
|
||||
interpreter = Interpreter()
|
||||
interpreter.auto_run = auto_run
|
||||
|
|
@ -127,5 +126,4 @@ class OpenInterpreterDecorator(object):
|
|||
except Exception as e:
|
||||
raise Exception("Could not evaluate Python code", e)
|
||||
return res
|
||||
|
||||
return wrapper(wrapped)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ from typing import Union
|
|||
|
||||
class GPTPromptGenerator:
|
||||
"""Using LLM, given an output, request LLM to provide input (supporting instruction, chatbot, and query styles)"""
|
||||
|
||||
def __init__(self):
|
||||
self._generators = {i: getattr(self, f"gen_{i}_style") for i in ['instruction', 'chatbot', 'query']}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import os
|
|||
from os.path import join
|
||||
from typing import List
|
||||
|
||||
from PIL import Image, PngImagePlugin
|
||||
from aiohttp import ClientSession
|
||||
from PIL import Image, PngImagePlugin
|
||||
|
||||
from metagpt.config import Config
|
||||
from metagpt.const import WORKSPACE_ROOT
|
||||
|
|
@ -64,12 +64,12 @@ class SDEngine:
|
|||
logger.info(self.sd_t2i_url)
|
||||
|
||||
def construct_payload(
|
||||
self,
|
||||
prompt,
|
||||
negtive_prompt=default_negative_prompt,
|
||||
width=512,
|
||||
height=512,
|
||||
sd_model="galaxytimemachinesGTM_photoV20",
|
||||
self,
|
||||
prompt,
|
||||
negtive_prompt=default_negative_prompt,
|
||||
width=512,
|
||||
height=512,
|
||||
sd_model="galaxytimemachinesGTM_photoV20",
|
||||
):
|
||||
# Configure the payload with provided inputs
|
||||
self.payload["prompt"] = prompt
|
||||
|
|
@ -120,13 +120,11 @@ def decode_base64_to_image(img, save_name):
|
|||
image.save(f"{save_name}.png", pnginfo=pnginfo)
|
||||
return pnginfo, image
|
||||
|
||||
|
||||
def batch_decode_base64_to_image(imgs, save_dir="", save_name=""):
|
||||
for idx, _img in enumerate(imgs):
|
||||
save_name = join(save_dir, save_name)
|
||||
decode_base64_to_image(_img, save_name=save_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
engine = SDEngine()
|
||||
prompt = "pixel style, game design, a game interface should be minimalistic and intuitive with the score and high score displayed at the top. The snake and its food should be easily distinguishable. The game should have a simple color scheme, with a contrasting color for the snake and its food. Complete interface boundary"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class SkSearchEngine:
|
|||
|
||||
@sk_function(
|
||||
description="searches results from Google. Useful when you need to find short "
|
||||
"and succinct answers about a specific topic. Input should be a search query.",
|
||||
"and succinct answers about a specific topic. Input should be a search query.",
|
||||
name="searchAsync",
|
||||
input_description="search",
|
||||
)
|
||||
|
|
@ -42,7 +42,7 @@ class SearchEngine:
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
self,
|
||||
engine: Optional[SearchEngineType] = None,
|
||||
run_func: Callable[[str, int, bool], Coroutine[None, None, Union[str, list[str]]]] = None,
|
||||
):
|
||||
|
|
@ -68,19 +68,19 @@ class SearchEngine:
|
|||
|
||||
@overload
|
||||
def run(
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: Literal[True] = True,
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: Literal[True] = True,
|
||||
) -> str:
|
||||
...
|
||||
|
||||
@overload
|
||||
def run(
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: Literal[False] = False,
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: Literal[False] = False,
|
||||
) -> list[dict[str, str]]:
|
||||
...
|
||||
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ class DDGAPIWrapper:
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
loop: asyncio.AbstractEventLoop | None = None,
|
||||
executor: futures.Executor | None = None,
|
||||
self,
|
||||
*,
|
||||
loop: asyncio.AbstractEventLoop | None = None,
|
||||
executor: futures.Executor | None = None,
|
||||
):
|
||||
kwargs = {}
|
||||
if CONFIG.global_proxy:
|
||||
|
|
@ -39,29 +39,29 @@ class DDGAPIWrapper:
|
|||
|
||||
@overload
|
||||
def run(
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: Literal[True] = True,
|
||||
focus: list[str] | None = None,
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: Literal[True] = True,
|
||||
focus: list[str] | None = None,
|
||||
) -> str:
|
||||
...
|
||||
|
||||
@overload
|
||||
def run(
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: Literal[False] = False,
|
||||
focus: list[str] | None = None,
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: Literal[False] = False,
|
||||
focus: list[str] | None = None,
|
||||
) -> list[dict[str, str]]:
|
||||
...
|
||||
|
||||
async def run(
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: bool = True,
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: bool = True,
|
||||
) -> str | list[dict]:
|
||||
"""Return the results of a Google search using the official Google API
|
||||
|
||||
|
|
|
|||
|
|
@ -76,11 +76,11 @@ class GoogleAPIWrapper(BaseModel):
|
|||
return service.cse()
|
||||
|
||||
async def run(
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: bool = True,
|
||||
focus: list[str] | None = None,
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 8,
|
||||
as_string: bool = True,
|
||||
focus: list[str] | None = None,
|
||||
) -> str | list[dict]:
|
||||
"""Return the results of a Google search using the official Google API.
|
||||
|
||||
|
|
|
|||
|
|
@ -24,4 +24,4 @@ class Translator:
|
|||
|
||||
@classmethod
|
||||
def translate_prompt(cls, original, lang='中文'):
|
||||
return prompt.format(LANG=lang, ORIGINAL=original)
|
||||
return prompt.format(LANG=lang, ORIGINAL=original)
|
||||
|
|
@ -12,9 +12,9 @@ from metagpt.utils.parse_html import WebPage
|
|||
|
||||
class WebBrowserEngine:
|
||||
def __init__(
|
||||
self,
|
||||
engine: WebBrowserEngineType | None = None,
|
||||
run_func: Callable[..., Coroutine[Any, Any, WebPage | list[WebPage]]] | None = None,
|
||||
self,
|
||||
engine: WebBrowserEngineType | None = None,
|
||||
run_func: Callable[..., Coroutine[Any, Any, WebPage | list[WebPage]]] | None = None,
|
||||
):
|
||||
engine = engine or CONFIG.web_browser_engine
|
||||
|
||||
|
|
@ -46,9 +46,7 @@ class WebBrowserEngine:
|
|||
if __name__ == "__main__":
|
||||
import fire
|
||||
|
||||
|
||||
async def main(url: str, *urls: str, engine_type: Literal["playwright", "selenium"] = "playwright", **kwargs):
|
||||
return await WebBrowserEngine(WebBrowserEngineType(engine_type), **kwargs).run(url, *urls)
|
||||
|
||||
|
||||
fire.Fire(main)
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ class PlaywrightWrapper:
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
browser_type: Literal["chromium", "firefox", "webkit"] | None = None,
|
||||
launch_kwargs: dict | None = None,
|
||||
**kwargs,
|
||||
self,
|
||||
browser_type: Literal["chromium", "firefox", "webkit"] | None = None,
|
||||
launch_kwargs: dict | None = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
if browser_type is None:
|
||||
browser_type = CONFIG.playwright_browser_type
|
||||
|
|
@ -139,12 +139,11 @@ async def _log_stream(sr, log_func):
|
|||
_install_lock: asyncio.Lock = None
|
||||
_install_cache = set()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import fire
|
||||
|
||||
|
||||
async def main(url: str, *urls: str, browser_type: str = "chromium", **kwargs):
|
||||
return await PlaywrightWrapper(browser_type, **kwargs).run(url, *urls)
|
||||
|
||||
|
||||
fire.Fire(main)
|
||||
|
|
|
|||
|
|
@ -28,12 +28,12 @@ class SeleniumWrapper:
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
browser_type: Literal["chrome", "firefox", "edge", "ie"] | None = None,
|
||||
launch_kwargs: dict | None = None,
|
||||
*,
|
||||
loop: asyncio.AbstractEventLoop | None = None,
|
||||
executor: futures.Executor | None = None,
|
||||
self,
|
||||
browser_type: Literal["chrome", "firefox", "edge", "ie"] | None = None,
|
||||
launch_kwargs: dict | None = None,
|
||||
*,
|
||||
loop: asyncio.AbstractEventLoop | None = None,
|
||||
executor: futures.Executor | None = None,
|
||||
) -> None:
|
||||
if browser_type is None:
|
||||
browser_type = CONFIG.selenium_browser_type
|
||||
|
|
@ -117,9 +117,7 @@ def _gen_get_driver_func(browser_type, *args, executable_path=None):
|
|||
if __name__ == "__main__":
|
||||
import fire
|
||||
|
||||
|
||||
async def main(url: str, *urls: str, browser_type: str = "chrome", **kwargs):
|
||||
return await SeleniumWrapper(browser_type, **kwargs).run(url, *urls)
|
||||
|
||||
|
||||
fire.Fire(main)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from metagpt.utils.token_counter import (
|
|||
count_string_tokens,
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"read_docx",
|
||||
"Singleton",
|
||||
|
|
|
|||
|
|
@ -36,11 +36,11 @@ def py_make_scanner(context):
|
|||
return parse_object((string, idx + 1), strict, _scan_once, object_hook, object_pairs_hook, memo)
|
||||
elif nextchar == "[":
|
||||
return parse_array((string, idx + 1), _scan_once)
|
||||
elif nextchar == "n" and string[idx: idx + 4] == "null":
|
||||
elif nextchar == "n" and string[idx : idx + 4] == "null":
|
||||
return None, idx + 4
|
||||
elif nextchar == "t" and string[idx: idx + 4] == "true":
|
||||
elif nextchar == "t" and string[idx : idx + 4] == "true":
|
||||
return True, idx + 4
|
||||
elif nextchar == "f" and string[idx: idx + 5] == "false":
|
||||
elif nextchar == "f" and string[idx : idx + 5] == "false":
|
||||
return False, idx + 5
|
||||
|
||||
m = match_number(string, idx)
|
||||
|
|
@ -51,11 +51,11 @@ def py_make_scanner(context):
|
|||
else:
|
||||
res = parse_int(integer)
|
||||
return res, m.end()
|
||||
elif nextchar == "N" and string[idx: idx + 3] == "NaN":
|
||||
elif nextchar == "N" and string[idx : idx + 3] == "NaN":
|
||||
return parse_constant("NaN"), idx + 3
|
||||
elif nextchar == "I" and string[idx: idx + 8] == "Infinity":
|
||||
elif nextchar == "I" and string[idx : idx + 8] == "Infinity":
|
||||
return parse_constant("Infinity"), idx + 8
|
||||
elif nextchar == "-" and string[idx: idx + 9] == "-Infinity":
|
||||
elif nextchar == "-" and string[idx : idx + 9] == "-Infinity":
|
||||
return parse_constant("-Infinity"), idx + 9
|
||||
else:
|
||||
raise StopIteration(idx)
|
||||
|
|
@ -89,7 +89,7 @@ WHITESPACE_STR = " \t\n\r"
|
|||
|
||||
|
||||
def JSONObject(
|
||||
s_and_end, strict, scan_once, object_hook, object_pairs_hook, memo=None, _w=WHITESPACE.match, _ws=WHITESPACE_STR
|
||||
s_and_end, strict, scan_once, object_hook, object_pairs_hook, memo=None, _w=WHITESPACE.match, _ws=WHITESPACE_STR
|
||||
):
|
||||
"""Parse a JSON object from a string and return the parsed object.
|
||||
|
||||
|
|
@ -118,12 +118,12 @@ def JSONObject(
|
|||
memo_get = memo.setdefault
|
||||
# Use a slice to prevent IndexError from being raised, the following
|
||||
# check will raise a more specific ValueError if the string is empty
|
||||
nextchar = s[end: end + 1]
|
||||
nextchar = s[end : end + 1]
|
||||
# Normally we expect nextchar == '"'
|
||||
if nextchar != '"' and nextchar != "'":
|
||||
if nextchar in _ws:
|
||||
end = _w(s, end).end()
|
||||
nextchar = s[end: end + 1]
|
||||
nextchar = s[end : end + 1]
|
||||
# Trivial empty object
|
||||
if nextchar == "}":
|
||||
if object_pairs_hook is not None:
|
||||
|
|
@ -146,9 +146,9 @@ def JSONObject(
|
|||
key = memo_get(key, key)
|
||||
# To skip some function call overhead we optimize the fast paths where
|
||||
# the JSON key separator is ": " or just ":".
|
||||
if s[end: end + 1] != ":":
|
||||
if s[end : end + 1] != ":":
|
||||
end = _w(s, end).end()
|
||||
if s[end: end + 1] != ":":
|
||||
if s[end : end + 1] != ":":
|
||||
raise JSONDecodeError("Expecting ':' delimiter", s, end)
|
||||
end += 1
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ def JSONObject(
|
|||
elif nextchar != ",":
|
||||
raise JSONDecodeError("Expecting ',' delimiter", s, end - 1)
|
||||
end = _w(s, end).end()
|
||||
nextchar = s[end: end + 1]
|
||||
nextchar = s[end : end + 1]
|
||||
end += 1
|
||||
if nextchar != '"':
|
||||
raise JSONDecodeError("Expecting property name enclosed in double quotes", s, end - 1)
|
||||
|
|
@ -257,7 +257,7 @@ def py_scanstring(s, end, strict=True, _b=BACKSLASH, _m=STRINGCHUNK.match, delim
|
|||
else:
|
||||
uni = _decode_uXXXX(s, end)
|
||||
end += 5
|
||||
if 0xD800 <= uni <= 0xDBFF and s[end: end + 2] == "\\u":
|
||||
if 0xD800 <= uni <= 0xDBFF and s[end : end + 2] == "\\u":
|
||||
uni2 = _decode_uXXXX(s, end + 1)
|
||||
if 0xDC00 <= uni2 <= 0xDFFF:
|
||||
uni = 0x10000 + (((uni - 0xD800) << 10) | (uni2 - 0xDC00))
|
||||
|
|
@ -272,14 +272,14 @@ scanstring = py_scanstring
|
|||
|
||||
class CustomDecoder(json.JSONDecoder):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
object_hook=None,
|
||||
parse_float=None,
|
||||
parse_int=None,
|
||||
parse_constant=None,
|
||||
strict=True,
|
||||
object_pairs_hook=None
|
||||
self,
|
||||
*,
|
||||
object_hook=None,
|
||||
parse_float=None,
|
||||
parse_int=None,
|
||||
parse_constant=None,
|
||||
strict=True,
|
||||
object_pairs_hook=None
|
||||
):
|
||||
super().__init__(
|
||||
object_hook=object_hook,
|
||||
|
|
|
|||
|
|
@ -6,9 +6,8 @@
|
|||
@File : file.py
|
||||
@Describe : General file operations.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
import aiofiles
|
||||
from pathlib import Path
|
||||
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
|
@ -73,3 +72,4 @@ class File:
|
|||
except Exception as e:
|
||||
logger.error(f"Error reading file: {e}")
|
||||
raise e
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# 添加代码语法高亮显示
|
||||
from pygments import highlight as highlight_
|
||||
from pygments.formatters import TerminalFormatter, HtmlFormatter
|
||||
from pygments.lexers import PythonLexer, SqlLexer
|
||||
from pygments.formatters import TerminalFormatter, HtmlFormatter
|
||||
|
||||
|
||||
def highlight(code: str, language: str = 'python', formatter: str = 'terminal'):
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ MMC2 = """sequenceDiagram
|
|||
S-->>SE: return summary
|
||||
SE-->>M: return summary"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
loop = asyncio.new_event_loop()
|
||||
result = loop.run_until_complete(mermaid_to_file(MMC1, PROJECT_ROOT / f"{CONFIG.mermaid_engine}/1"))
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
@File : mermaid.py
|
||||
"""
|
||||
import base64
|
||||
import os
|
||||
|
||||
from aiohttp import ClientSession, ClientError
|
||||
|
||||
from aiohttp import ClientSession,ClientError
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,13 +8,10 @@
|
|||
|
||||
import os
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048, height=2048) -> int:
|
||||
async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048, height=2048)-> int:
|
||||
"""
|
||||
Converts the given Mermaid code to various output formats and saves them to files.
|
||||
|
||||
|
|
@ -27,21 +24,20 @@ async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048,
|
|||
Returns:
|
||||
int: Returns 1 if the conversion and saving were successful, -1 otherwise.
|
||||
"""
|
||||
suffixes = ['png', 'svg', 'pdf']
|
||||
suffixes=['png', 'svg', 'pdf']
|
||||
__dirname = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch()
|
||||
device_scale_factor = 1.0
|
||||
context = await browser.new_context(
|
||||
viewport={'width': width, 'height': height},
|
||||
device_scale_factor=device_scale_factor,
|
||||
)
|
||||
viewport={'width': width, 'height': height},
|
||||
device_scale_factor=device_scale_factor,
|
||||
)
|
||||
page = await context.new_page()
|
||||
|
||||
async def console_message(msg):
|
||||
logger.info(msg.text)
|
||||
|
||||
page.on('console', console_message)
|
||||
|
||||
try:
|
||||
|
|
@ -76,7 +72,7 @@ async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048,
|
|||
|
||||
}''', [mermaid_code, mermaid_config, my_css, background_color])
|
||||
|
||||
if 'svg' in suffixes:
|
||||
if 'svg' in suffixes :
|
||||
svg_xml = await page.evaluate('''() => {
|
||||
const svg = document.querySelector('svg');
|
||||
const xmlSerializer = new XMLSerializer();
|
||||
|
|
@ -86,7 +82,7 @@ async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048,
|
|||
with open(f'{output_file_without_suffix}.svg', 'wb') as f:
|
||||
f.write(svg_xml.encode('utf-8'))
|
||||
|
||||
if 'png' in suffixes:
|
||||
if 'png' in suffixes:
|
||||
clip = await page.evaluate('''() => {
|
||||
const svg = document.querySelector('svg');
|
||||
const rect = svg.getBoundingClientRect();
|
||||
|
|
|
|||
|
|
@ -7,14 +7,11 @@
|
|||
"""
|
||||
import os
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from pyppeteer import launch
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.logs import logger
|
||||
from metagpt.config import CONFIG
|
||||
|
||||
|
||||
async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048, height=2048) -> int:
|
||||
async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048, height=2048)-> int:
|
||||
"""
|
||||
Converts the given Mermaid code to various output formats and saves them to files.
|
||||
|
||||
|
|
@ -27,14 +24,15 @@ async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048,
|
|||
Returns:
|
||||
int: Returns 1 if the conversion and saving were successful, -1 otherwise.
|
||||
"""
|
||||
suffixes = ['png', 'svg', 'pdf']
|
||||
suffixes = ['png', 'svg', 'pdf']
|
||||
__dirname = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
if CONFIG.pyppeteer_executable_path:
|
||||
browser = await launch(headless=True,
|
||||
executablePath=CONFIG.pyppeteer_executable_path,
|
||||
args=['--disable-extensions', "--no-sandbox"]
|
||||
)
|
||||
executablePath=CONFIG.pyppeteer_executable_path,
|
||||
args=['--disable-extensions',"--no-sandbox"]
|
||||
)
|
||||
else:
|
||||
logger.error("Please set the environment variable:PYPPETEER_EXECUTABLE_PATH.")
|
||||
return -1
|
||||
|
|
@ -43,7 +41,6 @@ async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048,
|
|||
|
||||
async def console_message(msg):
|
||||
logger.info(msg.text)
|
||||
|
||||
page.on('console', console_message)
|
||||
|
||||
try:
|
||||
|
|
@ -76,7 +73,7 @@ async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048,
|
|||
}
|
||||
}''', [mermaid_code, mermaid_config, my_css, background_color])
|
||||
|
||||
if 'svg' in suffixes:
|
||||
if 'svg' in suffixes :
|
||||
svg_xml = await page.evaluate('''() => {
|
||||
const svg = document.querySelector('svg');
|
||||
const xmlSerializer = new XMLSerializer();
|
||||
|
|
@ -86,7 +83,7 @@ async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048,
|
|||
with open(f'{output_file_without_suffix}.svg', 'wb') as f:
|
||||
f.write(svg_xml.encode('utf-8'))
|
||||
|
||||
if 'png' in suffixes:
|
||||
if 'png' in suffixes:
|
||||
clip = await page.evaluate('''() => {
|
||||
const svg = document.querySelector('svg');
|
||||
const rect = svg.getBoundingClientRect();
|
||||
|
|
@ -97,8 +94,7 @@ async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048,
|
|||
height: Math.ceil(rect.height)
|
||||
};
|
||||
}''')
|
||||
await page.setViewport({'width': clip['x'] + clip['width'], 'height': clip['y'] + clip['height'],
|
||||
'deviceScaleFactor': device_scale_factor})
|
||||
await page.setViewport({'width': clip['x'] + clip['width'], 'height': clip['y'] + clip['height'], 'deviceScaleFactor': device_scale_factor})
|
||||
screenshot = await page.screenshot(clip=clip, omit_background=True, scale='device')
|
||||
logger.info(f"Generating {output_file_without_suffix}.png..")
|
||||
with open(f'{output_file_without_suffix}.png', 'wb') as f:
|
||||
|
|
@ -114,3 +110,4 @@ async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048,
|
|||
return -1
|
||||
finally:
|
||||
await browser.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class WebPage(BaseModel):
|
|||
class Config:
|
||||
underscore_attrs_are_private = True
|
||||
|
||||
_soup: Optional[BeautifulSoup] = None
|
||||
_soup : Optional[BeautifulSoup] = None
|
||||
_title: Optional[str] = None
|
||||
|
||||
@property
|
||||
|
|
@ -24,7 +24,7 @@ class WebPage(BaseModel):
|
|||
if self._soup is None:
|
||||
self._soup = BeautifulSoup(self.html, "html.parser")
|
||||
return self._soup
|
||||
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
if self._title is None:
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ def get_docstring_statement(body: DocstringNode) -> cst.SimpleStatementLine:
|
|||
|
||||
if not isinstance(expr, cst.Expr):
|
||||
return None
|
||||
|
||||
|
||||
val = expr.value
|
||||
if not isinstance(val, (cst.SimpleString, cst.ConcatenatedString)):
|
||||
return None
|
||||
|
||||
evaluated_value = val.evaluated_value
|
||||
|
||||
evaluated_value = val.evaluated_value
|
||||
if isinstance(evaluated_value, bytes):
|
||||
return None
|
||||
|
||||
|
|
@ -56,7 +56,6 @@ class DocstringCollector(cst.CSTVisitor):
|
|||
stack: A list to keep track of the current path in the CST.
|
||||
docstrings: A dictionary mapping paths in the CST to their corresponding docstrings.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.stack: list[str] = []
|
||||
self.docstrings: dict[tuple[str, ...], cst.SimpleStatementLine] = {}
|
||||
|
|
@ -97,10 +96,9 @@ class DocstringTransformer(cst.CSTTransformer):
|
|||
stack: A list to keep track of the current path in the CST.
|
||||
docstrings: A dictionary mapping paths in the CST to their corresponding docstrings.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
docstrings: dict[tuple[str, ...], cst.SimpleStatementLine],
|
||||
self,
|
||||
docstrings: dict[tuple[str, ...], cst.SimpleStatementLine],
|
||||
):
|
||||
self.stack: list[str] = []
|
||||
self.docstrings = docstrings
|
||||
|
|
@ -127,8 +125,7 @@ class DocstringTransformer(cst.CSTTransformer):
|
|||
key = tuple(self.stack)
|
||||
self.stack.pop()
|
||||
|
||||
if hasattr(updated_node, "decorators") and any(
|
||||
(i.decorator.value == "overload") for i in updated_node.decorators):
|
||||
if hasattr(updated_node, "decorators") and any((i.decorator.value == "overload") for i in updated_node.decorators):
|
||||
return updated_node
|
||||
|
||||
statement = self.docstrings.get(key)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
import docx
|
||||
|
||||
|
||||
def read_docx(file_path: str) -> list:
|
||||
"""Open a docx file"""
|
||||
doc = docx.Document(file_path)
|
||||
|
|
|
|||
|
|
@ -20,3 +20,4 @@ class Singleton(abc.ABCMeta, type):
|
|||
if cls not in cls._instances:
|
||||
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
||||
return cls._instances[cls]
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# token to separate different code messages in a WriteCode Message content
|
||||
MSG_SEP = "#*000*#"
|
||||
MSG_SEP = "#*000*#"
|
||||
# token to seperate file name and the actual code text in a code message
|
||||
FILENAME_CODE_SEP = "#*001*#"
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ from typing import Generator, Sequence
|
|||
from metagpt.utils.token_counter import TOKEN_MAX, count_string_tokens
|
||||
|
||||
|
||||
def reduce_message_length(msgs: Generator[str, None, None], model_name: str, system_text: str,
|
||||
reserved: int = 0, ) -> str:
|
||||
def reduce_message_length(msgs: Generator[str, None, None], model_name: str, system_text: str, reserved: int = 0,) -> str:
|
||||
"""Reduce the length of concatenated message segments to fit within the maximum token size.
|
||||
|
||||
Args:
|
||||
|
|
@ -28,11 +27,11 @@ def reduce_message_length(msgs: Generator[str, None, None], model_name: str, sys
|
|||
|
||||
|
||||
def generate_prompt_chunk(
|
||||
text: str,
|
||||
prompt_template: str,
|
||||
model_name: str,
|
||||
system_text: str,
|
||||
reserved: int = 0,
|
||||
text: str,
|
||||
prompt_template: str,
|
||||
model_name: str,
|
||||
system_text: str,
|
||||
reserved: int = 0,
|
||||
) -> Generator[str, None, None]:
|
||||
"""Split the text into chunks of a maximum token size.
|
||||
|
||||
|
|
@ -50,9 +49,9 @@ def generate_prompt_chunk(
|
|||
current_token = 0
|
||||
current_lines = []
|
||||
|
||||
reserved = reserved + count_string_tokens(prompt_template + system_text, model_name)
|
||||
reserved = reserved + count_string_tokens(prompt_template+system_text, model_name)
|
||||
# 100 is a magic number to ensure the maximum context length is not exceeded
|
||||
max_token = TOKEN_MAX.get(model_name, 2048) - reserved - 100
|
||||
max_token = TOKEN_MAX.get(model_name, 2048) - reserved - 100
|
||||
|
||||
while paragraphs:
|
||||
paragraph = paragraphs.pop(0)
|
||||
|
|
@ -104,7 +103,7 @@ def decode_unicode_escape(text: str) -> str:
|
|||
return text.encode("utf-8").decode("unicode_escape", "ignore")
|
||||
|
||||
|
||||
def _split_by_count(lst: Sequence, count: int):
|
||||
def _split_by_count(lst: Sequence , count: int):
|
||||
avg = len(lst) // count
|
||||
remainder = len(lst) % count
|
||||
start = 0
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ TOKEN_COSTS = {
|
|||
"text-embedding-ada-002": {"prompt": 0.0004, "completion": 0.0},
|
||||
}
|
||||
|
||||
|
||||
TOKEN_MAX = {
|
||||
"gpt-3.5-turbo": 4096,
|
||||
"gpt-3.5-turbo-0301": 4096,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue