From 5c627df6c47fd8bd9257a4643a4fd0de49d7be82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 17:18:01 +0800 Subject: [PATCH 01/43] feat: +log --- metagpt/actions/talk_action.py | 1 + 1 file changed, 1 insertion(+) diff --git a/metagpt/actions/talk_action.py b/metagpt/actions/talk_action.py index 81caef013..4afed8014 100644 --- a/metagpt/actions/talk_action.py +++ b/metagpt/actions/talk_action.py @@ -44,6 +44,7 @@ class TalkAction(Action): f"Answer the following questions strictly in {language}, and the answers must follow the Markdown format.\n " f"{self._talk}" ) + logger.info(f"PROMPT: {prompt}") return prompt @property From c1aa93221086f094e3c661e3ac9f141f0f1b2168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 19:10:16 +0800 Subject: [PATCH 02/43] feat: +iflytek tts --- .well-known/metagpt_oas3_api.yaml | 57 +++++++++++++++++++++++++++++++ metagpt/learn/text_to_speech.py | 29 ++++++++++++++-- requirements.txt | 3 +- 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/.well-known/metagpt_oas3_api.yaml b/.well-known/metagpt_oas3_api.yaml index 56c6f42d5..1e3cecb10 100644 --- a/.well-known/metagpt_oas3_api.yaml +++ b/.well-known/metagpt_oas3_api.yaml @@ -73,6 +73,63 @@ paths: '500': description: "Internal Server Error" + /tts/iflytek: + x-prerequisite: + - name: IFLYTEK_APP_ID + description: "Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts`" + - name: IFLYTEK_API_KEY + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + - name: IFLYTEK_API_SECRET + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + post: + summary: "Convert Text to Base64-encoded .mp3 File Stream" + description: "For more details, check out: [iFlyTek](https://console.xfyun.cn/services/tts)" + operationId: iflytek_tts.oas3_iflytek_tts + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - text + properties: + text: + type: string + description: Text to convert + voice: + type: string + description: "Voice style, see: [iFlyTek Text-to_Speech](https://www.xfyun.cn/doc/tts/online_tts/API.html#%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B)" + default: "xiaoyan" + app_id: + type: string + description: "Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts`" + default: "" + api_key: + type: string + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + default: "" + api_secret: + type: string + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + default: "" + responses: + '200': + description: "Base64-encoded .mp3 file data if successful, otherwise an empty string." + content: + application/json: + schema: + type: object + properties: + wav_data: + type: string + format: base64 + '400': + description: "Bad Request" + '500': + description: "Internal Server Error" + + /txt2img/openai: x-prerequisite: - name: OPENAI_API_KEY diff --git a/metagpt/learn/text_to_speech.py b/metagpt/learn/text_to_speech.py index 81bc8512b..7c085c02f 100644 --- a/metagpt/learn/text_to_speech.py +++ b/metagpt/learn/text_to_speech.py @@ -11,6 +11,7 @@ import openai from metagpt.config import CONFIG from metagpt.const import BASE64_FORMAT from metagpt.tools.azure_tts import oas3_azsure_tts +from metagpt.tools.iflytek_tts import oas3_iflytek_tts from metagpt.utils.s3 import S3 @@ -22,6 +23,9 @@ async def text_to_speech( role="Girl", subscription_key="", region="", + iflytek_app_id="", + iflytek_api_key="", + iflytek_api_secret="", **kwargs, ): """Text to speech @@ -34,16 +38,35 @@ async def text_to_speech( :param text: The text used for voice conversion. :param subscription_key: key is used to access your Azure AI service API, see: `https://portal.azure.com/` > `Resource Management` > `Keys and Endpoint` :param region: This is the location (or region) of your resource. You may need to use this field when making calls to this API. - :return: Returns the Base64-encoded .wav file data if successful, otherwise an empty string. + :param iflytek_app_id: Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts` + :param iflytek_api_key: WebAPI argument, see: `https://console.xfyun.cn/services/tts` + :param iflytek_api_secret: WebAPI argument, see: `https://console.xfyun.cn/services/tts` + :return: Returns the Base64-encoded .wav/.mp3 file data if successful, otherwise an empty string. """ - audio_declaration = "data:audio/wav;base64," + if (CONFIG.AZURE_TTS_SUBSCRIPTION_KEY and CONFIG.AZURE_TTS_REGION) or (subscription_key and region): + audio_declaration = "data:audio/wav;base64," base64_data = await oas3_azsure_tts(text, lang, voice, style, role, subscription_key, region) s3 = S3() url = await s3.cache(data=base64_data, file_ext=".wav", format=BASE64_FORMAT) if url: return f"[{text}]({url})" return audio_declaration + base64_data if base64_data else base64_data + if (CONFIG.IFLYTEK_APP_ID and CONFIG.IFLYTEK_API_KEY and CONFIG.IFLYTEK_API_SECRET) or ( + iflytek_app_id and iflytek_api_key and iflytek_api_secret + ): + audio_declaration = "data:audio/mp3;base64," + base64_data = await oas3_iflytek_tts( + text=text, app_id=iflytek_app_id, api_key=iflytek_api_key, api_secret=iflytek_api_secret + ) + s3 = S3() + url = await s3.cache(data=base64_data, file_ext=".mp3", format=BASE64_FORMAT) + if url: + return f"[{text}]({url})" + return audio_declaration + base64_data if base64_data else base64_data - raise openai.error.InvalidRequestError(message="AZURE_TTS_SUBSCRIPTION_KEY and AZURE_TTS_REGION error", param={}) + raise openai.error.InvalidRequestError( + message="AZURE_TTS_SUBSCRIPTION_KEY, AZURE_TTS_REGION, IFLYTEK_APP_ID, IFLYTEK_API_KEY, IFLYTEK_API_SECRET error", + param={}, + ) diff --git a/requirements.txt b/requirements.txt index 588b29e0b..2dd767026 100644 --- a/requirements.txt +++ b/requirements.txt @@ -42,4 +42,5 @@ connexion[swagger-ui] aiohttp_jinja2 azure-cognitiveservices-speech==1.31.0 aioboto3~=11.3.0 -redis==4.3.5 \ No newline at end of file +redis==4.3.5 +websocket-client \ No newline at end of file From f8aea281a85fde07459780f3e1f7e3b5a1e27e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 19:11:22 +0800 Subject: [PATCH 03/43] feat: +iflytek tts --- metagpt/tools/iflytek_tts.py | 162 +++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 metagpt/tools/iflytek_tts.py diff --git a/metagpt/tools/iflytek_tts.py b/metagpt/tools/iflytek_tts.py new file mode 100644 index 000000000..a91d8091b --- /dev/null +++ b/metagpt/tools/iflytek_tts.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@Time : 2023/8/17 +@Author : mashenquan +@File : iflytek_tts.py +@Desc : iFLYTEK TTS OAS3 api, which provides text-to-speech functionality +""" +import asyncio +import base64 +import hashlib +import hmac +import json +import uuid +from datetime import datetime +from enum import Enum +from pathlib import Path +from time import mktime +from typing import Optional +from urllib.parse import urlencode +from wsgiref.handlers import format_date_time + +import aiofiles +import websockets as websockets +from pydantic import BaseModel + +from metagpt.config import CONFIG +from metagpt.logs import logger + + +class IFlyTekTTSStatus(Enum): + STATUS_FIRST_FRAME = 0 # The first frame + STATUS_CONTINUE_FRAME = 1 # The intermediate frame + STATUS_LAST_FRAME = 2 # The last frame + + +class AudioData(BaseModel): + audio: str + status: int + ced: str + + +class IFlyTekTTSResponse(BaseModel): + code: int + message: str + data: Optional[AudioData] = None + sid: str + + +DEFAULT_IFLYTEK_VOICE = "xiaoyan" + + +class IFlyTekTTS(object): + def __init__(self, app_id: str, api_key: str, api_secret: str): + """ + :param app_id: Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts` + :param api_key: WebAPI argument, see: `https://console.xfyun.cn/services/tts` + :param api_secret: WebAPI argument, see: `https://console.xfyun.cn/services/tts` + """ + self.app_id = app_id or CONFIG.IFLYTEK_APP_ID + self.api_key = api_key or CONFIG.IFLYTEK_API_KEY + self.api_secret = api_secret or CONFIG.API_SECRET + + async def synthesize_speech(self, text, output_file: str, voice=DEFAULT_IFLYTEK_VOICE): + url = self._create_url() + data = { + "common": {"app_id": self.app_id}, + "business": {"aue": "lame", "sfl": 1, "auf": "audio/L16;rate=16000", "vcn": voice, "tte": "utf8"}, + "data": {"status": 2, "text": str(base64.b64encode(text.encode("utf-8")), "UTF8")}, + } + req = json.dumps(data) + async with websockets.connect(url) as websocket: + # send request + await websocket.send(req) + + # receive frames + async with aiofiles.open(str(output_file), "w") as writer: + while True: + v = await websocket.recv() + rsp = IFlyTekTTSResponse(**json.loads(v)) + if rsp.data: + await writer.write(rsp.data.audio) + if rsp.data.status != IFlyTekTTSStatus.STATUS_LAST_FRAME.value: + continue + break + + def _create_url(self): + """Create request url""" + url = "wss://tts-api.xfyun.cn/v2/tts" + # Generate a timestamp in RFC1123 format + now = datetime.now() + date = format_date_time(mktime(now.timetuple())) + + signature_origin = "host: " + "ws-api.xfyun.cn" + "\n" + signature_origin += "date: " + date + "\n" + signature_origin += "GET " + "/v2/tts " + "HTTP/1.1" + # Perform HMAC-SHA256 encryption + signature_sha = hmac.new( + self.api_secret.encode("utf-8"), signature_origin.encode("utf-8"), digestmod=hashlib.sha256 + ).digest() + signature_sha = base64.b64encode(signature_sha).decode(encoding="utf-8") + + authorization_origin = 'api_key="%s", algorithm="%s", headers="%s", signature="%s"' % ( + self.api_key, + "hmac-sha256", + "host date request-line", + signature_sha, + ) + authorization = base64.b64encode(authorization_origin.encode("utf-8")).decode(encoding="utf-8") + # Combine the authentication parameters of the request into a dictionary. + v = {"authorization": authorization, "date": date, "host": "ws-api.xfyun.cn"} + # Concatenate the authentication parameters to generate the URL. + url = url + "?" + urlencode(v) + return url + + +# Export +async def oas3_iflytek_tts(text: str, voice: str = "", app_id: str = "", api_key: str = "", api_secret: str = ""): + """Text to speech + For more details, check out:`https://www.xfyun.cn/doc/tts/online_tts/API.html` + + :param voice: Default `xiaoyan`. For more details, checkout: `https://www.xfyun.cn/doc/tts/online_tts/API.html#%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B` + :param text: The text used for voice conversion. + :param app_id: Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts` + :param api_key: WebAPI argument, see: `https://console.xfyun.cn/services/tts` + :param api_secret: WebAPI argument, see: `https://console.xfyun.cn/services/tts` + :return: Returns the Base64-encoded .mp3 file data if successful, otherwise an empty string. + + """ + if not app_id: + app_id = CONFIG.IFLYTEK_APP_ID + if not api_key: + api_key = CONFIG.IFLYTEK_API_KEY + if not api_secret: + api_secret = CONFIG.IFLYTEK_API_SECRET + if not voice: + voice = CONFIG.IFLYTEK_VOICE or DEFAULT_IFLYTEK_VOICE + + filename = Path(__file__).parent / (str(uuid.uuid4()).replace("-", "") + ".mp3") + try: + tts = IFlyTekTTS(app_id=app_id, api_key=api_key, api_secret=api_secret) + await tts.synthesize_speech(text=text, output_file=str(filename), voice=voice) + async with aiofiles.open(str(filename), mode="r") as reader: + base64_string = await reader.read() + except Exception as e: + logger.error(f"text:{text}, error:{e}") + base64_string = "" + finally: + filename.unlink() + + return base64_string + + +if __name__ == "__main__": + asyncio.get_event_loop().run_until_complete( + oas3_iflytek_tts( + text="你好,hello", + app_id="f7acef62", + api_key="fda72e3aa286042a492525816a5efa08", + api_secret="ZDk3NjdiMDBkODJlOWQ1NjRjMGI2NDY4", + ) + ) From 96aad1ce7745e7e39ae5dc82fbd2f59bf7ff144a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 19:25:50 +0800 Subject: [PATCH 04/43] feat: +log --- metagpt/tools/metagpt_oas3_api_svc.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/metagpt/tools/metagpt_oas3_api_svc.py b/metagpt/tools/metagpt_oas3_api_svc.py index 5c23f6566..2ff4c8225 100644 --- a/metagpt/tools/metagpt_oas3_api_svc.py +++ b/metagpt/tools/metagpt_oas3_api_svc.py @@ -7,8 +7,8 @@ @Desc : MetaGPT OpenAPI Specification 3.0 REST API service """ import asyncio -from pathlib import Path import sys +from pathlib import Path import connexion @@ -17,7 +17,7 @@ sys.path.append(str(Path(__file__).resolve().parent.parent.parent)) # fix-bug: def oas_http_svc(): """Start the OAS 3.0 OpenAPI HTTP service""" - app = connexion.AioHttpApp(__name__, specification_dir='../../.well-known/') + app = connexion.AioHttpApp(__name__, specification_dir="../../.well-known/") app.add_api("metagpt_oas3_api.yaml") app.add_api("openapi.yaml") app.run(port=8080) @@ -35,6 +35,7 @@ async def async_main(): def main(): + print("http://localhost:8080/oas3/ui/") oas_http_svc() From c800ad02d18bff6295af1a0d3a0fc1f50e9092a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 19:35:48 +0800 Subject: [PATCH 05/43] feat: +example --- .well-known/skills.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.well-known/skills.yaml b/.well-known/skills.yaml index 009368dbe..d08d7aced 100644 --- a/.well-known/skills.yaml +++ b/.well-known/skills.yaml @@ -21,7 +21,9 @@ entities: - ask: 'A boy affectionate says "hello world"' answer: 'text_to_speech(text="hello world", role="Boy", style="affectionate")' - ask: 'A boy says "你好"' - answer: 'text_to_speech(text="hello world", role="Boy", lang="Chinese")' + answer: 'text_to_speech(text="你好", role="Boy", lang="Chinese")' + - ask: 'How to speak "你好"?' + answer: 'text_to_speech(text="你好", lang="Chinese")' returns: type: string format: base64 @@ -42,6 +44,10 @@ entities: answer: 'text_to_image(text="Draw a girl", size_type="512x512")' - ask: 'Draw an apple' answer: 'text_to_image(text="Draw an apple", size_type="512x512")' + - ask: 'Draw an apple picture' + answer: 'text_to_image(text="Draw an apple", size_type="512x512")' + - ask: 'Draw an apple image' + answer: 'text_to_image(text="Draw an apple", size_type="512x512")' returns: type: string format: base64 From f60b68f1c54bec7bd787e0620828887cc1a6ed09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 19:39:38 +0800 Subject: [PATCH 06/43] refactor: think prompt --- metagpt/roles/assistant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 87127cbab..a988572f4 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -62,7 +62,7 @@ class Assistant(Role): ) prompt += "If the preceding text presents a complete question and solution, rewrite and return `[SOLUTION]: {problem}` brief and clear. For instance: [SOLUTION]: Solution for distributing watermelon\n" prompt += "If the preceding text presents an unresolved issue and its corresponding discussion, rewrite and return `[PROBLEM]: {problem}` brief and clear. For instance: [PROBLEM]: How to distribute watermelon?\n" - prompt += "Otherwise, rewrite and return `[TALK]: {talk}` brief and clear. For instance: [TALK]: distribute watermelon" + prompt += "Otherwise, return `[TALK]: {talk}` brief and clear. For instance: [TALK]: distribute watermelon" logger.info(prompt) rsp = await self._llm.aask(prompt, []) logger.info(rsp) From a71708addcdc19575b6ef7f5e36cbf871655867c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 19:56:41 +0800 Subject: [PATCH 07/43] feat: +ver --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2dd767026..3b2dc3106 100644 --- a/requirements.txt +++ b/requirements.txt @@ -43,4 +43,4 @@ aiohttp_jinja2 azure-cognitiveservices-speech==1.31.0 aioboto3~=11.3.0 redis==4.3.5 -websocket-client \ No newline at end of file +websocket-client==1.6.2 \ No newline at end of file From 50835b8c472b23238d351aadade7acf3b79e428d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 20:04:44 +0800 Subject: [PATCH 08/43] refactor: think --- metagpt/provider/openai_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index bf2ca7f14..06e06df69 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -276,7 +276,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): return response async def is_related(self, text1, text2): - command = f"{text1}\n{text2}\n\nIf the two sentences above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." + command = f"Paragraph 1:{text1}\n\nParagraph 2:{text2}\n\nIf the two Paragraphs above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." rsp = await self.aask(msg=command, system_msgs=[]) result, _ = self.extract_info(rsp) return result == "TRUE" From 246bf5ce00ab6a71fe8f97a297bbd44ed47a5bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 20:07:55 +0800 Subject: [PATCH 09/43] refactor: think --- metagpt/provider/openai_api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 06e06df69..68b0e4171 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -276,7 +276,9 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): return response async def is_related(self, text1, text2): - command = f"Paragraph 1:{text1}\n\nParagraph 2:{text2}\n\nIf the two Paragraphs above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." + p1 = text1.replace("\n", " ") + p2 = text2.replace("\n", " ") + command = f"Paragraph 1:{p1}\n\nParagraph 2:{p2}\n\nIf the two Paragraphs above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." rsp = await self.aask(msg=command, system_msgs=[]) result, _ = self.extract_info(rsp) return result == "TRUE" From 0b412008c4e10626d124c2939dfcb9c43e529bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 20:11:51 +0800 Subject: [PATCH 10/43] refactor: think --- metagpt/provider/openai_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 68b0e4171..353ae46a0 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -278,7 +278,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): async def is_related(self, text1, text2): p1 = text1.replace("\n", " ") p2 = text2.replace("\n", " ") - command = f"Paragraph 1:{p1}\n\nParagraph 2:{p2}\n\nIf the two Paragraphs above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." + command = f"Paragraph 1: {p1}\n\nParagraph 2: {p2}\n\nIf the two Paragraphs above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." rsp = await self.aask(msg=command, system_msgs=[]) result, _ = self.extract_info(rsp) return result == "TRUE" From caff43e1965acb87baf1011f54a9a77f68b4d041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 20:24:46 +0800 Subject: [PATCH 11/43] refactor: think --- metagpt/provider/openai_api.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 353ae46a0..fdf95f68c 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -280,14 +280,14 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): p2 = text2.replace("\n", " ") command = f"Paragraph 1: {p1}\n\nParagraph 2: {p2}\n\nIf the two Paragraphs above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." rsp = await self.aask(msg=command, system_msgs=[]) + logger.info(f"RELATED:{rsp}\n\n{p1}\n{p2}") result, _ = self.extract_info(rsp) return result == "TRUE" async def rewrite(self, sentence: str, context: str): - command = ( - f"{context}\n\nConsidering the content above, rewrite and return this sentence brief and clear:\n{sentence}" - ) + command = f"{context}\n\nTaking into account the information above, please rephrase and provide the revised sentence:\n{sentence}" rsp = await self.aask(msg=command, system_msgs=[]) + logger.info(f"REWRITE:{rsp}\nFROM\n\n{sentence}") return rsp @staticmethod From b76ab1943656353eabde3320e7b8d4ffa1b24172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 20:32:02 +0800 Subject: [PATCH 12/43] refactor: think --- metagpt/provider/openai_api.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index fdf95f68c..827a2e399 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -278,16 +278,14 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): async def is_related(self, text1, text2): p1 = text1.replace("\n", " ") p2 = text2.replace("\n", " ") - command = f"Paragraph 1: {p1}\n\nParagraph 2: {p2}\n\nIf the two Paragraphs above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." + command = f"Paragraph 1: {p2}\n\nParagraph 2: {p1}\n\nIf the two Paragraphs above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." rsp = await self.aask(msg=command, system_msgs=[]) - logger.info(f"RELATED:{rsp}\n\n{p1}\n{p2}") result, _ = self.extract_info(rsp) return result == "TRUE" async def rewrite(self, sentence: str, context: str): command = f"{context}\n\nTaking into account the information above, please rephrase and provide the revised sentence:\n{sentence}" rsp = await self.aask(msg=command, system_msgs=[]) - logger.info(f"REWRITE:{rsp}\nFROM\n\n{sentence}") return rsp @staticmethod From 508fff69209ce0d34699bc4ac37dc13382f2b19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 22:02:51 +0800 Subject: [PATCH 13/43] refactor: think --- metagpt/provider/openai_api.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 827a2e399..90fcd7ab3 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -276,15 +276,17 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): return response async def is_related(self, text1, text2): - p1 = text1.replace("\n", " ") - p2 = text2.replace("\n", " ") - command = f"Paragraph 1: {p2}\n\nParagraph 2: {p1}\n\nIf the two Paragraphs above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." + # command = f"{text1}\n{text2}\n\nIf the two sentences above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." + command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any, return [TRUE] brief and clear. Otherwise, return [FALSE]." rsp = await self.aask(msg=command, system_msgs=[]) result, _ = self.extract_info(rsp) return result == "TRUE" async def rewrite(self, sentence: str, context: str): - command = f"{context}\n\nTaking into account the information above, please rephrase and provide the revised sentence:\n{sentence}" + # command = ( + # f"{context}\n\nConsidering the content above, rewrite and return this sentence brief and clear:\n{sentence}" + # ) + command = f"{context}\n\nExtract relevant information from every preceding sentence and use it to succinctly supplement or rewrite the following text:\n{sentence}" rsp = await self.aask(msg=command, system_msgs=[]) return rsp From a9b56a6f56e1950e2b86f3c9c06f0c6f7bfed269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 22:04:25 +0800 Subject: [PATCH 14/43] refactor: think --- metagpt/roles/assistant.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index a988572f4..7fd1b1236 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -129,9 +129,10 @@ class Assistant(Role): await self.memory.set_history_summary( history_summary=history_summary, redis_key=CONFIG.REDIS_KEY, redis_conf=CONFIG.REDIS ) - if last_talk and await self._llm.is_related(last_talk, history_summary): # Merge relevant content. - last_talk = await self._llm.rewrite(sentence=last_talk, context=history_text) - return last_talk + # if last_talk and await self._llm.is_related(last_talk, history_summary): # Merge relevant content. + # last_talk = await self._llm.rewrite(sentence=last_talk, context=history_text) + # return last_talk + last_talk = await self._llm.rewrite(sentence=last_talk, context=history_text) return last_talk From f450b61bc215ad70fbafb14e153a0cd905e203e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 22:13:10 +0800 Subject: [PATCH 15/43] refactor: think --- metagpt/provider/openai_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 90fcd7ab3..462d9d12d 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -286,7 +286,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): # command = ( # f"{context}\n\nConsidering the content above, rewrite and return this sentence brief and clear:\n{sentence}" # ) - command = f"{context}\n\nExtract relevant information from every preceding sentence and use it to succinctly supplement or rewrite the following text:\n{sentence}" + command = f"{context}\n\nExtract relevant information from every preceding sentence and use it to succinctly supplement or rewrite the following text in brief and clear:\n{sentence}" rsp = await self.aask(msg=command, system_msgs=[]) return rsp From cb17a17b4aa02552c6d99af6e18dbb8946ace33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 22:20:39 +0800 Subject: [PATCH 16/43] refactor: think --- metagpt/roles/assistant.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 7fd1b1236..a988572f4 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -129,10 +129,9 @@ class Assistant(Role): await self.memory.set_history_summary( history_summary=history_summary, redis_key=CONFIG.REDIS_KEY, redis_conf=CONFIG.REDIS ) - # if last_talk and await self._llm.is_related(last_talk, history_summary): # Merge relevant content. - # last_talk = await self._llm.rewrite(sentence=last_talk, context=history_text) - # return last_talk - last_talk = await self._llm.rewrite(sentence=last_talk, context=history_text) + if last_talk and await self._llm.is_related(last_talk, history_summary): # Merge relevant content. + last_talk = await self._llm.rewrite(sentence=last_talk, context=history_text) + return last_talk return last_talk From 1e39618b972bb9b9d55d53b1256c413451ecd289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 22:29:49 +0800 Subject: [PATCH 17/43] refactor: think --- metagpt/roles/assistant.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index a988572f4..0a6237f42 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -60,8 +60,7 @@ class Assistant(Role): prompt += ( f"If want you to do {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" ) - prompt += "If the preceding text presents a complete question and solution, rewrite and return `[SOLUTION]: {problem}` brief and clear. For instance: [SOLUTION]: Solution for distributing watermelon\n" - prompt += "If the preceding text presents an unresolved issue and its corresponding discussion, rewrite and return `[PROBLEM]: {problem}` brief and clear. For instance: [PROBLEM]: How to distribute watermelon?\n" + prompt += "If the user's intent is unclear, return `[TALK]: {talk}` brief and clear. For instance: [TALK]: distribute watermelon\n" prompt += "Otherwise, return `[TALK]: {talk}` brief and clear. For instance: [TALK]: distribute watermelon" logger.info(prompt) rsp = await self._llm.aask(prompt, []) @@ -90,7 +89,6 @@ class Assistant(Role): skill, text = Assistant.extract_info(input_string=rsp) handlers = { MessageType.Talk.value: self.talk_handler, - MessageType.Problem.value: self.talk_handler, MessageType.Skill.value: self.skill_handler, } handler = handlers.get(skill, self.talk_handler) From 80b934d41ac5e6cdc559586fdfe5a699bad0c149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 22:33:55 +0800 Subject: [PATCH 18/43] refactor: think --- metagpt/provider/openai_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 462d9d12d..7139c4946 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -277,7 +277,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): async def is_related(self, text1, text2): # command = f"{text1}\n{text2}\n\nIf the two sentences above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." - command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any, return [TRUE] brief and clear. Otherwise, return [FALSE]." + command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any relevance, return [TRUE] brief and clear. Otherwise, return [FALSE]." rsp = await self.aask(msg=command, system_msgs=[]) result, _ = self.extract_info(rsp) return result == "TRUE" From fa0b0b15114899e6724f081b7aa8f0dbfd9fbb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 22:43:21 +0800 Subject: [PATCH 19/43] refactor: think --- metagpt/roles/assistant.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 0a6237f42..c0d1c3240 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -57,10 +57,7 @@ class Assistant(Role): prompt = f"Refer to this sentence:\n {last_talk}\n" skills = self.skills.get_skill_list() for desc, name in skills.items(): - prompt += ( - f"If want you to do {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" - ) - prompt += "If the user's intent is unclear, return `[TALK]: {talk}` brief and clear. For instance: [TALK]: distribute watermelon\n" + prompt += f"If explicitly want you to do {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" prompt += "Otherwise, return `[TALK]: {talk}` brief and clear. For instance: [TALK]: distribute watermelon" logger.info(prompt) rsp = await self._llm.aask(prompt, []) From e2ffba863127b376afa53f3165816544206572bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 22:51:14 +0800 Subject: [PATCH 20/43] refactor: think --- metagpt/roles/assistant.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index c0d1c3240..86a27cb18 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -58,7 +58,9 @@ class Assistant(Role): skills = self.skills.get_skill_list() for desc, name in skills.items(): prompt += f"If explicitly want you to do {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" - prompt += "Otherwise, return `[TALK]: {talk}` brief and clear. For instance: [TALK]: distribute watermelon" + prompt += ( + 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx' + ) logger.info(prompt) rsp = await self._llm.aask(prompt, []) logger.info(rsp) From e25e19eb8fe6a4392766adf14f6456a649f023d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 22:59:36 +0800 Subject: [PATCH 21/43] refactor: think --- metagpt/provider/openai_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 7139c4946..949b252b2 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -277,7 +277,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): async def is_related(self, text1, text2): # command = f"{text1}\n{text2}\n\nIf the two sentences above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." - command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any relevance, return [TRUE] brief and clear. Otherwise, return [FALSE]." + command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any relevance, return [TRUE] brief and clear. Otherwise, return [FALSE] brief and clear." rsp = await self.aask(msg=command, system_msgs=[]) result, _ = self.extract_info(rsp) return result == "TRUE" From 703b2a9a2418f3184ecad157b76e28112983cbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 23:15:11 +0800 Subject: [PATCH 22/43] refactor: think --- metagpt/provider/openai_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 949b252b2..e352ff54f 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -277,7 +277,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): async def is_related(self, text1, text2): # command = f"{text1}\n{text2}\n\nIf the two sentences above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." - command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any relevance, return [TRUE] brief and clear. Otherwise, return [FALSE] brief and clear." + command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any relevance, return [TRUE]:1 brief and clear. Otherwise, return [FALSE]:1 brief and clear." rsp = await self.aask(msg=command, system_msgs=[]) result, _ = self.extract_info(rsp) return result == "TRUE" From a147bdf92a306553bc93580b085102fb0efd7295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 23:18:18 +0800 Subject: [PATCH 23/43] refactor: think --- metagpt/provider/openai_api.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index e352ff54f..bbceac1d2 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -318,8 +318,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): return windows @staticmethod - def extract_info(input_string): - pattern = r"\[([A-Z]+)\]:\s*(.+)" + def extract_info(input_string, pattern=r"\[([A-Z]+)\]:\s*(.+)"): match = re.match(pattern, input_string) if match: return match.group(1), match.group(2) From c8e24aa39b60cdea52664a29f6c52180c04d31be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 23:20:13 +0800 Subject: [PATCH 24/43] refactor: think --- metagpt/provider/openai_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index bbceac1d2..30b82b8dc 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -277,9 +277,9 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): async def is_related(self, text1, text2): # command = f"{text1}\n{text2}\n\nIf the two sentences above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." - command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any relevance, return [TRUE]:1 brief and clear. Otherwise, return [FALSE]:1 brief and clear." + command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any relevance, return [TRUE] brief and clear. Otherwise, return [FALSE] brief and clear." rsp = await self.aask(msg=command, system_msgs=[]) - result, _ = self.extract_info(rsp) + result, _ = self.extract_info(rsp, pattern=r"\[([A-Z]+)\]\s*(.+)") return result == "TRUE" async def rewrite(self, sentence: str, context: str): From 558f80b238a1da513046351dab31c97598fa3282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 5 Sep 2023 23:35:24 +0800 Subject: [PATCH 25/43] refactor: think --- metagpt/roles/assistant.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 86a27cb18..428c1a70f 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -54,10 +54,10 @@ class Assistant(Role): last_talk = await self.refine_memory() if not last_talk: return False - prompt = f"Refer to this sentence:\n {last_talk}\n" + prompt = f"Refer to this text:\n {last_talk}\n" skills = self.skills.get_skill_list() for desc, name in skills.items(): - prompt += f"If explicitly want you to do {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" + prompt += f"If the text explicitly want you to do {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" prompt += ( 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx' ) From 04231088c7717241df1da275f1c553854188897c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 10:14:31 +0800 Subject: [PATCH 26/43] refactor: think --- metagpt/roles/assistant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 428c1a70f..6530a3cac 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -57,7 +57,7 @@ class Assistant(Role): prompt = f"Refer to this text:\n {last_talk}\n" skills = self.skills.get_skill_list() for desc, name in skills.items(): - prompt += f"If the text explicitly want you to do {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" + prompt += f"If the text explicitly want you to {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" prompt += ( 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx' ) From ac211ae3a6ed9df419585b70d6a6765223a6aaf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 10:17:21 +0800 Subject: [PATCH 27/43] refactor: think --- metagpt/roles/assistant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 6530a3cac..516f78b0e 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -63,7 +63,7 @@ class Assistant(Role): ) logger.info(prompt) rsp = await self._llm.aask(prompt, []) - logger.info(rsp) + logger.info(f"THINK: {prompt}\n, THINK RESULT: {rsp}\n") return await self._plan(rsp, last_talk=last_talk) async def act(self) -> ActionOutput: From 092243670f7e9e716187be27843c7d11aff6b832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 10:23:29 +0800 Subject: [PATCH 28/43] feat: +log --- metagpt/provider/openai_api.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 30b82b8dc..99f281964 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -280,6 +280,9 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any relevance, return [TRUE] brief and clear. Otherwise, return [FALSE] brief and clear." rsp = await self.aask(msg=command, system_msgs=[]) result, _ = self.extract_info(rsp, pattern=r"\[([A-Z]+)\]\s*(.+)") + p2 = text2.replace("\n", "") + p1 = text1.replace("\n", "") + logger.info(f"IS_RELATED:\nParagraph 1: {p2}\nParagraph 2: {p1}\nRESULT: {result}") return result == "TRUE" async def rewrite(self, sentence: str, context: str): @@ -288,6 +291,7 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): # ) command = f"{context}\n\nExtract relevant information from every preceding sentence and use it to succinctly supplement or rewrite the following text in brief and clear:\n{sentence}" rsp = await self.aask(msg=command, system_msgs=[]) + logger.info(f"REWRITE:\nCommand: {command}\nRESULT: {rsp}") return rsp @staticmethod From 6f55709ec599f804dcaefd86b4260e6ec6024f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 10:31:21 +0800 Subject: [PATCH 29/43] feat: +log --- metagpt/provider/openai_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 99f281964..d84109f6a 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -279,11 +279,11 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): # command = f"{text1}\n{text2}\n\nIf the two sentences above are related, return [TRUE] brief and clear. Otherwise, return [FALSE]." command = f"{text2}\n\nIs there any sentence above related to the following sentence: {text1}.\nIf is there any relevance, return [TRUE] brief and clear. Otherwise, return [FALSE] brief and clear." rsp = await self.aask(msg=command, system_msgs=[]) - result, _ = self.extract_info(rsp, pattern=r"\[([A-Z]+)\]\s*(.+)") + result = True if "TRUE" in rsp else False p2 = text2.replace("\n", "") p1 = text1.replace("\n", "") logger.info(f"IS_RELATED:\nParagraph 1: {p2}\nParagraph 2: {p1}\nRESULT: {result}") - return result == "TRUE" + return result async def rewrite(self, sentence: str, context: str): # command = ( From 8f8a5e185a84ebccc5bad58fa0a21fa963613cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 10:41:30 +0800 Subject: [PATCH 30/43] refactor: think --- metagpt/roles/assistant.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 516f78b0e..bae1b6c79 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -54,13 +54,12 @@ class Assistant(Role): last_talk = await self.refine_memory() if not last_talk: return False - prompt = f"Refer to this text:\n {last_talk}\n" + prompt = "" skills = self.skills.get_skill_list() for desc, name in skills.items(): prompt += f"If the text explicitly want you to {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" - prompt += ( - 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx' - ) + prompt += 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx\n\n' + prompt = f"Now the text is: {last_talk}" logger.info(prompt) rsp = await self._llm.aask(prompt, []) logger.info(f"THINK: {prompt}\n, THINK RESULT: {rsp}\n") From 8695a042e99cc61efeedbf2bde9c2db0525f5751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 10:49:06 +0800 Subject: [PATCH 31/43] refactor: think --- metagpt/roles/assistant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index bae1b6c79..a615c3933 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -59,7 +59,7 @@ class Assistant(Role): for desc, name in skills.items(): prompt += f"If the text explicitly want you to {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" prompt += 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx\n\n' - prompt = f"Now the text is: {last_talk}" + prompt += f"Now the text is: {last_talk}" logger.info(prompt) rsp = await self._llm.aask(prompt, []) logger.info(f"THINK: {prompt}\n, THINK RESULT: {rsp}\n") From 2ff563e6b6261bf04116991f92ba0c3bacad920d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 11:01:21 +0800 Subject: [PATCH 32/43] refactor: think --- metagpt/roles/assistant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index a615c3933..743ec7c43 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -59,7 +59,7 @@ class Assistant(Role): for desc, name in skills.items(): prompt += f"If the text explicitly want you to {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" prompt += 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx\n\n' - prompt += f"Now the text is: {last_talk}" + prompt += f"Now determine the appropriate pattern for the text: {last_talk}" logger.info(prompt) rsp = await self._llm.aask(prompt, []) logger.info(f"THINK: {prompt}\n, THINK RESULT: {rsp}\n") From 5f5fda42730cbc2e6441e20260bf246a6ee98e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 11:03:25 +0800 Subject: [PATCH 33/43] refactor: think --- metagpt/roles/assistant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 743ec7c43..07991da1a 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -59,7 +59,7 @@ class Assistant(Role): for desc, name in skills.items(): prompt += f"If the text explicitly want you to {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" prompt += 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx\n\n' - prompt += f"Now determine the appropriate pattern for the text: {last_talk}" + prompt += f"Now determine the appropriate pattern for the text: {last_talk}\n" logger.info(prompt) rsp = await self._llm.aask(prompt, []) logger.info(f"THINK: {prompt}\n, THINK RESULT: {rsp}\n") From db72848965b29400a9235f7432a0a85cd3206ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 11:17:32 +0800 Subject: [PATCH 34/43] refactor: think --- metagpt/roles/assistant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 07991da1a..d310fca7c 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -59,7 +59,7 @@ class Assistant(Role): for desc, name in skills.items(): prompt += f"If the text explicitly want you to {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" prompt += 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx\n\n' - prompt += f"Now determine the appropriate pattern for the text: {last_talk}\n" + prompt += f"Now what specific action does the text explicitly ask for: {last_talk}\n" logger.info(prompt) rsp = await self._llm.aask(prompt, []) logger.info(f"THINK: {prompt}\n, THINK RESULT: {rsp}\n") From 341bbbe4ba8a1e959158724196b9a8529d4211dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 6 Sep 2023 11:33:40 +0800 Subject: [PATCH 35/43] refactor: think --- metagpt/roles/assistant.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index d310fca7c..bef2cf53c 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -59,8 +59,7 @@ class Assistant(Role): for desc, name in skills.items(): prompt += f"If the text explicitly want you to {desc}, return `[SKILL]: {name}` brief and clear. For instance: [SKILL]: {name}\n" prompt += 'Otherwise, return `[TALK]: {talk}` brief and clear. For instance: if {talk} is "xxxx" return [TALK]: xxxx\n\n' - prompt += f"Now what specific action does the text explicitly ask for: {last_talk}\n" - logger.info(prompt) + prompt += f"Now what specific action is explicitly mentioned in the text: {last_talk}\n" rsp = await self._llm.aask(prompt, []) logger.info(f"THINK: {prompt}\n, THINK RESULT: {rsp}\n") return await self._plan(rsp, last_talk=last_talk) From 768e934444bb0c2180240a9671eb61ce3218471d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Fri, 15 Sep 2023 17:32:45 +0800 Subject: [PATCH 36/43] refactor: uuid --- metagpt/tools/iflytek_tts.py | 2 +- metagpt/utils/s3.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/metagpt/tools/iflytek_tts.py b/metagpt/tools/iflytek_tts.py index a91d8091b..cb87d2e7f 100644 --- a/metagpt/tools/iflytek_tts.py +++ b/metagpt/tools/iflytek_tts.py @@ -136,7 +136,7 @@ async def oas3_iflytek_tts(text: str, voice: str = "", app_id: str = "", api_key if not voice: voice = CONFIG.IFLYTEK_VOICE or DEFAULT_IFLYTEK_VOICE - filename = Path(__file__).parent / (str(uuid.uuid4()).replace("-", "") + ".mp3") + filename = Path(__file__).parent / (uuid.uuid4().hex + ".mp3") try: tts = IFlyTekTTS(app_id=app_id, api_key=api_key, api_secret=api_secret) await tts.synthesize_speech(text=text, output_file=str(filename), voice=voice) diff --git a/metagpt/utils/s3.py b/metagpt/utils/s3.py index 96b457972..dde68f720 100644 --- a/metagpt/utils/s3.py +++ b/metagpt/utils/s3.py @@ -132,7 +132,7 @@ class S3: async def cache(self, data: str, file_ext: str, format: str = "") -> str: """Save data to remote S3 and return url""" - object_name = str(uuid.uuid4()).replace("-", "") + file_ext + object_name = uuid.uuid4().hex + file_ext path = Path(__file__).parent pathname = path / object_name try: From 89be81524c963a64e5e21c4cc05126bf289eb63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Fri, 15 Sep 2023 21:56:39 +0800 Subject: [PATCH 37/43] feat: update skill specification --- .well-known/skills.yaml | 213 +++++++++++++++++++++++----------- metagpt/learn/skill_loader.py | 61 +++++++--- 2 files changed, 189 insertions(+), 85 deletions(-) diff --git a/.well-known/skills.yaml b/.well-known/skills.yaml index d08d7aced..137bfcdb4 100644 --- a/.well-known/skills.yaml +++ b/.well-known/skills.yaml @@ -1,72 +1,149 @@ +skillapi: "0.1.0" + +info: + title: "Agent Skill Specification" + version: "1.0" + entities: Assistant: - skills: - - name: text_to_speech - description: Text-to-speech - id: text_to_speech.text_to_speech - x-prerequisite: - - name: AZURE_TTS_SUBSCRIPTION_KEY - description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" - - name: AZURE_TTS_REGION - description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" - arguments: - text: 'The text used for voice conversion. Required.' - lang: 'The value can contain a language code such as en (English), or a locale such as en-US (English - United States). The optional parameter are "English", "Chinese". Default value: "Chinese".' - voice: 'Default value: "zh-CN-XiaomoNeural".' - style: 'Speaking style to express different emotions like cheerfulness, empathy, and calm. The optional parameter values are "affectionate", "angry", "calm", "cheerful", "depressed", "disgruntled", "embarrassed", "envious", "fearful", "gentle", "sad", "serious". Default value: "affectionate".' - role: 'With roles, the same voice can act as a different age and gender. The optional parameter values are "Girl", "Boy", "OlderAdultFemale", "OlderAdultMale", "SeniorFemale", "SeniorMale", "YoungAdultFemale", "YoungAdultMale". Default value: "Girl".' - examples: - - ask: 'A girl says "hello world"' - answer: 'text_to_speech(text="hello world", role="Girl")' - - ask: 'A boy affectionate says "hello world"' - answer: 'text_to_speech(text="hello world", role="Boy", style="affectionate")' - - ask: 'A boy says "你好"' - answer: 'text_to_speech(text="你好", role="Boy", lang="Chinese")' - - ask: 'How to speak "你好"?' - answer: 'text_to_speech(text="你好", lang="Chinese")' - returns: - type: string - format: base64 + summary: assistant + description: assistant + skills: + - name: text_to_speech + description: Text-to-speech + id: text_to_speech.text_to_speech + required: + oneOf: + - schema: + type: object + properties: + AZURE_TTS_SUBSCRIPTION_KEY: + type: string + description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" + AZURE_TTS_REGION: + type: string + description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" + - schema: + type: object + properties: + IFLYTEK_APP_ID: + type: string + description: "Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts`" + IFLYTEK_API_KEY: + type: string + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + IFLYTEK_API_SECRET: + type: string + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + parameters: + text: + description: 'The text used for voice conversion.' + required: true + type: string + lang: + description: 'The value can contain a language code such as en (English), or a locale such as en-US (English - United States).' + type: string + enum: + - English + - Chinese + default: Chinese + voice: + description: Name of voice styles + type: string + default: zh-CN-XiaomoNeural + style: + type: string + description: Speaking style to express different emotions like cheerfulness, empathy, and calm. + enum: + - affectionate + - angry + - calm + - cheerful + - depressed + - disgruntled + - embarrassed + - envious + - fearful + - gentle + - sad + - serious + default: affectionate + role: + type: string + description: With roles, the same voice can act as a different age and gender. + enum: + - Girl + - Boy + - OlderAdultFemale + - OlderAdultMale + - SeniorFemale + - SeniorMale + - YoungAdultFemale + - YoungAdultMale + default: Girl + examples: + - ask: 'A girl says "hello world"' + answer: 'text_to_speech(text="hello world", role="Girl")' + - ask: 'A boy affectionate says "hello world"' + answer: 'text_to_speech(text="hello world", role="Boy", style="affectionate")' + - ask: 'A boy says "你好"' + answer: 'text_to_speech(text="hello world", role="Boy", lang="Chinese")' + returns: + type: string + format: base64 - - name: text_to_image - description: Create a drawing based on the text. - id: text_to_image.text_to_image - x-prerequisite: - - name: OPENAI_API_KEY - description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`" - - name: METAGPT_TEXT_TO_IMAGE_MODEL_URL - description: "Model url." - arguments: - text: 'The text used for image conversion. Required.' - size_type: 'Default value: "512x512".' - examples: - - ask: 'Draw a girl' - answer: 'text_to_image(text="Draw a girl", size_type="512x512")' - - ask: 'Draw an apple' - answer: 'text_to_image(text="Draw an apple", size_type="512x512")' - - ask: 'Draw an apple picture' - answer: 'text_to_image(text="Draw an apple", size_type="512x512")' - - ask: 'Draw an apple image' - answer: 'text_to_image(text="Draw an apple", size_type="512x512")' - returns: - type: string - format: base64 + - name: text_to_image + description: Create a drawing based on the text. + id: text_to_image.text_to_image + required: + oneOf: + - name: OPENAI_API_KEY + type: string + description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`" + - name: METAGPT_TEXT_TO_IMAGE_MODEL_URL + type: string + description: "Model url." + parameters: + text: + description: 'The text used for image conversion.' + type: string + required: true + size_type: + description: size type + type: string + default: "512x512" + examples: + - ask: 'Draw a girl' + answer: 'text_to_image(text="Draw a girl", size_type="512x512")' + - ask: 'Draw an apple' + answer: 'text_to_image(text="Draw an apple", size_type="512x512")' + returns: + type: string + format: base64 - - name: web_search - description: Perform Google searches to provide real-time information. - id: web_search.web_search - x-prerequisite: - - name: SEARCH_ENGINE - description: "Supported values: serpapi/google/serper/ddg" - - name: SERPER_API_KEY - description: "SERPER API KEY, For more details, checkout: `https://serper.dev/api-key`" - arguments: - query: 'The search query. Required.' - max_results: 'The number of search results to retrieve. Default value: 6.' - examples: - - ask: 'Search for information about artificial intelligence' - answer: 'web_search(query="Search for information about artificial intelligence", max_results=6)' - - ask: 'Find news articles about climate change' - answer: 'web_search(query="Find news articles about climate change", max_results=6)' - returns: - type: string \ No newline at end of file + - name: web_search + description: Perform Google searches to provide real-time information. + id: web_search.web_search + required: + - name: SEARCH_ENGINE + type: string + description: "Supported values: serpapi/google/serper/ddg" + - name: SERPER_API_KEY + type: string + description: "SERPER API KEY, For more details, checkout: `https://serper.dev/api-key`" + parameters: + query: + type: string + description: 'The search query.' + required: true + max_results: + type: number + default: 6 + description: 'The number of search results to retrieve.' + examples: + - ask: 'Search for information about artificial intelligence' + answer: 'web_search(query="Search for information about artificial intelligence", max_results=6)' + - ask: 'Find news articles about climate change' + answer: 'web_search(query="Find news articles about climate change", max_results=6)' + returns: + type: string diff --git a/metagpt/learn/skill_loader.py b/metagpt/learn/skill_loader.py index 83200bca6..b1d27db92 100644 --- a/metagpt/learn/skill_loader.py +++ b/metagpt/learn/skill_loader.py @@ -7,10 +7,10 @@ @Desc : Skill YAML Configuration Loader. """ from pathlib import Path -from typing import Dict, List, Optional +from typing import Dict, List, Optional, Union import yaml -from pydantic import BaseModel, Field +from pydantic import BaseModel from metagpt.config import CONFIG @@ -25,29 +25,43 @@ class Returns(BaseModel): format: Optional[str] = None -class Prerequisite(BaseModel): - name: str - type: Optional[str] = None - description: Optional[str] = None - default: Optional[str] = None +class Parameter(BaseModel): + type: str + description: str = None class Skill(BaseModel): name: str - description: str - id: str - x_prerequisite: Optional[List[Prerequisite]] = Field(default=None, alias="x-prerequisite") - arguments: Dict + description: str = None + id: str = None + required: Optional[Union[List, Dict]] = None + parameters: Dict[str, Parameter] = None examples: List[Example] returns: Returns + @property + def arguments(self) -> Dict: + if not self.parameters: + return {} + ret = {} + for k, v in self.parameters.items(): + ret[k] = v.description if v.description else "" + return ret -class EntitySkills(BaseModel): + +class Entity(BaseModel): + name: str = None skills: List[Skill] +class Components(BaseModel): + pass + + class SkillsDeclaration(BaseModel): - entities: Dict[str, EntitySkills] + skillapi: str + entities: Dict[str, Entity] + components: Components = None class SkillLoader: @@ -60,8 +74,8 @@ class SkillLoader: def get_skill_list(self, entity_name: str = "Assistant") -> Dict: """Return the skill name based on the skill description.""" - entity_skills = self.get_entity(entity_name) - if not entity_skills: + entity = self.get_entity(entity_name) + if not entity: return {} agent_skills = CONFIG.agent_skills @@ -73,7 +87,7 @@ class SkillLoader: names = [AgentSkill(**i).name for i in agent_skills] description_to_name_mappings = {} - for s in entity_skills.skills: + for s in entity.skills: if s.name not in names: continue description_to_name_mappings[s.description] = s.name @@ -89,8 +103,21 @@ class SkillLoader: if sk.name == name: return sk - def get_entity(self, name) -> EntitySkills: + def get_entity(self, name) -> Entity: """Return a list of skills for the entity.""" if not self._skills: return None return self._skills.entities.get(name) + + +if __name__ == "__main__": + CONFIG.agent_skills = [ + {"id": 1, "name": "text_to_speech", "type": "builtin", "config": {}, "enabled": True}, + {"id": 2, "name": "text_to_image", "type": "builtin", "config": {}, "enabled": True}, + {"id": 3, "name": "ai_call", "type": "builtin", "config": {}, "enabled": True}, + {"id": 3, "name": "data_analysis", "type": "builtin", "config": {}, "enabled": True}, + {"id": 5, "name": "crawler", "type": "builtin", "config": {"engine": "ddg"}, "enabled": True}, + {"id": 6, "name": "knowledge", "type": "builtin", "config": {}, "enabled": True}, + ] + loader = SkillLoader() + print(loader.get_skill_list()) From 9fdf70658608d2a91d3648bf155d0ff4fa5b7d82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Sat, 16 Sep 2023 10:37:27 +0800 Subject: [PATCH 38/43] feat: +type --- .well-known/metagpt_oas3_api.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.well-known/metagpt_oas3_api.yaml b/.well-known/metagpt_oas3_api.yaml index 1e3cecb10..e21cc2d01 100644 --- a/.well-known/metagpt_oas3_api.yaml +++ b/.well-known/metagpt_oas3_api.yaml @@ -14,8 +14,10 @@ paths: /tts/azsure: x-prerequisite: - name: AZURE_TTS_SUBSCRIPTION_KEY + type: string description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" - name: AZURE_TTS_REGION + type: string description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" post: summary: "Convert Text to Base64-encoded .wav File Stream" @@ -76,10 +78,13 @@ paths: /tts/iflytek: x-prerequisite: - name: IFLYTEK_APP_ID + type: string description: "Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts`" - name: IFLYTEK_API_KEY + type: string description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" - name: IFLYTEK_API_SECRET + type: string description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" post: summary: "Convert Text to Base64-encoded .mp3 File Stream" @@ -133,6 +138,7 @@ paths: /txt2img/openai: x-prerequisite: - name: OPENAI_API_KEY + type: string description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`" post: summary: "Convert Text to Base64-encoded Image Data Stream" @@ -174,6 +180,7 @@ paths: /txt2embedding/openai: x-prerequisite: - name: OPENAI_API_KEY + type: string description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`" post: summary: Text to embedding @@ -216,6 +223,7 @@ paths: /txt2image/metagpt: x-prerequisite: - name: METAGPT_TEXT_TO_IMAGE_MODEL_URL + type: string description: "Model url." post: summary: "Text to Image" From b4493052e7a3eb2533e5a642491a5e9c1c0e5e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Sat, 16 Sep 2023 14:56:38 +0800 Subject: [PATCH 39/43] feat: +x-prerequisite --- .well-known/metagpt_oas3_api.yaml | 71 ++++++++++++++++--------- .well-known/skills.yaml | 86 ++++++++++++++++++------------- 2 files changed, 96 insertions(+), 61 deletions(-) diff --git a/.well-known/metagpt_oas3_api.yaml b/.well-known/metagpt_oas3_api.yaml index e21cc2d01..0a702e8b6 100644 --- a/.well-known/metagpt_oas3_api.yaml +++ b/.well-known/metagpt_oas3_api.yaml @@ -13,12 +13,17 @@ servers: paths: /tts/azsure: x-prerequisite: - - name: AZURE_TTS_SUBSCRIPTION_KEY - type: string - description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" - - name: AZURE_TTS_REGION - type: string - description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" + configurations: + AZURE_TTS_SUBSCRIPTION_KEY: + type: string + description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" + AZURE_TTS_REGION: + type: string + description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" + required: + allOf: + - AZURE_TTS_SUBSCRIPTION_KEY + - AZURE_TTS_REGION post: summary: "Convert Text to Base64-encoded .wav File Stream" description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" @@ -77,15 +82,21 @@ paths: /tts/iflytek: x-prerequisite: - - name: IFLYTEK_APP_ID - type: string - description: "Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts`" - - name: IFLYTEK_API_KEY - type: string - description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" - - name: IFLYTEK_API_SECRET - type: string - description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + configurations: + IFLYTEK_APP_ID: + type: string + description: "Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts`" + IFLYTEK_API_KEY: + type: string + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + IFLYTEK_API_SECRET: + type: string + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + required: + allOf: + - IFLYTEK_APP_ID + - IFLYTEK_API_KEY + - IFLYTEK_API_SECRET post: summary: "Convert Text to Base64-encoded .mp3 File Stream" description: "For more details, check out: [iFlyTek](https://console.xfyun.cn/services/tts)" @@ -137,9 +148,13 @@ paths: /txt2img/openai: x-prerequisite: - - name: OPENAI_API_KEY - type: string - description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`" + configurations: + OPENAI_API_KEY: + type: string + description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`" + required: + allOf: + - OPENAI_API_KEY post: summary: "Convert Text to Base64-encoded Image Data Stream" operationId: openai_text_to_image.oas3_openai_text_to_image @@ -179,9 +194,13 @@ paths: description: "Internal Server Error" /txt2embedding/openai: x-prerequisite: - - name: OPENAI_API_KEY - type: string - description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`" + configurations: + OPENAI_API_KEY: + type: string + description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`" + required: + allOf: + - OPENAI_API_KEY post: summary: Text to embedding operationId: openai_text_to_embedding.oas3_openai_text_to_embedding @@ -222,9 +241,13 @@ paths: /txt2image/metagpt: x-prerequisite: - - name: METAGPT_TEXT_TO_IMAGE_MODEL_URL - type: string - description: "Model url." + configurations: + METAGPT_TEXT_TO_IMAGE_MODEL_URL: + type: string + description: "Model url." + required: + allOf: + - METAGPT_TEXT_TO_IMAGE_MODEL_URL post: summary: "Text to Image" description: "Generate an image from the provided text using the MetaGPT Text-to-Image API." diff --git a/.well-known/skills.yaml b/.well-known/skills.yaml index 137bfcdb4..05465454a 100644 --- a/.well-known/skills.yaml +++ b/.well-known/skills.yaml @@ -12,29 +12,32 @@ entities: - name: text_to_speech description: Text-to-speech id: text_to_speech.text_to_speech - required: - oneOf: - - schema: - type: object - properties: - AZURE_TTS_SUBSCRIPTION_KEY: - type: string - description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" - AZURE_TTS_REGION: - type: string - description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" - - schema: - type: object - properties: - IFLYTEK_APP_ID: - type: string - description: "Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts`" - IFLYTEK_API_KEY: - type: string - description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" - IFLYTEK_API_SECRET: - type: string - description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + x-prerequisite: + configurations: + AZURE_TTS_SUBSCRIPTION_KEY: + type: string + description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" + AZURE_TTS_REGION: + type: string + description: "For more details, check out: [Azure Text-to_Speech](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)" + IFLYTEK_APP_ID: + type: string + description: "Application ID is used to access your iFlyTek service API, see: `https://console.xfyun.cn/services/tts`" + IFLYTEK_API_KEY: + type: string + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + IFLYTEK_API_SECRET: + type: string + description: "WebAPI argument, see: `https://console.xfyun.cn/services/tts`" + required: + oneOf: + - allOf: + - AZURE_TTS_SUBSCRIPTION_KEY + - AZURE_TTS_REGION + - allOf: + - IFLYTEK_APP_ID + - IFLYTEK_API_KEY + - IFLYTEK_API_SECRET parameters: text: description: 'The text used for voice conversion.' @@ -51,9 +54,9 @@ entities: description: Name of voice styles type: string default: zh-CN-XiaomoNeural - style: + style: type: string - description: Speaking style to express different emotions like cheerfulness, empathy, and calm. + description: Speaking style to express different emotions like cheerfulness, empathy, and calm. enum: - affectionate - angry @@ -95,16 +98,20 @@ entities: - name: text_to_image description: Create a drawing based on the text. id: text_to_image.text_to_image - required: - oneOf: - - name: OPENAI_API_KEY + x-prerequisite: + configurations: + OPENAI_API_KEY: type: string description: "OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`" - - name: METAGPT_TEXT_TO_IMAGE_MODEL_URL + METAGPT_TEXT_TO_IMAGE_MODEL_URL: type: string description: "Model url." + required: + oneOf: + - OPENAI_API_KEY + - METAGPT_TEXT_TO_IMAGE_MODEL_URL parameters: - text: + text: description: 'The text used for image conversion.' type: string required: true @@ -124,13 +131,18 @@ entities: - name: web_search description: Perform Google searches to provide real-time information. id: web_search.web_search - required: - - name: SEARCH_ENGINE - type: string - description: "Supported values: serpapi/google/serper/ddg" - - name: SERPER_API_KEY - type: string - description: "SERPER API KEY, For more details, checkout: `https://serper.dev/api-key`" + x-prerequisite: + configurations: + SEARCH_ENGINE: + type: string + description: "Supported values: serpapi/google/serper/ddg" + SERPER_API_KEY: + type: string + description: "SERPER API KEY, For more details, checkout: `https://serper.dev/api-key`" + required: + allOf: + - SEARCH_ENGINE + - SERPER_API_KEY parameters: query: type: string From ad71adb2091bbefb948cad48bc70c74891226bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Sat, 16 Sep 2023 15:02:24 +0800 Subject: [PATCH 40/43] feat: +x-prerequisite --- metagpt/learn/skill_loader.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/metagpt/learn/skill_loader.py b/metagpt/learn/skill_loader.py index b1d27db92..dff5e26ae 100644 --- a/metagpt/learn/skill_loader.py +++ b/metagpt/learn/skill_loader.py @@ -7,10 +7,10 @@ @Desc : Skill YAML Configuration Loader. """ from pathlib import Path -from typing import Dict, List, Optional, Union +from typing import Dict, List, Optional import yaml -from pydantic import BaseModel +from pydantic import BaseModel, Field from metagpt.config import CONFIG @@ -34,7 +34,7 @@ class Skill(BaseModel): name: str description: str = None id: str = None - required: Optional[Union[List, Dict]] = None + x_prerequisite: Dict = Field(default=None, alias="x-prerequisite") parameters: Dict[str, Parameter] = None examples: List[Example] returns: Returns From 4bf3510832e1114c9418b56d02f215c48334964f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 19 Sep 2023 14:13:28 +0800 Subject: [PATCH 41/43] feat: +unit test --- tests/metagpt/learn/test_skill_loader.py | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/metagpt/learn/test_skill_loader.py diff --git a/tests/metagpt/learn/test_skill_loader.py b/tests/metagpt/learn/test_skill_loader.py new file mode 100644 index 000000000..5bc0e776f --- /dev/null +++ b/tests/metagpt/learn/test_skill_loader.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@Time : 2023/9/19 +@Author : mashenquan +@File : test_skill_loader.py +@Desc : Unit tests. +""" + +from metagpt.config import CONFIG +from metagpt.learn.skill_loader import SkillLoader + + +def test_suite(): + CONFIG.agent_skills = [ + {"id": 1, "name": "text_to_speech", "type": "builtin", "config": {}, "enabled": True}, + {"id": 2, "name": "text_to_image", "type": "builtin", "config": {}, "enabled": True}, + {"id": 3, "name": "ai_call", "type": "builtin", "config": {}, "enabled": True}, + {"id": 3, "name": "data_analysis", "type": "builtin", "config": {}, "enabled": True}, + {"id": 5, "name": "crawler", "type": "builtin", "config": {"engine": "ddg"}, "enabled": True}, + {"id": 6, "name": "knowledge", "type": "builtin", "config": {}, "enabled": True}, + {"id": 6, "name": "web_search", "type": "builtin", "config": {}, "enabled": True}, + ] + loader = SkillLoader() + skills = loader.get_skill_list() + assert skills + assert len(skills) >= 3 + for desc, name in skills.items(): + assert desc + assert name + + entity = loader.get_entity("Assistant") + assert entity + assert entity.skills + for sk in entity.skills: + assert sk + assert sk.arguments + + +if __name__ == "__main__": + test_suite() From c69928a1745a84bb9a25a040ac50a59a849807ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Tue, 19 Sep 2023 21:33:23 +0800 Subject: [PATCH 42/43] refactor: example --- .well-known/skills.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.well-known/skills.yaml b/.well-known/skills.yaml index 05465454a..c19a9501e 100644 --- a/.well-known/skills.yaml +++ b/.well-known/skills.yaml @@ -10,7 +10,7 @@ entities: description: assistant skills: - name: text_to_speech - description: Text-to-speech + description: Generate a voice file from the input text, text-to-speech id: text_to_speech.text_to_speech x-prerequisite: configurations: @@ -90,7 +90,7 @@ entities: - ask: 'A boy affectionate says "hello world"' answer: 'text_to_speech(text="hello world", role="Boy", style="affectionate")' - ask: 'A boy says "你好"' - answer: 'text_to_speech(text="hello world", role="Boy", lang="Chinese")' + answer: 'text_to_speech(text="你好", role="Boy", lang="Chinese")' returns: type: string format: base64 From 56bf0b9b97c69e0aa0a49ddf35d576945e38d236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 20 Sep 2023 17:45:47 +0800 Subject: [PATCH 43/43] fixbug: max_words --- metagpt/provider/openai_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index 7fc8b867a..953043912 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -228,4 +228,4 @@ class OpenAIGPTAPI(BaseGPTAPI, RateLimiter): from metagpt.memory.brain_memory import BrainMemory memory = BrainMemory(llm_type=LLMType.OPENAI.value, historical_summary=text, cacheable=False) - return await memory.summarize(llm=self, max_length=max_words, keep_language=keep_language) + return await memory.summarize(llm=self, max_words=max_words, keep_language=keep_language)