using streaming api now.

This commit is contained in:
geekan 2023-07-06 11:14:50 +08:00
parent a69f07e62f
commit 1de45add2e
8 changed files with 28 additions and 14 deletions

View file

@ -12,6 +12,7 @@ from metagpt.actions import Action
from metagpt.const import WORKSPACE_ROOT
from metagpt.utils.common import CodeParser
from metagpt.schema import Message
from metagpt.logs import logger
from metagpt.utils.mermaid import mermaid_to_file
PROMPT_TEMPLATE = """
@ -56,6 +57,7 @@ class WriteDesign(Action):
prd_file = docs_path / 'prd.md'
quadrant_chart = CodeParser.parse_code(block="Competitive Quadrant Chart", text=prd)
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, system_design):
@ -64,6 +66,7 @@ class WriteDesign(Action):
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(system_design)
def _save(self, context, system_design):

View file

@ -41,8 +41,8 @@ class WriteCode(Action):
return any(i in filename for i in ["mp3", "wav"])
def _save(self, context, filename, code_rsp):
logger.info(filename)
logger.info(code_rsp)
# logger.info(filename)
# logger.info(code_rsp)
if self._is_invalid(filename):
return
@ -55,9 +55,13 @@ class WriteCode(Action):
code_path.parent.mkdir(parents=True, exist_ok=True)
code = CodeParser.parse_code(block="", text=code_rsp)
code_path.write_text(code)
logger.info(f"Saving Code to {code_path}")
async def run(self, **kwargs):
prompt = PROMPT_TEMPLATE.format(**kwargs)
filename = kwargs['filename']
context = kwargs['context']
logger.info(f'Writing {filename}..')
code_rsp = await self._aask(prompt)
self._save(kwargs['context'], kwargs['filename'], code_rsp)
self._save(context, filename, code_rsp)
return code_rsp

View file

@ -68,8 +68,9 @@ class WritePRD(Action):
sas = SearchAndSummarize()
rsp = await sas.run(context=requirements, system_text=SEARCH_AND_SUMMARIZE_SYSTEM_EN_US)
info = f"### Search Results\n{sas.result}\n\n### Search Summary\n{rsp}"
logger.info(sas.result)
logger.info(rsp)
if sas.result:
logger.info(sas.result)
logger.info(rsp)
prompt = PROMPT_TEMPLATE.format(requirements=requirements, search_information=info)
prd = await self._aask(prompt)

View file

@ -41,10 +41,10 @@ class BaseGPTAPI(BaseChatbot):
message = self._system_msgs(system_msgs) + [self._user_msg(msg)]
else:
message = [self._default_system_msg(), self._user_msg(msg)]
rsp = await self.acompletion(message)
rsp = await self.acompletion_text(message, stream=True)
logger.debug(message)
# logger.debug(rsp)
return self.get_choice_text(rsp)
return rsp
def _extract_assistant_rsp(self, context):
return "\n".join([i["content"] for i in context if i["role"] == "assistant"])
@ -58,14 +58,14 @@ class BaseGPTAPI(BaseChatbot):
rsp_text = self.get_choice_text(rsp)
context.append(self._assistant_msg(rsp_text))
return self._extract_assistant_rsp(context)
async def aask_batch(self, msgs: list) -> str:
"""Sequential questioning"""
context = []
for msg in msgs:
umsg = self._user_msg(msg)
context.append(umsg)
rsp = await self.acompletion(context)
rsp_text = self.get_choice_text(rsp)
rsp_text = await self.acompletion_text(context)
context.append(self._assistant_msg(rsp_text))
return self._extract_assistant_rsp(context)
@ -100,6 +100,10 @@ class BaseGPTAPI(BaseChatbot):
]
"""
@abstractmethod
async def acompletion_text(self, messages: list[dict], stream=False) -> str:
"""Asynchronous version of completion. Return str. Support stream-print"""
def get_choice_text(self, rsp: dict) -> str:
"""Required to provide the first text of choice"""
return rsp.get("choices")[0]["message"]["content"]

View file

@ -166,6 +166,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter):
collected_messages.append(chunk_message) # save the message
if "content" in chunk_message:
print(chunk_message["content"], end="")
print()
full_reply_content = ''.join([m.get('content', '') for m in collected_messages])
return full_reply_content
@ -206,6 +207,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter):
return await self._achat_completion(messages)
async def acompletion_text(self, messages: list[dict], stream=False) -> str:
"""when streaming, print each token in place."""
if stream:
return await self._achat_completion_stream(messages)
rsp = await self._achat_completion(messages)

View file

@ -150,8 +150,9 @@ class Role:
# prompt += ROLE_TEMPLATE.format(name=self.profile, state=self.states[self.state], result=response,
# history=self.history)
logger.info(f"{self._setting}: ready to {self._rc.todo}")
response = await self._rc.todo.run(self._rc.important_memory)
logger.info(response)
# logger.info(response)
msg = Message(content=response, role=self.profile, cause_by=type(self._rc.todo))
self._rc.memory.add(msg)
# logger.debug(f"{response}")

View file

@ -24,8 +24,6 @@ def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048, height
"""
# Write the Mermaid code to a temporary file
tmp = Path(f'{output_file_without_suffix}.mmd')
logger.info(tmp)
logger.info(str(tmp))
tmp.write_text(mermaid_code, encoding='utf-8')
if check_cmd_exists('mmdc') != 0:
@ -35,6 +33,7 @@ def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048, height
for suffix in ['pdf', 'svg', 'png']:
output_file = f'{output_file_without_suffix}.{suffix}'
# Call the `mmdc` command to convert the Mermaid code to a PNG
logger.info(f"Generating {output_file}..")
subprocess.run(['mmdc', '-i', str(tmp), '-o', output_file, '-w', str(width), '-H', str(height)])
return 0

View file

@ -15,14 +15,14 @@ async def startup(idea: str, investment: float = 3.0, n_round: int = 5):
await company.run(n_round=n_round)
def main(idea: str, investment: float = 3.0):
def main(idea: str, investment: float = 3.0, n_round: int = 5):
"""
We are a software startup comprised of AI. By investing in us, you are empowering a future filled with limitless possibilities.
:param idea: Your innovative idea, such as "Creating a snake game."
:param investment: As an investor, you have the opportunity to contribute a certain dollar amount to this AI company.
:return:
"""
asyncio.run(startup(idea, investment))
asyncio.run(startup(idea, investment, n_round))
if __name__ == '__main__':