diff --git a/config/config.yaml b/config/config.yaml index 444f55efd..a60d2dbdd 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -15,6 +15,19 @@ RPM: 10 #### if Anthropic #Anthropic_API_KEY: "YOUR_API_KEY" +#### if xinghuo +#xinghuo_appid : "APPID" +#xinghuo_api_secret : "APISecret" +#xinghuo_api_key : "APIKey" + +#domain : "generalv2" + +#Spark_url : "ws://spark-api.xf-yun.com/v2.1/chat" + +#### 如果不能使用api + +#no_api_mode :"true" + #### if AZURE, check https://github.com/openai/openai-cookbook/blob/main/examples/azure/chat.ipynb #### You can use ENGINE or DEPLOYMENT mode #OPENAI_API_TYPE: "azure" diff --git a/debating_tournament.py b/debating_tournament.py new file mode 100644 index 000000000..8971a12c1 --- /dev/null +++ b/debating_tournament.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@Time : 2023/9/20 00:30 +@Author : zhouziming +@File : debating_tourmament.py +""" +import asyncio +import platform +import fire +from pydantic import BaseModel, Field + +from metagpt.actions import BossRequirement +from metagpt.config import CONFIG +from metagpt.environment import Environment +from metagpt.logs import logger +from metagpt.roles import Role +from metagpt.schema import Message +from metagpt.utils.common import NoMoneyException +from metagpt.llm import DEFAULT_LLM +正方一辩提示词=''' +##角色 +现在你是一名高水平,有辩论技巧,有强大表达能力的辩手。 +##要求 +您的立论题目是{正方辩题}。您的立论稿应该包括明确自己的论点,解释自己论点的含义,然后使用对论点有利的论据来支撑自己的论点。最后使用生活中的示例来论证自己的论点。 +''' +反方一辩提示词=''' +##角色 +现在你是一名高水平,有辩论技巧,有强大表达能力的辩手。 +##要求 +您的立论题目是{反方辩题}。您的立论稿应该包括明确自己的论点,解释自己论点的含义,然后使用对论点有利的论据来支撑自己的论点。最后使用生活中的示例来论证自己的论点。 +''' +正方一辩评价提示词=''' +##角色 +现在你是一名高水平,有辩论技巧辩论赛裁判,根据辩论赛而不是自身立场来评价。 +##要求 +你的任务是根据一辩辩手的立论稿对辩手的立论进行评价,指出改进空间。评价应当包括:立论稿内容是否符合辩题、逻辑表达是否清晰、论据是否能够支撑论点、能否结合实际方面进行评价。并在进行中立,客观的评价后,给出自己的评分。评分从A+到C-。 +##辩题 +{正方辩题} +##立论稿 +{正方立论稿} +''' +反方一辩评价提示词=''' +##角色 +现在你是一名高水平,有辩论技巧辩论赛裁判,根据辩论赛而不是自身立场来评价。 +##要求 +你的任务是根据一辩辩手的立论稿对辩手的立论进行评价,指出改进空间。评价应当包括:立论稿内容是否符合辩题、逻辑表达是否清晰、论据是否能够支撑论点、能否结合实际方面进行评价。并在进行中立,客观的评价后,给出自己的评分。评分从A+到C-。 +##辩题 +{反方辩题} +##立论稿 +{反方立论稿} +''' +正方质询提示词=''' +##角色 +现在你是一名高水平,有辩论技巧,有强大表达能力的辩手。 +##要求 +你的任务是,根据自己辩题,针对立论稿提出疑问。疑问内容不超过五条,每条只限一句话。 +##辩题 +{正方辩题} +##立论稿 +{反方立论稿} +''' +反方回答提示词=''' +##角色 +现在你是一名高水平,有辩论技巧,有强大表达能力的辩手。 +##要求 +你的任务是,根据立论稿对对手提出的疑问进行回答。对每个问题的回答应限制在三句话以内。回答内容和疑问应当一一对应。 +##辩题 +{反方辩题} +##立论稿 +{反方立论稿} +##疑问 +{正方质询} +''' +反方质询提示词=''' +##角色 +现在你是一名高水平,有辩论技巧,有强大表达能力的辩手。 +##要求 +你的任务是,根据自己辩题,针对立论稿提出疑问。疑问内容不超过五条,每条只限一句话。 +##辩题 +{反方辩题} +##立论稿 +{正方立论稿} +''' +正方回答提示词=''' +##角色 +现在你是一名高水平,有辩论技巧,有强大表达能力的辩手。 +##要求 +你的任务是,根据立论稿对对手提出的疑问进行回答。对每个问题的回答应限制在三句话以内。回答内容和疑问应当一一对应。 +##辩题 +{正方辩题} +##立论稿 +{正方立论稿} +##疑问 +{反方质询} +''' +def main( + zf:str='人性本善', + ff:str='人性本恶' +): + """ + """ + if platform.system() == "Windows": + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + asyncio.run(startup(zf,ff)) + +async def startup(正方辩题:str,反方辩题:str): + llm=DEFAULT_LLM + #一辩环节 + #正方 + + 正方立论稿=await llm.aask(正方一辩提示词.format(正方辩题=正方辩题)) + #反方 + + 反方立论稿=await llm.aask(反方一辩提示词.format(反方辩题=反方辩题)) + #裁判评价环节 + + 正方一辩评价=await llm.aask(正方一辩评价提示词.format(正方辩题=正方辩题,正方立论稿=正方立论稿)) + + 反方一辩评价=await llm.aask(反方一辩评价提示词.format(反方辩题=反方辩题,反方立论稿=反方立论稿)) + #二辩质询环节 + #正方质询 + + 正方质询=await llm.aask(正方质询提示词.format(正方辩题=正方辩题,反方立论稿=反方立论稿)) + #反方回答 + + 反方回答=await llm.aask(反方回答提示词.format(反方辩题=反方辩题,反方立论稿=反方立论稿,正方质询=正方质询)) + #反方质询 + + 反方质询=await llm.aask(反方质询提示词.format(反方辩题=反方辩题,正方立论稿=正方立论稿)) + #正方回答 + + 正方回答=await llm.aask(正方回答提示词.format(正方辩题=正方辩题,正方立论稿=正方立论稿,反方质询=反方质询)) +if __name__ == '__main__': + fire.Fire(main) diff --git a/examples/llm_hello_world.py b/examples/llm_hello_world.py index 3ba03eea0..d6d24b688 100644 --- a/examples/llm_hello_world.py +++ b/examples/llm_hello_world.py @@ -7,12 +7,11 @@ """ import asyncio -from metagpt.llm import LLM, Claude -from metagpt.logs import logger +import metagpt.llm as LLM async def main(): - llm = LLM() + llm=LLM.DEFAULT_LLM claude = Claude() logger.info(await claude.aask('你好,请进行自我介绍')) logger.info(await llm.aask('hello world')) diff --git a/metagpt/actions/action.py b/metagpt/actions/action.py index 790295d55..8e1d5c85d 100644 --- a/metagpt/actions/action.py +++ b/metagpt/actions/action.py @@ -22,7 +22,7 @@ class Action(ABC): def __init__(self, name: str = "", context=None, llm: LLM = None): self.name: str = name if llm is None: - llm = LLM() + llm=LLM.DEFAULT_LLM self.llm = llm self.context = context self.prefix = "" diff --git a/metagpt/config.py b/metagpt/config.py index 53271133b..146fb957b 100644 --- a/metagpt/config.py +++ b/metagpt/config.py @@ -45,8 +45,18 @@ class Config(metaclass=Singleton): self.global_proxy = self._get("GLOBAL_PROXY") self.openai_api_key = self._get("OPENAI_API_KEY") self.anthropic_api_key = self._get("Anthropic_API_KEY") + + #星火大模型相关 + self.xinghuo_appid = self._get("xinghuo_appid") + self.xinghuo_api_secret = self._get("xinghuo_api_secret") + self.xinghuo_api_key = self._get("xinghuo_api_key") + self.domain=self._get("domain") + self.Spark_url=self._get("Spark_url") + self.no_api_mode=self._get("no_api_mode") if (not self.openai_api_key or "YOUR_API_KEY" == self.openai_api_key) and ( not self.anthropic_api_key or "YOUR_API_KEY" == self.anthropic_api_key + )and ( + not self.xinghuo_api_key or "APIKey" == self.xinghuo_api_key ): raise NotConfiguredException("Set OPENAI_API_KEY or Anthropic_API_KEY first") self.openai_api_base = self._get("OPENAI_API_BASE") diff --git a/metagpt/llm.py b/metagpt/llm.py index e6f815950..68945e71e 100644 --- a/metagpt/llm.py +++ b/metagpt/llm.py @@ -8,9 +8,9 @@ from metagpt.provider.anthropic_api import Claude2 as Claude from metagpt.provider.openai_api import OpenAIGPTAPI as LLM +from metagpt.provider.spark_api import Spark -DEFAULT_LLM = LLM() -CLAUDE_LLM = Claude() +DEFAULT_LLM = Spark() async def ai_func(prompt): """使用LLM进行QA diff --git a/metagpt/management/skill_manager.py b/metagpt/management/skill_manager.py index f967a0a94..4852e452f 100644 --- a/metagpt/management/skill_manager.py +++ b/metagpt/management/skill_manager.py @@ -8,7 +8,7 @@ from metagpt.actions import Action from metagpt.const import PROMPT_PATH from metagpt.document_store.chromadb_store import ChromaStore -from metagpt.llm import LLM +import metagpt.llm as LLM from metagpt.logs import logger Skill = Action @@ -18,7 +18,7 @@ class SkillManager: """Used to manage all skills""" def __init__(self): - self._llm = LLM() + self._llm=LLM.DEFAULT_LLM self._store = ChromaStore('skill_manager') self._skills: dict[str: Skill] = {} diff --git a/metagpt/manager.py b/metagpt/manager.py index 9d238c621..3f6c115f3 100644 --- a/metagpt/manager.py +++ b/metagpt/manager.py @@ -5,13 +5,13 @@ @Author : alexanderwu @File : manager.py """ -from metagpt.llm import LLM +import metagpt.llm as LLM from metagpt.logs import logger from metagpt.schema import Message class Manager: - def __init__(self, llm: LLM = LLM()): + def __init__(self, llm: llm=LLM.DEFAULT_LLM): self.llm = llm # Large Language Model self.role_directions = { "BOSS": "Product Manager", diff --git a/metagpt/prompts/generate_skill.md b/metagpt/prompts/generate_skill.md index 74948cd15..dd28df079 100644 --- a/metagpt/prompts/generate_skill.md +++ b/metagpt/prompts/generate_skill.md @@ -9,10 +9,10 @@ ```python from typing import Optional from abc import ABC -from metagpt.llm import LLM # Large language model, similar to GPT -n +import metagpt.llm as LLM # 大语言模型,类似GPT + class Action(ABC): - def __init__(self, name='', context=None, llm: LLM = LLM()): + def __init__(self, name='', context=None, llm: llm=LLM.DEFAULT_LLM): self.name = name self.llm = llm self.context = context diff --git a/metagpt/provider/SparkApi.py b/metagpt/provider/SparkApi.py new file mode 100644 index 000000000..7ce57c22a --- /dev/null +++ b/metagpt/provider/SparkApi.py @@ -0,0 +1,138 @@ +import _thread as thread +import base64 +import datetime +import hashlib +import hmac +import json +from urllib.parse import urlparse +import ssl +from datetime import datetime +from time import mktime +from urllib.parse import urlencode +from wsgiref.handlers import format_date_time +from metagpt.logs import logger + +import websocket # 使用websocket_client +answer = "" + +class Ws_Param(object): + # 初始化 + def __init__(self, appid, apikey, apiSecret, spark_url): + self.appid = appid + self.apikey = apikey + self.apiSecret = apiSecret + self.host = urlparse(spark_url).netloc + self.path = urlparse(spark_url).path + self.spark_url = spark_url + + # 生成url + def create_url(self): + # 生成RFC1123格式的时间戳 + now = datetime.now() + date = format_date_time(mktime(now.timetuple())) + + # 拼接字符串 + signature_origin = "host: " + self.host + "\n" + signature_origin += "date: " + date + "\n" + signature_origin += "GET " + self.path + " HTTP/1.1" + + # 进行hmac-sha256进行加密 + signature_sha = hmac.new(self.apiSecret.encode('utf-8'), signature_origin.encode('utf-8'), + digestmod=hashlib.sha256).digest() + + signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8') + + authorization_origin = f'api_key="{self.apikey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"' + + authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8') + + # 将请求的鉴权参数组合为字典 + v = { + "authorization": authorization, + "date": date, + "host": self.host + } + # 拼接鉴权参数,生成url + url = self.spark_url + '?' + urlencode(v) + # 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释,比对相同参数时生成的url与自己代码生成的url是否一致 + return url + + +# 收到websocket错误的处理 +def on_error(ws, error): + logger.error("### error:"+error) + + +# 收到websocket关闭的处理 +def on_close(ws,one,two): + logger.error("websocket关闭") + + +# 收到websocket连接建立的处理 +def on_open(ws): + thread.start_new_thread(run, (ws,)) + + +def run(ws, *args): + data = json.dumps(gen_params(appid=ws.appid, domain= ws.domain,question=ws.question)) + ws.send(data) + + +# 收到websocket消息的处理 +def on_message(ws, message): + # print(message) + data = json.loads(message) + code = data['header']['code'] + if code != 0: + logger.error(f'请求错误: {code}, {data}') + ws.close() + else: + choices = data["payload"]["choices"] + status = choices["status"] + content = choices["text"][0]["content"] + print(content,end ="") + global answer + answer += content + # print(1) + if status == 2: + ws.close() + + +def gen_params(appid, domain,question): + """ + 通过appid和用户的提问来生成请参数 + """ + data = { + "header": { + "app_id": appid, + "uid": "1234" + }, + "parameter": { + "chat": { + "domain": domain, + "random_threshold": 0.5, + "max_tokens": 2048, + "auditing": "default" + } + }, + "payload": { + "message": { + "text": question + } + } + } + return data + + +def main(appid, api_key, api_secret, spark_url,domain, question): + # print("星火:") + wsParam = Ws_Param(appid, api_key, api_secret, spark_url) + websocket.enableTrace(False) + wsUrl = wsParam.create_url() + ws = websocket.WebSocketApp(wsUrl, on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open) + ws.appid = appid + ws.question = question + ws.domain = domain + ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) + + diff --git a/metagpt/provider/spark_api.py b/metagpt/provider/spark_api.py new file mode 100644 index 000000000..e855e019a --- /dev/null +++ b/metagpt/provider/spark_api.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@Time : 2023/7/21 11:15 +@Author : Leo Xiao +@File : anthropic_api.py +""" + +from typing import Optional +from metagpt.provider import SparkApi + +from metagpt.config import CONFIG + +def getlength(text): + length = 0 + for content in text: + temp = content["content"] + leng = len(temp) + length += leng + return length + +def checklen(text): + while (getlength(text) > 8000): + del text[0] + return text + +class Spark: + system_prompt = 'You are a helpful assistant.' + + def _user_msg(self, msg: str) -> dict[str, str]: + return {"role": "user", "content": msg} + + def _assistant_msg(self, msg: str) -> dict[str, str]: + return {"role": "assistant", "content": msg} + + def _system_msg(self, msg: str) -> dict[str, str]: + return {"role": "system", "content": msg} + + def _system_msgs(self, msgs: list[str]) -> list[dict[str, str]]: + return [self._system_msg(msg) for msg in msgs] + + def _default_system_msg(self): + return self._system_msg(self.system_prompt) + + def ask(self, msg: str): + message = [self._user_msg(msg)] + SparkApi.main(CONFIG.xinghuo_appid,CONFIG.xinghuo_api_key,CONFIG.xinghuo_api_secret,"ws://spark-api.xf-yun.com/v2.1/chat","generalv2",message) + rsp = SparkApi.answer + return rsp + + async def aask(self, msg: str, system_msgs: Optional[list[str]] = None) -> str: + if system_msgs: + message = self._system_msgs(system_msgs) + [self._user_msg(msg)] + else: + message = [self._user_msg(msg)] + SparkApi.main(CONFIG.xinghuo_appid,CONFIG.xinghuo_api_key,CONFIG.xinghuo_api_secret,"ws://spark-api.xf-yun.com/v2.1/chat","generalv2",message) + rsp = SparkApi.answer + return rsp diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index b1ae51cf5..52cc693a0 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -14,7 +14,7 @@ from pydantic import BaseModel, Field # from metagpt.environment import Environment from metagpt.config import CONFIG from metagpt.actions import Action, ActionOutput -from metagpt.llm import LLM +from metagpt import llm as LLM from metagpt.logs import logger from metagpt.memory import Memory, LongTermMemory from metagpt.schema import Message @@ -94,7 +94,7 @@ class Role: """Role/Agent""" def __init__(self, name="", profile="", goal="", constraints="", desc=""): - self._llm = LLM() + self._llm=LLM.DEFAULT_LLM self._setting = RoleSetting(name=name, profile=profile, goal=goal, constraints=constraints, desc=desc) self._states = [] self._actions = [] diff --git a/requirements.txt b/requirements.txt index de861ded9..c2616a08a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,7 +34,7 @@ tqdm==4.64.0 # selenium>4 # webdriver_manager<3.9 anthropic==0.3.6 -typing-inspect==0.8.0 +typing-inspect typing_extensions==4.5.0 libcst==1.0.1 qdrant-client==1.4.0 diff --git a/tests/metagpt/actions/test_write_code.py b/tests/metagpt/actions/test_write_code.py index 7bb18ddf2..00d2c504e 100644 --- a/tests/metagpt/actions/test_write_code.py +++ b/tests/metagpt/actions/test_write_code.py @@ -8,7 +8,7 @@ import pytest from metagpt.actions.write_code import WriteCode -from metagpt.llm import LLM +import metagpt.llm as LLM from metagpt.logs import logger from tests.metagpt.actions.mock import TASKS_2, WRITE_CODE_PROMPT_SAMPLE @@ -29,6 +29,6 @@ async def test_write_code(): @pytest.mark.asyncio async def test_write_code_directly(): prompt = WRITE_CODE_PROMPT_SAMPLE + '\n' + TASKS_2[0] - llm = LLM() + llm=LLM.DEFAULT_LLM rsp = await llm.aask(prompt) logger.info(rsp) diff --git a/tests/metagpt/roles/mock.py b/tests/metagpt/roles/mock.py index 52fc4a3c1..9567be603 100644 --- a/tests/metagpt/roles/mock.py +++ b/tests/metagpt/roles/mock.py @@ -16,7 +16,7 @@ DETAIL_REQUIREMENT = """需求:开发一个基于LLM(大语言模型)与 3. 私有知识库支持pdf、word、txt等各种文件格式上传,上传后可以在服务端解析为文本,存储ES 资源: -1. 大语言模型已经有前置的抽象、部署,可以通过 `from metagpt.llm import LLM`,再使用`LLM().ask(prompt)`直接调用 +1. 大语言模型已经有前置的抽象、部署,可以通过 `import metagpt.llm as LLM`,再使用`LLM().ask(prompt)`直接调用 2. Elastic已有[部署](http://192.168.50.82:9200/),代码可以直接使用这个部署""" diff --git a/tests/metagpt/test_llm.py b/tests/metagpt/test_llm.py index 11503af1d..1986f3f22 100644 --- a/tests/metagpt/test_llm.py +++ b/tests/metagpt/test_llm.py @@ -8,7 +8,7 @@ import pytest -from metagpt.llm import LLM +import metagpt.llm as LLM @pytest.fixture() diff --git a/webui.py b/webui.py new file mode 100644 index 000000000..e69de29bb