mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-07-02 16:01:04 +02:00
feat: +unit test
This commit is contained in:
parent
339714261a
commit
6512f40ddd
27 changed files with 333 additions and 151 deletions
|
|
@ -6,6 +6,7 @@
|
|||
@File : text_to_image.py
|
||||
@Desc : Text-to-Image skill, which provides text-to-image functionality.
|
||||
"""
|
||||
import base64
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.const import BASE64_FORMAT
|
||||
|
|
@ -25,11 +26,12 @@ async def text_to_image(text, size_type: str = "512x512", openai_api_key="", mod
|
|||
"""
|
||||
image_declaration = "data:image/png;base64,"
|
||||
if CONFIG.METAGPT_TEXT_TO_IMAGE_MODEL_URL or model_url:
|
||||
base64_data = await oas3_metagpt_text_to_image(text, size_type, model_url)
|
||||
binary_data = await oas3_metagpt_text_to_image(text, size_type, model_url)
|
||||
elif CONFIG.OPENAI_API_KEY or openai_api_key:
|
||||
base64_data = await oas3_openai_text_to_image(text, size_type)
|
||||
binary_data = await oas3_openai_text_to_image(text, size_type)
|
||||
else:
|
||||
raise ValueError("Missing necessary parameters.")
|
||||
base64_data = base64.b64encode(binary_data).decode("utf-8")
|
||||
|
||||
s3 = S3()
|
||||
url = await s3.cache(data=base64_data, file_ext=".png", format=BASE64_FORMAT) if s3.is_valid else ""
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
@File : text_to_speech.py
|
||||
@Desc : Text-to-Speech skill, which provides text-to-speech functionality
|
||||
"""
|
||||
import openai
|
||||
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.const import BASE64_FORMAT
|
||||
|
|
@ -66,7 +65,6 @@ async def text_to_speech(
|
|||
return f"[{text}]({url})"
|
||||
return audio_declaration + base64_data if base64_data else base64_data
|
||||
|
||||
raise openai.InvalidRequestError(
|
||||
message="AZURE_TTS_SUBSCRIPTION_KEY, AZURE_TTS_REGION, IFLYTEK_APP_ID, IFLYTEK_API_KEY, IFLYTEK_API_SECRET error",
|
||||
param={},
|
||||
raise ValueError(
|
||||
"AZURE_TTS_SUBSCRIPTION_KEY, AZURE_TTS_REGION, IFLYTEK_APP_ID, IFLYTEK_API_KEY, IFLYTEK_API_SECRET error"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -96,9 +96,10 @@ async def oas3_azsure_tts(text, lang="", voice="", style="", role="", subscripti
|
|||
async with aiofiles.open(filename, mode="rb") as reader:
|
||||
data = await reader.read()
|
||||
base64_string = base64.b64encode(data).decode("utf-8")
|
||||
filename.unlink()
|
||||
except Exception as e:
|
||||
logger.error(f"text:{text}, error:{e}")
|
||||
return ""
|
||||
finally:
|
||||
filename.unlink(missing_ok=True)
|
||||
|
||||
return base64_string
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
@Desc : Implement the OpenAPI Specification 3.0 demo and use the following command to test the HTTP service:
|
||||
|
||||
curl -X 'POST' \
|
||||
'http://localhost:8080/openapi/greeting/dave' \
|
||||
'http://localhost:8082/openapi/greeting/dave' \
|
||||
-H 'accept: text/plain' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{}'
|
||||
|
|
@ -26,4 +26,4 @@ if __name__ == "__main__":
|
|||
specification_dir = Path(__file__).parent.parent.parent / ".well-known"
|
||||
app = connexion.AsyncApp(__name__, specification_dir=str(specification_dir))
|
||||
app.add_api("openapi.yaml", arguments={"title": "Hello World Example"})
|
||||
app.run(port=8080)
|
||||
app.run(port=8082)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
@File : iflytek_tts.py
|
||||
@Desc : iFLYTEK TTS OAS3 api, which provides text-to-speech functionality
|
||||
"""
|
||||
import asyncio
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
|
|
@ -74,12 +73,13 @@ class IFlyTekTTS(object):
|
|||
await websocket.send(req)
|
||||
|
||||
# receive frames
|
||||
async with aiofiles.open(str(output_file), "w") as writer:
|
||||
async with aiofiles.open(str(output_file), "wb") as writer:
|
||||
while True:
|
||||
v = await websocket.recv()
|
||||
rsp = IFlyTekTTSResponse(**json.loads(v))
|
||||
if rsp.data:
|
||||
await writer.write(rsp.data.audio)
|
||||
binary_data = base64.b64decode(rsp.data.audio)
|
||||
await writer.write(binary_data)
|
||||
if rsp.data.status != IFlyTekTTSStatus.STATUS_LAST_FRAME.value:
|
||||
continue
|
||||
break
|
||||
|
|
@ -140,23 +140,13 @@ async def oas3_iflytek_tts(text: str, voice: str = "", app_id: str = "", api_key
|
|||
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()
|
||||
async with aiofiles.open(str(filename), mode="rb") as reader:
|
||||
data = await reader.read()
|
||||
base64_string = base64.b64encode(data).decode("utf-8")
|
||||
except Exception as e:
|
||||
logger.error(f"text:{text}, error:{e}")
|
||||
base64_string = ""
|
||||
finally:
|
||||
filename.unlink()
|
||||
filename.unlink(missing_ok=True)
|
||||
|
||||
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",
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,39 +6,21 @@
|
|||
@File : metagpt_oas3_api_svc.py
|
||||
@Desc : MetaGPT OpenAPI Specification 3.0 REST API service
|
||||
"""
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import connexion
|
||||
|
||||
sys.path.append(str(Path(__file__).resolve().parent.parent.parent)) # fix-bug: No module named 'metagpt'
|
||||
|
||||
|
||||
def oas_http_svc():
|
||||
"""Start the OAS 3.0 OpenAPI HTTP service"""
|
||||
app = connexion.AioHttpApp(__name__, specification_dir="../../.well-known/")
|
||||
print("http://localhost:8080/oas3/ui/")
|
||||
specification_dir = Path(__file__).parent.parent.parent / ".well-known"
|
||||
app = connexion.AsyncApp(__name__, specification_dir=str(specification_dir))
|
||||
app.add_api("metagpt_oas3_api.yaml")
|
||||
app.add_api("openapi.yaml")
|
||||
app.run(port=8080)
|
||||
|
||||
|
||||
async def async_main():
|
||||
"""Start the OAS 3.0 OpenAPI HTTP service in the background."""
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_in_executor(None, oas_http_svc)
|
||||
|
||||
# TODO: replace following codes:
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
print("sleep")
|
||||
|
||||
|
||||
def main():
|
||||
print("http://localhost:8080/oas3/ui/")
|
||||
oas_http_svc()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# asyncio.run(async_main())
|
||||
main()
|
||||
oas_http_svc()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
@File : metagpt_text_to_image.py
|
||||
@Desc : MetaGPT Text-to-Image OAS3 api, which provides text-to-image functionality.
|
||||
"""
|
||||
import asyncio
|
||||
import base64
|
||||
from typing import Dict, List
|
||||
|
||||
|
|
@ -14,7 +13,7 @@ import aiohttp
|
|||
import requests
|
||||
from pydantic import BaseModel
|
||||
|
||||
from metagpt.config import CONFIG, Config
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
|
|
@ -75,11 +74,12 @@ class MetaGPTText2Image:
|
|||
async with session.post(self.model_url, headers=headers, json=data) as response:
|
||||
result = ImageResult(**await response.json())
|
||||
if len(result.images) == 0:
|
||||
return ""
|
||||
return result.images[0]
|
||||
return 0
|
||||
data = base64.b64decode(result.images[0])
|
||||
return data
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"An error occurred:{e}")
|
||||
return ""
|
||||
return 0
|
||||
|
||||
|
||||
# Export
|
||||
|
|
@ -96,15 +96,3 @@ async def oas3_metagpt_text_to_image(text, size_type: str = "512x512", model_url
|
|||
if not model_url:
|
||||
model_url = CONFIG.METAGPT_TEXT_TO_IMAGE_MODEL_URL
|
||||
return await MetaGPTText2Image(model_url).text_2_image(text, size_type=size_type)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
Config()
|
||||
loop = asyncio.new_event_loop()
|
||||
task = loop.create_task(oas3_metagpt_text_to_image("Panda emoji"))
|
||||
v = loop.run_until_complete(task)
|
||||
print(v)
|
||||
data = base64.b64decode(v)
|
||||
with open("tmp.png", mode="wb") as writer:
|
||||
writer.write(data)
|
||||
print(v)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
@Author : zhanglei
|
||||
@File : moderation.py
|
||||
"""
|
||||
import asyncio
|
||||
from typing import Union
|
||||
|
||||
from metagpt.llm import LLM
|
||||
|
|
@ -15,6 +14,38 @@ class Moderation:
|
|||
def __init__(self):
|
||||
self.llm = LLM()
|
||||
|
||||
def handle_moderation_results(self, results):
|
||||
resp = []
|
||||
for item in results:
|
||||
categories = item.categories.dict()
|
||||
true_categories = [category for category, item_flagged in categories.items() if item_flagged]
|
||||
resp.append({"flagged": item.flagged, "true_categories": true_categories})
|
||||
return resp
|
||||
|
||||
def moderation_with_categories(self, content: Union[str, list[str]]):
|
||||
resp = []
|
||||
if content:
|
||||
moderation_results = self.llm.moderation(content=content)
|
||||
resp = self.handle_moderation_results(moderation_results.results)
|
||||
return resp
|
||||
|
||||
async def amoderation_with_categories(self, content: Union[str, list[str]]):
|
||||
resp = []
|
||||
if content:
|
||||
moderation_results = await self.llm.amoderation(content=content)
|
||||
resp = self.handle_moderation_results(moderation_results.results)
|
||||
return resp
|
||||
|
||||
def moderation(self, content: Union[str, list[str]]):
|
||||
resp = []
|
||||
if content:
|
||||
moderation_results = self.llm.moderation(content=content)
|
||||
results = moderation_results.results
|
||||
for item in results:
|
||||
resp.append(item.flagged)
|
||||
|
||||
return resp
|
||||
|
||||
async def amoderation(self, content: Union[str, list[str]]):
|
||||
resp = []
|
||||
if content:
|
||||
|
|
@ -24,15 +55,3 @@ class Moderation:
|
|||
resp.append(item.flagged)
|
||||
|
||||
return resp
|
||||
|
||||
|
||||
async def main():
|
||||
moderation = Moderation()
|
||||
rsp = await moderation.amoderation(
|
||||
content=["I will kill you", "The weather is really nice today", "I want to hit you"]
|
||||
)
|
||||
print(rsp)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
|
|
|
|||
|
|
@ -7,14 +7,13 @@
|
|||
@Desc : OpenAI Text-to-Embedding OAS3 api, which provides text-to-embedding functionality.
|
||||
For more details, checkout: `https://platform.openai.com/docs/api-reference/embeddings/object`
|
||||
"""
|
||||
import asyncio
|
||||
from typing import List
|
||||
|
||||
import aiohttp
|
||||
import requests
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from metagpt.config import CONFIG, Config
|
||||
from metagpt.config import CONFIG
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
|
|
@ -29,15 +28,18 @@ class Embedding(BaseModel):
|
|||
|
||||
|
||||
class Usage(BaseModel):
|
||||
prompt_tokens: int
|
||||
total_tokens: int
|
||||
prompt_tokens: int = 0
|
||||
total_tokens: int = 0
|
||||
|
||||
|
||||
class ResultEmbedding(BaseModel):
|
||||
object: str
|
||||
data: List[Embedding]
|
||||
model: str
|
||||
usage: Usage
|
||||
class Config:
|
||||
alias = {"object_": "object"}
|
||||
|
||||
object_: str = ""
|
||||
data: List[Embedding] = []
|
||||
model: str = ""
|
||||
usage: Usage = Field(default_factory=Usage)
|
||||
|
||||
|
||||
class OpenAIText2Embedding:
|
||||
|
|
@ -45,7 +47,7 @@ class OpenAIText2Embedding:
|
|||
"""
|
||||
:param openai_api_key: OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`
|
||||
"""
|
||||
self.openai_api_key = openai_api_key if openai_api_key else CONFIG.OPENAI_API_KEY
|
||||
self.openai_api_key = openai_api_key or CONFIG.OPENAI_API_KEY
|
||||
|
||||
async def text_2_embedding(self, text, model="text-embedding-ada-002"):
|
||||
"""Text to embedding
|
||||
|
|
@ -55,15 +57,18 @@ class OpenAIText2Embedding:
|
|||
:return: A json object of :class:`ResultEmbedding` class if successful, otherwise `{}`.
|
||||
"""
|
||||
|
||||
proxies = {"proxy": CONFIG.openai_proxy} if CONFIG.openai_proxy else {}
|
||||
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {self.openai_api_key}"}
|
||||
data = {"input": text, "model": model}
|
||||
url = "https://api.openai.com/v1/embeddings"
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post("https://api.openai.com/v1/embeddings", headers=headers, json=data) as response:
|
||||
return await response.json()
|
||||
async with session.post(url, headers=headers, json=data, **proxies) as response:
|
||||
data = await response.json()
|
||||
return ResultEmbedding(**data)
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"An error occurred:{e}")
|
||||
return {}
|
||||
return ResultEmbedding()
|
||||
|
||||
|
||||
# Export
|
||||
|
|
@ -80,11 +85,3 @@ async def oas3_openai_text_to_embedding(text, model="text-embedding-ada-002", op
|
|||
if not openai_api_key:
|
||||
openai_api_key = CONFIG.OPENAI_API_KEY
|
||||
return await OpenAIText2Embedding(openai_api_key).text_2_embedding(text, model=model)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
Config()
|
||||
loop = asyncio.new_event_loop()
|
||||
task = loop.create_task(oas3_openai_text_to_embedding("Panda emoji"))
|
||||
v = loop.run_until_complete(task)
|
||||
print(v)
|
||||
|
|
|
|||
|
|
@ -6,13 +6,10 @@
|
|||
@File : openai_text_to_image.py
|
||||
@Desc : OpenAI Text-to-Image OAS3 api, which provides text-to-image functionality.
|
||||
"""
|
||||
import asyncio
|
||||
import base64
|
||||
|
||||
import aiohttp
|
||||
import requests
|
||||
|
||||
from metagpt.config import Config
|
||||
from metagpt.llm import LLM
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
|
@ -23,7 +20,6 @@ class OpenAIText2Image:
|
|||
:param openai_api_key: OpenAI API key, For more details, checkout: `https://platform.openai.com/account/api-keys`
|
||||
"""
|
||||
self._llm = LLM()
|
||||
self._client = self._llm.async_client
|
||||
|
||||
def __del__(self):
|
||||
if self._llm:
|
||||
|
|
@ -37,7 +33,7 @@ class OpenAIText2Image:
|
|||
:return: The image data is returned in Base64 encoding.
|
||||
"""
|
||||
try:
|
||||
result = await self._client.images.generate(prompt=text, n=1, size=size_type)
|
||||
result = await self._llm.async_client.images.generate(prompt=text, n=1, size=size_type)
|
||||
except Exception as e:
|
||||
logger.error(f"An error occurred:{e}")
|
||||
return ""
|
||||
|
|
@ -57,12 +53,11 @@ class OpenAIText2Image:
|
|||
async with session.get(url) as response:
|
||||
response.raise_for_status() # 如果是 4xx 或 5xx 响应,会引发异常
|
||||
image_data = await response.read()
|
||||
base64_image = base64.b64encode(image_data).decode("utf-8")
|
||||
return base64_image
|
||||
return image_data
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"An error occurred:{e}")
|
||||
return ""
|
||||
return 0
|
||||
|
||||
|
||||
# Export
|
||||
|
|
@ -76,11 +71,3 @@ async def oas3_openai_text_to_image(text, size_type: str = "1024x1024"):
|
|||
if not text:
|
||||
return ""
|
||||
return await OpenAIText2Image().text_2_image(text, size_type=size_type)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
Config()
|
||||
loop = asyncio.new_event_loop()
|
||||
task = loop.create_task(oas3_openai_text_to_image("Panda emoji"))
|
||||
v = loop.run_until_complete(task)
|
||||
print(v)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import asyncio
|
|||
import importlib
|
||||
from concurrent import futures
|
||||
from copy import deepcopy
|
||||
from typing import Dict, Literal
|
||||
from typing import Literal
|
||||
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
|
@ -33,7 +33,6 @@ class SeleniumWrapper:
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
options: Dict,
|
||||
browser_type: Literal["chrome", "firefox", "edge", "ie"] | None = None,
|
||||
launch_kwargs: dict | None = None,
|
||||
*,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue