From 3c9b1a14e9fa5f4bdf5f7f36c737b2670752f00f Mon Sep 17 00:00:00 2001 From: resphinas <2934218525@qq.com> Date: Mon, 28 Aug 2023 16:43:26 +0800 Subject: [PATCH 01/28] claude bot update --- chatgpt-on-wechat | 1 + 1 file changed, 1 insertion(+) create mode 160000 chatgpt-on-wechat diff --git a/chatgpt-on-wechat b/chatgpt-on-wechat new file mode 160000 index 0000000..827e8ed --- /dev/null +++ b/chatgpt-on-wechat @@ -0,0 +1 @@ +Subproject commit 827e8eddf87b73f310464e3d6c0509e5b6e2ba67 From f98b43514e03fa571bd071e4324e0a55815035a7 Mon Sep 17 00:00:00 2001 From: resphinas <2934218525@qq.com> Date: Mon, 28 Aug 2023 17:18:00 +0800 Subject: [PATCH 02/28] claude_bot --- bot/bot_factory.py | 4 + bot/chatgpt/chat_gpt_bot.py | 4 + bot/claude/claude_ai_bot.py | 229 ++++++++++++++++++++++++ bridge/bridge.py | 2 + chatgpt-on-wechat | 1 - chatgpt-on-wechat-master.iml | 12 ++ common/const.py | 5 +- common/log.py | 4 +- config-template.json | 7 +- config.py | 4 +- lib/itchat/async_components/messages.py | 4 + lib/itchat/components/messages.py | 1 + requirements.txt | 4 + 13 files changed, 274 insertions(+), 7 deletions(-) create mode 100644 bot/claude/claude_ai_bot.py delete mode 160000 chatgpt-on-wechat create mode 100644 chatgpt-on-wechat-master.iml diff --git a/bot/bot_factory.py b/bot/bot_factory.py index 513eb78..da12f95 100644 --- a/bot/bot_factory.py +++ b/bot/bot_factory.py @@ -39,4 +39,8 @@ def create_bot(bot_type): elif bot_type == const.LINKAI: from bot.linkai.link_ai_bot import LinkAIBot return LinkAIBot() + + elif bot_type == const.CLAUDEAI: + from bot.claude.claude_ai_bot import ClaudeAIBot + return ClaudeAIBot() raise RuntimeError diff --git a/bot/chatgpt/chat_gpt_bot.py b/bot/chatgpt/chat_gpt_bot.py index 8c9a250..00f83e8 100644 --- a/bot/chatgpt/chat_gpt_bot.py +++ b/bot/chatgpt/chat_gpt_bot.py @@ -106,6 +106,10 @@ class ChatGPTBot(Bot, OpenAIImage): reply = Reply(ReplyType.ERROR, "Bot不支持处理{}类型的消息".format(context.type)) return reply +<<<<<<< 827e8eddf87b73f310464e3d6c0509e5b6e2ba67 +======= + +>>>>>>> claude bot def reply_text(self, session: ChatGPTSession, api_key=None, args=None, retry_count=0) -> dict: """ call openai's ChatCompletion to get the answer diff --git a/bot/claude/claude_ai_bot.py b/bot/claude/claude_ai_bot.py new file mode 100644 index 0000000..bb1cbd8 --- /dev/null +++ b/bot/claude/claude_ai_bot.py @@ -0,0 +1,229 @@ +import re +import time +import json +import uuid + +from curl_cffi import requests +from bot.bot import Bot +from bot.chatgpt.chat_gpt_session import ChatGPTSession +from bot.openai.open_ai_image import OpenAIImage +from bot.session_manager import SessionManager +from bridge.context import Context, ContextType +from bridge.reply import Reply, ReplyType +from common.log import logger +from config import conf + + +class ClaudeAIBot(Bot, OpenAIImage): + # authentication failed + AUTH_FAILED_CODE = 401 + NO_QUOTA_CODE = 406 + + def __init__(self): + super().__init__() + self.sessions = SessionManager(ChatGPTSession, model=conf().get("model") or "gpt-3.5-turbo") + self.claude_api_cookie = conf().get("claude_api_cookie") + self.proxy = conf().get("proxy") + self.proxies = { + "http": self.proxy, + "https": self.proxy + } + self.org_uuid = self.get_organization_id() + self.con_uuid = None + self.get_uuid() + + + + + def generate_uuid(self): + random_uuid = uuid.uuid4() + random_uuid_str = str(random_uuid) + formatted_uuid = f"{random_uuid_str[0:8]}-{random_uuid_str[9:13]}-{random_uuid_str[14:18]}-{random_uuid_str[19:23]}-{random_uuid_str[24:]}" + return formatted_uuid + + def get_uuid(self): + if conf().get("claude_uuid") != None: + self.con_uuid = conf().get("claude_uuid") + else: + self.con_uuid = self.generate_uuid() + self.create_new_chat() + + + + def get_organization_id(self): + url = "https://claude.ai/api/organizations" + + headers = { + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', + 'Accept-Language': 'en-US,en;q=0.5', + 'Referer': 'https://claude.ai/chats', + 'Content-Type': 'application/json', + 'Sec-Fetch-Dest': 'empty', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Site': 'same-origin', + 'Connection': 'keep-alive', + 'Cookie': f'{self.claude_api_cookie}' + } + + response = requests.get(url, headers=headers,impersonate="chrome110",proxies=self.proxies) + res = json.loads(response.text) + uuid = res[0]['uuid'] + + return uuid + def reply(self, query, context: Context = None) -> Reply: + if context.type == ContextType.TEXT: + return self._chat(query, context) + elif context.type == ContextType.IMAGE_CREATE: + ok, res = self.create_img(query, 0) + if ok: + reply = Reply(ReplyType.IMAGE_URL, res) + else: + reply = Reply(ReplyType.ERROR, res) + return reply + else: + reply = Reply(ReplyType.ERROR, "Bot不支持处理{}类型的消息".format(context.type)) + return reply + + def get_organization_id(self): + url = "https://claude.ai/api/organizations" + + headers = { + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', + 'Accept-Language': 'en-US,en;q=0.5', + 'Referer': 'https://claude.ai/chats', + 'Content-Type': 'application/json', + 'Sec-Fetch-Dest': 'empty', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Site': 'same-origin', + 'Connection': 'keep-alive', + 'Cookie': f'{self.claude_api_cookie}' + } + try: + response = requests.get(url, headers=headers,impersonate="chrome110",proxies =self.proxies ) + res = json.loads(response.text) + uuid = res[0]['uuid'] + except: + print(response.text) + + return uuid + def create_new_chat(self): + url = f"https://claude.ai/api/organizations/{self.org_uuid}/chat_conversations" + + payload = json.dumps({"uuid": self.con_uuid, "name": ""}) + headers = { + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', + 'Accept-Language': 'en-US,en;q=0.5', + 'Referer': 'https://claude.ai/chats', + 'Content-Type': 'application/json', + 'Origin': 'https://claude.ai', + 'DNT': '1', + 'Connection': 'keep-alive', + 'Cookie': self.claude_api_cookie, + 'Sec-Fetch-Dest': 'empty', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Site': 'same-origin', + 'TE': 'trailers' + } + + response = requests.post( url, headers=headers, data=payload,impersonate="chrome110", proxies= self.proxies) + + # Returns JSON of the newly created conversation information + return response.json() + def _chat(self, query, context, retry_count=0) -> Reply: + """ + 发起对话请求 + :param query: 请求提示词 + :param context: 对话上下文 + :param retry_count: 当前递归重试次数 + :return: 回复 + """ + if retry_count >= 2: + # exit from retry 2 times + logger.warn("[CLAUDEAI] failed after maximum number of retry times") + return Reply(ReplyType.ERROR, "请再问我一次吧") + + try: + + session_id = context["session_id"] + session = self.sessions.session_query(query, session_id) + model = conf().get("model") or "gpt-3.5-turbo" + # remove system message + if session.messages[0].get("role") == "system": + if model == "wenxin": + session.messages.pop(0) + + + logger.info(f"[CLAUDEAI] query={query}") + + # do http request + base_url = "https://claude.ai" + payload = json.dumps({ + "completion": { + "prompt": f"{query}", + "timezone": "Asia/Kolkata", + "model": "claude-2" + }, + "organization_uuid": f"{self.org_uuid}", + "conversation_uuid": f"{self.con_uuid}", + "text": f"{query}", + "attachments": [] + }) + headers = { + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', + 'Accept': 'text/event-stream, text/event-stream', + 'Accept-Language': 'en-US,en;q=0.5', + 'Referer': 'https://claude.ai/chats', + 'Content-Type': 'application/json', + 'Origin': 'https://claude.ai', + 'DNT': '1', + 'Connection': 'keep-alive', + 'Cookie': f'{self.claude_api_cookie}', + 'Sec-Fetch-Dest': 'empty', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Site': 'same-origin', + 'TE': 'trailers' + } + + res = requests.post(base_url + "/api/append_message", headers=headers, data=payload,impersonate="chrome110",proxies= self.proxies,timeout=400) + + if res.status_code == 200 or "pemission" in res.text: + # execute success + decoded_data = res.content.decode("utf-8") + decoded_data = re.sub('\n+', '\n', decoded_data).strip() + data_strings = decoded_data.split('\n') + completions = [] + for data_string in data_strings: + json_str = data_string[6:].strip() + data = json.loads(json_str) + if 'completion' in data: + completions.append(data['completion']) + + reply_content = ''.join(completions) + logger.info(f"[CLAUDE] reply={reply_content}, total_tokens=100") + self.sessions.session_reply(reply_content, session_id, 100) + return Reply(ReplyType.TEXT, reply_content) + + else: + response = res.json() + error = response.get("error") + logger.error(f"[CLAUDE] chat failed, status_code={res.status_code}, " + f"msg={error.get('message')}, type={error.get('type')}, detail: {res.text}, uuid: {self.con_uuid}") + + if res.status_code >= 500: + # server error, need retry + time.sleep(2) + logger.warn(f"[CLAUDE] do retry, times={retry_count}") + return self._chat(query, context, retry_count + 1) + + return Reply(ReplyType.ERROR, "提问太快啦,请休息一下再问我吧") + + except Exception as e: + logger.exception(e) + # retry + time.sleep(2) + logger.warn(f"[CLAUDE] do retry, times={retry_count}") + return self._chat(query, context, retry_count + 1) diff --git a/bridge/bridge.py b/bridge/bridge.py index 2022438..4a0ef4f 100644 --- a/bridge/bridge.py +++ b/bridge/bridge.py @@ -29,6 +29,8 @@ class Bridge(object): self.btype["chat"] = const.XUNFEI if conf().get("use_linkai") and conf().get("linkai_api_key"): self.btype["chat"] = const.LINKAI + if model_type in ["claude"]: + self.btype["chat"] = const.CLAUDEAI self.bots = {} def get_bot(self, typename): diff --git a/chatgpt-on-wechat b/chatgpt-on-wechat deleted file mode 160000 index 827e8ed..0000000 --- a/chatgpt-on-wechat +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 827e8eddf87b73f310464e3d6c0509e5b6e2ba67 diff --git a/chatgpt-on-wechat-master.iml b/chatgpt-on-wechat-master.iml new file mode 100644 index 0000000..049614a --- /dev/null +++ b/chatgpt-on-wechat-master.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/common/const.py b/common/const.py index 505ab71..ce3eac4 100644 --- a/common/const.py +++ b/common/const.py @@ -5,7 +5,8 @@ BAIDU = "baidu" XUNFEI = "xunfei" CHATGPTONAZURE = "chatGPTOnAzure" LINKAI = "linkai" - VERSION = "1.3.0" - MODEL_LIST = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4", "wenxin", "xunfei"] +CLAUDEAI = "claude" +VERSION = "1.3.0" +MODEL_LIST = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4", "wenxin", "xunfei","claude"] diff --git a/common/log.py b/common/log.py index f02a365..ac64530 100644 --- a/common/log.py +++ b/common/log.py @@ -13,14 +13,14 @@ def _reset_logger(log): console_handle.setFormatter( logging.Formatter( "[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d] - %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", + datefmt="%Y-%m-%claude_ai_bot.py%H:%M:%S", ) ) file_handle = logging.FileHandler("run.log", encoding="utf-8") file_handle.setFormatter( logging.Formatter( "[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d] - %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", + datefmt="%Y-%m-%claude_ai_bot.py%H:%M:%S", ) ) log.addHandler(file_handle) diff --git a/config-template.json b/config-template.json index f01633d..003fbb6 100644 --- a/config-template.json +++ b/config-template.json @@ -2,8 +2,12 @@ "open_ai_api_key": "YOUR API KEY", "model": "gpt-3.5-turbo", "channel_type": "wx", - "proxy": "", + "proxy": "http://127.0.0.1:33210", "hot_reload": false, + "model": "claude", + "channel_type": "wx", + "claude_api_cookie": "intercom-device-id-lupk8zyo=b37192f8-c3a5-408d-8525-60ad8c2cc57c; sessionKey=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; intercom-session-lupk8zyo=dHBseWhqVVIvVW4vZU1NMWM3eUpTQldjQkUwYUMwQVlGQ3g4azR6RlQ3ZDBkTTRqQWd4aGN6ZmY4MSt4aEVERy0tdXY0OGdnUTdYdVhsYWx3c2ErUFFTdz09--58fbe081d071984de6a196e49d513761e8b806e9; cf_clearance=9R_XpUT12.KKIRtXlXUFng05L_sdc0GDwz55ZBGsZ6o-1693003153-0-1-636ec5eb.e36b35e5.346f9a0b-0.2.1693003153; __cf_bm=TLFZA8a7JhAo6NRLVIL0jYsD8nb4cDna6slscBAns3A-1693004564-0-AfWzEcpZbRjF6cLEjxhPUnA84TNQDNQofUkZCuabIKkmQan+BlCvvYIeZod8ISJ/RLq1URvIsp++UwTDJyKfLI8=", + "hot_reload": true, "single_chat_prefix": [ "bot", "@bot" @@ -14,6 +18,7 @@ ], "group_name_white_list": [ "ChatGPT测试群", + "高中数学应用题", "ChatGPT测试群2" ], "group_chat_in_one_session": [ diff --git a/config.py b/config.py index 5853b0d..cb043d1 100644 --- a/config.py +++ b/config.py @@ -120,7 +120,9 @@ available_setting = { "use_linkai": False, "linkai_api_key": "", "linkai_app_code": "", - "linkai_api_base": "https://api.link-ai.chat" # linkAI服务地址,若国内无法访问或延迟较高可改为 https://api.link-ai.tech + "linkai_api_base": "https://api.link-ai.chat", # linkAI服务地址,若国内无法访问或延迟较高可改为 https://api.link-ai.tech + "claude_api_cookie":"", + "claude_uuid":"" } diff --git a/lib/itchat/async_components/messages.py b/lib/itchat/async_components/messages.py index f842f1f..20726dd 100644 --- a/lib/itchat/async_components/messages.py +++ b/lib/itchat/async_components/messages.py @@ -349,7 +349,11 @@ def upload_chunk_file(core, fileDir, fileSymbol, fileSize, ('id', (None, 'WU_FILE_0')), ('name', (None, fileName)), ('type', (None, fileType)), +<<<<<<< 827e8eddf87b73f310464e3d6c0509e5b6e2ba67 ('lastModifiedDate', (None, time.strftime('%a %b %d %Y %H:%M:%S GMT+0800 (CST)'))), +======= + ('lastModifiedDate', (None, time.strftime('%a %b %claude_ai_bot.py%Y %H:%M:%S GMT+0800 (CST)'))), +>>>>>>> claude bot ('size', (None, str(fileSize))), ('chunks', (None, None)), ('chunk', (None, None)), diff --git a/lib/itchat/components/messages.py b/lib/itchat/components/messages.py index 85c0ca2..cdeb6fb 100644 --- a/lib/itchat/components/messages.py +++ b/lib/itchat/components/messages.py @@ -351,6 +351,7 @@ def upload_chunk_file(core, fileDir, fileSymbol, fileSize, ('name', (None, fileName)), ('type', (None, fileType)), ('lastModifiedDate', (None, time.strftime('%a %b %d %Y %H:%M:%S GMT+0800 (CST)'))), + ('lastModifiedDate', (None, time.strftime('%a %b %claude_ai_bot.py%Y %H:%M:%S GMT+0800 (CST)'))), ('size', (None, str(fileSize))), ('chunks', (None, None)), ('chunk', (None, None)), diff --git a/requirements.txt b/requirements.txt index 0863125..4d5bfe4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,7 @@ chardet>=5.1.0 Pillow pre-commit web.py +<<<<<<< 827e8eddf87b73f310464e3d6c0509e5b6e2ba67 +======= +curl_cffi +>>>>>>> claude bot From 44cc4165d17e490cdc73440cf0013054b880b03c Mon Sep 17 00:00:00 2001 From: resphinas <2934218525@qq.com> Date: Mon, 28 Aug 2023 17:22:20 +0800 Subject: [PATCH 03/28] claude_bot --- bot/chatgpt/chat_gpt_bot.py | 3 --- common/const.py | 2 ++ lib/itchat/async_components/messages.py | 3 --- requirements.txt | 3 --- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/bot/chatgpt/chat_gpt_bot.py b/bot/chatgpt/chat_gpt_bot.py index 00f83e8..88a52f1 100644 --- a/bot/chatgpt/chat_gpt_bot.py +++ b/bot/chatgpt/chat_gpt_bot.py @@ -106,10 +106,7 @@ class ChatGPTBot(Bot, OpenAIImage): reply = Reply(ReplyType.ERROR, "Bot不支持处理{}类型的消息".format(context.type)) return reply -<<<<<<< 827e8eddf87b73f310464e3d6c0509e5b6e2ba67 -======= ->>>>>>> claude bot def reply_text(self, session: ChatGPTSession, api_key=None, args=None, retry_count=0) -> dict: """ call openai's ChatCompletion to get the answer diff --git a/common/const.py b/common/const.py index ce3eac4..a85fec7 100644 --- a/common/const.py +++ b/common/const.py @@ -5,7 +5,9 @@ BAIDU = "baidu" XUNFEI = "xunfei" CHATGPTONAZURE = "chatGPTOnAzure" LINKAI = "linkai" + VERSION = "1.3.0" + MODEL_LIST = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4", "wenxin", "xunfei"] CLAUDEAI = "claude" VERSION = "1.3.0" diff --git a/lib/itchat/async_components/messages.py b/lib/itchat/async_components/messages.py index 20726dd..558889b 100644 --- a/lib/itchat/async_components/messages.py +++ b/lib/itchat/async_components/messages.py @@ -349,11 +349,8 @@ def upload_chunk_file(core, fileDir, fileSymbol, fileSize, ('id', (None, 'WU_FILE_0')), ('name', (None, fileName)), ('type', (None, fileType)), -<<<<<<< 827e8eddf87b73f310464e3d6c0509e5b6e2ba67 ('lastModifiedDate', (None, time.strftime('%a %b %d %Y %H:%M:%S GMT+0800 (CST)'))), -======= ('lastModifiedDate', (None, time.strftime('%a %b %claude_ai_bot.py%Y %H:%M:%S GMT+0800 (CST)'))), ->>>>>>> claude bot ('size', (None, str(fileSize))), ('chunks', (None, None)), ('chunk', (None, None)), diff --git a/requirements.txt b/requirements.txt index 4d5bfe4..74bc96e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,4 @@ chardet>=5.1.0 Pillow pre-commit web.py -<<<<<<< 827e8eddf87b73f310464e3d6c0509e5b6e2ba67 -======= curl_cffi ->>>>>>> claude bot From cc3a0fc367d7217d520cb2550b8f9cc2acc08d12 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Mon, 28 Aug 2023 17:28:13 +0800 Subject: [PATCH 04/28] Update config-template.json --- config-template.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config-template.json b/config-template.json index 003fbb6..6956a24 100644 --- a/config-template.json +++ b/config-template.json @@ -2,11 +2,11 @@ "open_ai_api_key": "YOUR API KEY", "model": "gpt-3.5-turbo", "channel_type": "wx", - "proxy": "http://127.0.0.1:33210", + "proxy": ", "hot_reload": false, "model": "claude", "channel_type": "wx", - "claude_api_cookie": "intercom-device-id-lupk8zyo=b37192f8-c3a5-408d-8525-60ad8c2cc57c; sessionKey=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; intercom-session-lupk8zyo=dHBseWhqVVIvVW4vZU1NMWM3eUpTQldjQkUwYUMwQVlGQ3g4azR6RlQ3ZDBkTTRqQWd4aGN6ZmY4MSt4aEVERy0tdXY0OGdnUTdYdVhsYWx3c2ErUFFTdz09--58fbe081d071984de6a196e49d513761e8b806e9; cf_clearance=9R_XpUT12.KKIRtXlXUFng05L_sdc0GDwz55ZBGsZ6o-1693003153-0-1-636ec5eb.e36b35e5.346f9a0b-0.2.1693003153; __cf_bm=TLFZA8a7JhAo6NRLVIL0jYsD8nb4cDna6slscBAns3A-1693004564-0-AfWzEcpZbRjF6cLEjxhPUnA84TNQDNQofUkZCuabIKkmQan+BlCvvYIeZod8ISJ/RLq1URvIsp++UwTDJyKfLI8=", + "claude_api_cookie": "", "hot_reload": true, "single_chat_prefix": [ "bot", @@ -18,7 +18,6 @@ ], "group_name_white_list": [ "ChatGPT测试群", - "高中数学应用题", "ChatGPT测试群2" ], "group_chat_in_one_session": [ From 187601da1e2e0969dd20c5b35fbc13e9688f192e Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Mon, 28 Aug 2023 17:30:03 +0800 Subject: [PATCH 05/28] Update config-template.json --- config-template.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config-template.json b/config-template.json index 6956a24..3af9fbc 100644 --- a/config-template.json +++ b/config-template.json @@ -2,7 +2,7 @@ "open_ai_api_key": "YOUR API KEY", "model": "gpt-3.5-turbo", "channel_type": "wx", - "proxy": ", + "proxy": "", "hot_reload": false, "model": "claude", "channel_type": "wx", From 8d9d5b7b6ff76de657ead33de5681a912ae09950 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Mon, 28 Aug 2023 17:40:27 +0800 Subject: [PATCH 06/28] Update claude_ai_bot.py --- bot/claude/claude_ai_bot.py | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/bot/claude/claude_ai_bot.py b/bot/claude/claude_ai_bot.py index bb1cbd8..71cc970 100644 --- a/bot/claude/claude_ai_bot.py +++ b/bot/claude/claude_ai_bot.py @@ -2,7 +2,6 @@ import re import time import json import uuid - from curl_cffi import requests from bot.bot import Bot from bot.chatgpt.chat_gpt_session import ChatGPTSession @@ -15,10 +14,6 @@ from config import conf class ClaudeAIBot(Bot, OpenAIImage): - # authentication failed - AUTH_FAILED_CODE = 401 - NO_QUOTA_CODE = 406 - def __init__(self): super().__init__() self.sessions = SessionManager(ChatGPTSession, model=conf().get("model") or "gpt-3.5-turbo") @@ -32,9 +27,6 @@ class ClaudeAIBot(Bot, OpenAIImage): self.con_uuid = None self.get_uuid() - - - def generate_uuid(self): random_uuid = uuid.uuid4() random_uuid_str = str(random_uuid) @@ -48,11 +40,8 @@ class ClaudeAIBot(Bot, OpenAIImage): self.con_uuid = self.generate_uuid() self.create_new_chat() - - def get_organization_id(self): url = "https://claude.ai/api/organizations" - headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', @@ -65,12 +54,11 @@ class ClaudeAIBot(Bot, OpenAIImage): 'Connection': 'keep-alive', 'Cookie': f'{self.claude_api_cookie}' } - response = requests.get(url, headers=headers,impersonate="chrome110",proxies=self.proxies) res = json.loads(response.text) uuid = res[0]['uuid'] - return uuid + def reply(self, query, context: Context = None) -> Reply: if context.type == ContextType.TEXT: return self._chat(query, context) @@ -108,9 +96,9 @@ class ClaudeAIBot(Bot, OpenAIImage): print(response.text) return uuid + def create_new_chat(self): url = f"https://claude.ai/api/organizations/{self.org_uuid}/chat_conversations" - payload = json.dumps({"uuid": self.con_uuid, "name": ""}) headers = { 'User-Agent': @@ -127,11 +115,10 @@ class ClaudeAIBot(Bot, OpenAIImage): 'Sec-Fetch-Site': 'same-origin', 'TE': 'trailers' } - response = requests.post( url, headers=headers, data=payload,impersonate="chrome110", proxies= self.proxies) - # Returns JSON of the newly created conversation information return response.json() + def _chat(self, query, context, retry_count=0) -> Reply: """ 发起对话请求 @@ -146,7 +133,6 @@ class ClaudeAIBot(Bot, OpenAIImage): return Reply(ReplyType.ERROR, "请再问我一次吧") try: - session_id = context["session_id"] session = self.sessions.session_query(query, session_id) model = conf().get("model") or "gpt-3.5-turbo" @@ -154,8 +140,6 @@ class ClaudeAIBot(Bot, OpenAIImage): if session.messages[0].get("role") == "system": if model == "wenxin": session.messages.pop(0) - - logger.info(f"[CLAUDEAI] query={query}") # do http request @@ -189,7 +173,6 @@ class ClaudeAIBot(Bot, OpenAIImage): } res = requests.post(base_url + "/api/append_message", headers=headers, data=payload,impersonate="chrome110",proxies= self.proxies,timeout=400) - if res.status_code == 200 or "pemission" in res.text: # execute success decoded_data = res.content.decode("utf-8") @@ -206,7 +189,6 @@ class ClaudeAIBot(Bot, OpenAIImage): logger.info(f"[CLAUDE] reply={reply_content}, total_tokens=100") self.sessions.session_reply(reply_content, session_id, 100) return Reply(ReplyType.TEXT, reply_content) - else: response = res.json() error = response.get("error") @@ -218,7 +200,6 @@ class ClaudeAIBot(Bot, OpenAIImage): time.sleep(2) logger.warn(f"[CLAUDE] do retry, times={retry_count}") return self._chat(query, context, retry_count + 1) - return Reply(ReplyType.ERROR, "提问太快啦,请休息一下再问我吧") except Exception as e: From b9e31256105ff5bfa8b2c3ccd6c46e8885b389cf Mon Sep 17 00:00:00 2001 From: resphinas <2934218525@qq.com> Date: Mon, 28 Aug 2023 18:04:28 +0800 Subject: [PATCH 07/28] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E7=BA=A0=E6=AD=A32?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot/claude/claude_ai_bot.py | 29 +++++-------------------- common/const.py | 4 ---- common/log.py | 4 ++-- config-template.json | 4 ++-- lib/itchat/async_components/messages.py | 1 - lib/itchat/components/messages.py | 1 - 6 files changed, 9 insertions(+), 34 deletions(-) diff --git a/bot/claude/claude_ai_bot.py b/bot/claude/claude_ai_bot.py index bb1cbd8..21ec5a9 100644 --- a/bot/claude/claude_ai_bot.py +++ b/bot/claude/claude_ai_bot.py @@ -2,7 +2,6 @@ import re import time import json import uuid - from curl_cffi import requests from bot.bot import Bot from bot.chatgpt.chat_gpt_session import ChatGPTSession @@ -15,10 +14,6 @@ from config import conf class ClaudeAIBot(Bot, OpenAIImage): - # authentication failed - AUTH_FAILED_CODE = 401 - NO_QUOTA_CODE = 406 - def __init__(self): super().__init__() self.sessions = SessionManager(ChatGPTSession, model=conf().get("model") or "gpt-3.5-turbo") @@ -32,9 +27,6 @@ class ClaudeAIBot(Bot, OpenAIImage): self.con_uuid = None self.get_uuid() - - - def generate_uuid(self): random_uuid = uuid.uuid4() random_uuid_str = str(random_uuid) @@ -48,11 +40,8 @@ class ClaudeAIBot(Bot, OpenAIImage): self.con_uuid = self.generate_uuid() self.create_new_chat() - - def get_organization_id(self): url = "https://claude.ai/api/organizations" - headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', @@ -65,12 +54,11 @@ class ClaudeAIBot(Bot, OpenAIImage): 'Connection': 'keep-alive', 'Cookie': f'{self.claude_api_cookie}' } - response = requests.get(url, headers=headers,impersonate="chrome110",proxies=self.proxies) res = json.loads(response.text) uuid = res[0]['uuid'] - return uuid + def reply(self, query, context: Context = None) -> Reply: if context.type == ContextType.TEXT: return self._chat(query, context) @@ -108,9 +96,9 @@ class ClaudeAIBot(Bot, OpenAIImage): print(response.text) return uuid + def create_new_chat(self): url = f"https://claude.ai/api/organizations/{self.org_uuid}/chat_conversations" - payload = json.dumps({"uuid": self.con_uuid, "name": ""}) headers = { 'User-Agent': @@ -127,11 +115,10 @@ class ClaudeAIBot(Bot, OpenAIImage): 'Sec-Fetch-Site': 'same-origin', 'TE': 'trailers' } - response = requests.post( url, headers=headers, data=payload,impersonate="chrome110", proxies= self.proxies) - # Returns JSON of the newly created conversation information return response.json() + def _chat(self, query, context, retry_count=0) -> Reply: """ 发起对话请求 @@ -146,7 +133,6 @@ class ClaudeAIBot(Bot, OpenAIImage): return Reply(ReplyType.ERROR, "请再问我一次吧") try: - session_id = context["session_id"] session = self.sessions.session_query(query, session_id) model = conf().get("model") or "gpt-3.5-turbo" @@ -154,8 +140,6 @@ class ClaudeAIBot(Bot, OpenAIImage): if session.messages[0].get("role") == "system": if model == "wenxin": session.messages.pop(0) - - logger.info(f"[CLAUDEAI] query={query}") # do http request @@ -189,7 +173,6 @@ class ClaudeAIBot(Bot, OpenAIImage): } res = requests.post(base_url + "/api/append_message", headers=headers, data=payload,impersonate="chrome110",proxies= self.proxies,timeout=400) - if res.status_code == 200 or "pemission" in res.text: # execute success decoded_data = res.content.decode("utf-8") @@ -203,10 +186,9 @@ class ClaudeAIBot(Bot, OpenAIImage): completions.append(data['completion']) reply_content = ''.join(completions) - logger.info(f"[CLAUDE] reply={reply_content}, total_tokens=100") + logger.info(f"[CLAUDE] reply={reply_content}, total_tokens=invisible") self.sessions.session_reply(reply_content, session_id, 100) return Reply(ReplyType.TEXT, reply_content) - else: response = res.json() error = response.get("error") @@ -218,7 +200,6 @@ class ClaudeAIBot(Bot, OpenAIImage): time.sleep(2) logger.warn(f"[CLAUDE] do retry, times={retry_count}") return self._chat(query, context, retry_count + 1) - return Reply(ReplyType.ERROR, "提问太快啦,请休息一下再问我吧") except Exception as e: @@ -226,4 +207,4 @@ class ClaudeAIBot(Bot, OpenAIImage): # retry time.sleep(2) logger.warn(f"[CLAUDE] do retry, times={retry_count}") - return self._chat(query, context, retry_count + 1) + return self._chat(query, context, retry_count + 1) \ No newline at end of file diff --git a/common/const.py b/common/const.py index a85fec7..20e9f89 100644 --- a/common/const.py +++ b/common/const.py @@ -5,10 +5,6 @@ BAIDU = "baidu" XUNFEI = "xunfei" CHATGPTONAZURE = "chatGPTOnAzure" LINKAI = "linkai" - VERSION = "1.3.0" - -MODEL_LIST = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4", "wenxin", "xunfei"] CLAUDEAI = "claude" -VERSION = "1.3.0" MODEL_LIST = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4", "wenxin", "xunfei","claude"] diff --git a/common/log.py b/common/log.py index ac64530..3f28294 100644 --- a/common/log.py +++ b/common/log.py @@ -13,14 +13,14 @@ def _reset_logger(log): console_handle.setFormatter( logging.Formatter( "[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d] - %(message)s", - datefmt="%Y-%m-%claude_ai_bot.py%H:%M:%S", + datefmt="%Y-%m-%d %H:%M:%S", ) ) file_handle = logging.FileHandler("run.log", encoding="utf-8") file_handle.setFormatter( logging.Formatter( "[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d] - %(message)s", - datefmt="%Y-%m-%claude_ai_bot.py%H:%M:%S", + datefmt="%Y-%m-%d %H:%M:%S", ) ) log.addHandler(file_handle) diff --git a/config-template.json b/config-template.json index 003fbb6..38d3ef6 100644 --- a/config-template.json +++ b/config-template.json @@ -2,11 +2,11 @@ "open_ai_api_key": "YOUR API KEY", "model": "gpt-3.5-turbo", "channel_type": "wx", - "proxy": "http://127.0.0.1:33210", + "proxy": "", "hot_reload": false, "model": "claude", "channel_type": "wx", - "claude_api_cookie": "intercom-device-id-lupk8zyo=b37192f8-c3a5-408d-8525-60ad8c2cc57c; sessionKey=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; intercom-session-lupk8zyo=dHBseWhqVVIvVW4vZU1NMWM3eUpTQldjQkUwYUMwQVlGQ3g4azR6RlQ3ZDBkTTRqQWd4aGN6ZmY4MSt4aEVERy0tdXY0OGdnUTdYdVhsYWx3c2ErUFFTdz09--58fbe081d071984de6a196e49d513761e8b806e9; cf_clearance=9R_XpUT12.KKIRtXlXUFng05L_sdc0GDwz55ZBGsZ6o-1693003153-0-1-636ec5eb.e36b35e5.346f9a0b-0.2.1693003153; __cf_bm=TLFZA8a7JhAo6NRLVIL0jYsD8nb4cDna6slscBAns3A-1693004564-0-AfWzEcpZbRjF6cLEjxhPUnA84TNQDNQofUkZCuabIKkmQan+BlCvvYIeZod8ISJ/RLq1URvIsp++UwTDJyKfLI8=", + "claude_api_cookie": "", "hot_reload": true, "single_chat_prefix": [ "bot", diff --git a/lib/itchat/async_components/messages.py b/lib/itchat/async_components/messages.py index 558889b..f842f1f 100644 --- a/lib/itchat/async_components/messages.py +++ b/lib/itchat/async_components/messages.py @@ -350,7 +350,6 @@ def upload_chunk_file(core, fileDir, fileSymbol, fileSize, ('name', (None, fileName)), ('type', (None, fileType)), ('lastModifiedDate', (None, time.strftime('%a %b %d %Y %H:%M:%S GMT+0800 (CST)'))), - ('lastModifiedDate', (None, time.strftime('%a %b %claude_ai_bot.py%Y %H:%M:%S GMT+0800 (CST)'))), ('size', (None, str(fileSize))), ('chunks', (None, None)), ('chunk', (None, None)), diff --git a/lib/itchat/components/messages.py b/lib/itchat/components/messages.py index cdeb6fb..85c0ca2 100644 --- a/lib/itchat/components/messages.py +++ b/lib/itchat/components/messages.py @@ -351,7 +351,6 @@ def upload_chunk_file(core, fileDir, fileSymbol, fileSize, ('name', (None, fileName)), ('type', (None, fileType)), ('lastModifiedDate', (None, time.strftime('%a %b %d %Y %H:%M:%S GMT+0800 (CST)'))), - ('lastModifiedDate', (None, time.strftime('%a %b %claude_ai_bot.py%Y %H:%M:%S GMT+0800 (CST)'))), ('size', (None, str(fileSize))), ('chunks', (None, None)), ('chunk', (None, None)), From a4ab547f779d0e3ff635d92ce6516422a7a24a89 Mon Sep 17 00:00:00 2001 From: resphinas <2934218525@qq.com> Date: Tue, 29 Aug 2023 05:59:59 +0800 Subject: [PATCH 08/28] proxy update --- bot/claude/claude_ai_bot.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bot/claude/claude_ai_bot.py b/bot/claude/claude_ai_bot.py index 21ec5a9..6115614 100644 --- a/bot/claude/claude_ai_bot.py +++ b/bot/claude/claude_ai_bot.py @@ -19,10 +19,13 @@ class ClaudeAIBot(Bot, OpenAIImage): self.sessions = SessionManager(ChatGPTSession, model=conf().get("model") or "gpt-3.5-turbo") self.claude_api_cookie = conf().get("claude_api_cookie") self.proxy = conf().get("proxy") - self.proxies = { + if self.proxy: + self.proxies = { "http": self.proxy, "https": self.proxy } + else: + self.proxies = None self.org_uuid = self.get_organization_id() self.con_uuid = None self.get_uuid() From a5a825e4390c5df943e537d9797883747d56e827 Mon Sep 17 00:00:00 2001 From: resphinas <2934218525@qq.com> Date: Tue, 29 Aug 2023 06:45:21 +0800 Subject: [PATCH 09/28] system role remove --- bot/claude/claude_ai_bot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/claude/claude_ai_bot.py b/bot/claude/claude_ai_bot.py index 6115614..24ff11f 100644 --- a/bot/claude/claude_ai_bot.py +++ b/bot/claude/claude_ai_bot.py @@ -141,7 +141,7 @@ class ClaudeAIBot(Bot, OpenAIImage): model = conf().get("model") or "gpt-3.5-turbo" # remove system message if session.messages[0].get("role") == "system": - if model == "wenxin": + if model == "wenxin" or model == "claude": session.messages.pop(0) logger.info(f"[CLAUDEAI] query={query}") From 91dc44df530209cbe246ecc3ad7b180f1b1aaed2 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 09:38:47 +0800 Subject: [PATCH 10/28] Update const.py --- common/const.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/const.py b/common/const.py index 20e9f89..959b4c1 100644 --- a/common/const.py +++ b/common/const.py @@ -5,6 +5,8 @@ BAIDU = "baidu" XUNFEI = "xunfei" CHATGPTONAZURE = "chatGPTOnAzure" LINKAI = "linkai" + VERSION = "1.3.0" + CLAUDEAI = "claude" MODEL_LIST = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4", "wenxin", "xunfei","claude"] From c6e31b2fdc3be3f4ea8506459254ced818e5dc0f Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 09:39:08 +0800 Subject: [PATCH 11/28] Update chat_gpt_bot.py --- bot/chatgpt/chat_gpt_bot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bot/chatgpt/chat_gpt_bot.py b/bot/chatgpt/chat_gpt_bot.py index 88a52f1..8c9a250 100644 --- a/bot/chatgpt/chat_gpt_bot.py +++ b/bot/chatgpt/chat_gpt_bot.py @@ -106,7 +106,6 @@ class ChatGPTBot(Bot, OpenAIImage): reply = Reply(ReplyType.ERROR, "Bot不支持处理{}类型的消息".format(context.type)) return reply - def reply_text(self, session: ChatGPTSession, api_key=None, args=None, retry_count=0) -> dict: """ call openai's ChatCompletion to get the answer From 79e4af315e2486d20cb3e537ed5d149fa002bbed Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 09:39:45 +0800 Subject: [PATCH 12/28] Update log.py --- common/log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/log.py b/common/log.py index 3f28294..f02a365 100644 --- a/common/log.py +++ b/common/log.py @@ -20,7 +20,7 @@ def _reset_logger(log): file_handle.setFormatter( logging.Formatter( "[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d] - %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", + datefmt="%Y-%m-%d %H:%M:%S", ) ) log.addHandler(file_handle) From 4a670b7df7f99ce6b8c76891e56c728435f8a0f0 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 09:40:26 +0800 Subject: [PATCH 13/28] Update config-template.json --- config-template.json | 1 - 1 file changed, 1 deletion(-) diff --git a/config-template.json b/config-template.json index 3af9fbc..779b44d 100644 --- a/config-template.json +++ b/config-template.json @@ -7,7 +7,6 @@ "model": "claude", "channel_type": "wx", "claude_api_cookie": "", - "hot_reload": true, "single_chat_prefix": [ "bot", "@bot" From 33a7f8b558e487b77880a8b58ecb4596dd0f75ea Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 10:08:34 +0800 Subject: [PATCH 14/28] Delete chatgpt-on-wechat-master.iml --- chatgpt-on-wechat-master.iml | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 chatgpt-on-wechat-master.iml diff --git a/chatgpt-on-wechat-master.iml b/chatgpt-on-wechat-master.iml deleted file mode 100644 index 049614a..0000000 --- a/chatgpt-on-wechat-master.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file From 297404b21e6f86ff26e0cecc7fb4a26b775c2819 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 10:31:45 +0800 Subject: [PATCH 15/28] Update config-template.json --- config-template.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/config-template.json b/config-template.json index 779b44d..f995c53 100644 --- a/config-template.json +++ b/config-template.json @@ -4,8 +4,6 @@ "channel_type": "wx", "proxy": "", "hot_reload": false, - "model": "claude", - "channel_type": "wx", "claude_api_cookie": "", "single_chat_prefix": [ "bot", From bac70108b226b63c25a39aafbeb2eea36ef4d818 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 10:32:03 +0800 Subject: [PATCH 16/28] Update requirements.txt --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 74bc96e..0863125 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,3 @@ chardet>=5.1.0 Pillow pre-commit web.py -curl_cffi From 7dc7105ee2893a07ef494da3ac20d1b4b966342c Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 10:32:33 +0800 Subject: [PATCH 17/28] Update requirements-optional.txt --- requirements-optional.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/requirements-optional.txt b/requirements-optional.txt index 1cb8a55..17c4c1f 100644 --- a/requirements-optional.txt +++ b/requirements-optional.txt @@ -28,3 +28,6 @@ chatgpt_tool_hub==0.4.6 # xunfei spark websocket-client==1.2.0 + +# claude bot +curl_cffi From 6fc158e7d6498145fad502b57d55f7e54682eaea Mon Sep 17 00:00:00 2001 From: zhayujie Date: Fri, 1 Sep 2023 11:32:58 +0800 Subject: [PATCH 18/28] hotfix: config.py format --- config.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config.py b/config.py index 276eb22..68e6404 100644 --- a/config.py +++ b/config.py @@ -59,6 +59,11 @@ available_setting = { "xunfei_app_id": "", # 讯飞应用ID "xunfei_api_key": "", # 讯飞 API key "xunfei_api_secret": "", # 讯飞 API secret + # claude 配置 + "claude_api_cookie": "", + "claude_uuid": "", + # wework的通用配置 + "wework_smart": True, # 配置wework是否使用已登录的企业微信,False为多开 # 语音设置 "speech_recognition": False, # 是否开启语音识别 "group_speech_recognition": False, # 是否开启群组语音识别 @@ -121,11 +126,6 @@ available_setting = { "linkai_api_key": "", "linkai_app_code": "", "linkai_api_base": "https://api.link-ai.chat", # linkAI服务地址,若国内无法访问或延迟较高可改为 https://api.link-ai.tech - # wework的通用配置 - "wework_smart": True # 配置wework是否使用已登录的企业微信,False为多开 - #claude 配置 - "claude_api_cookie":"", - "claude_uuid":"" } From 53b2deb72caa35dd6ba9b19c06c41f538f0da6e7 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:38:58 +0800 Subject: [PATCH 19/28] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=9C=BA=E5=99=A8?= =?UTF-8?q?=E4=BA=BA=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 934a944..352296d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ 最新版本支持的功能如下: - [x] **多端部署:** 有多种部署方式可选择且功能完备,目前已支持个人微信,微信公众号和企业微信应用等部署方式 -- [x] **基础对话:** 私聊及群聊的消息智能回复,支持多轮会话上下文记忆,支持 GPT-3, GPT-3.5, GPT-4, 文心一言, 讯飞星火 +- [x] **基础对话:** 私聊及群聊的消息智能回复,支持多轮会话上下文记忆,支持 GPT-3, GPT-3.5, GPT-4, Claude, 文心一言, 讯飞星火 - [x] **语音识别:** 可识别语音消息,通过文字或语音回复,支持 azure, baidu, google, openai等多种语音模型 - [x] **图片生成:** 支持图片生成 和 图生图(如照片修复),可选择 Dell-E, stable diffusion, replicate, midjourney模型 - [x] **丰富插件:** 支持个性化插件扩展,已实现多角色切换、文字冒险、敏感词过滤、聊天记录总结等插件 @@ -27,6 +27,7 @@ Demo made by [Visionn](https://www.wangpc.cc/) # 更新日志 +>**2023.09.01:** 接入讯飞星火,Claude机器人 >**2023.08.08:** 接入百度文心一言模型,通过 [插件](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins/linkai) 支持 Midjourney 绘图 @@ -157,7 +158,7 @@ pip3 install azure-cognitiveservices-speech **4.其他配置** -+ `model`: 模型名称,目前支持 `gpt-3.5-turbo`, `text-davinci-003`, `gpt-4`, `gpt-4-32k`, `wenxin` (其中gpt-4 api暂未完全开放,申请通过后可使用) ++ `model`: 模型名称,目前支持 `gpt-3.5-turbo`, `text-davinci-003`, `gpt-4`, `gpt-4-32k`, `wenxin` , `claude` , `xunfei`(其中gpt-4 api暂未完全开放,申请通过后可使用) + `temperature`,`frequency_penalty`,`presence_penalty`: Chat API接口参数,详情参考[OpenAI官方文档。](https://platform.openai.com/docs/api-reference/chat) + `proxy`:由于目前 `openai` 接口国内无法访问,需配置代理客户端的地址,详情参考 [#351](https://github.com/zhayujie/chatgpt-on-wechat/issues/351) + 对于图像生成,在满足个人或群组触发条件外,还需要额外的关键词前缀来触发,对应配置 `image_create_prefix ` @@ -175,6 +176,26 @@ pip3 install azure-cognitiveservices-speech + `linkai_api_key`: LinkAI Api Key,可在 [控制台](https://chat.link-ai.tech/console/interface) 创建 + `linkai_app_code`: LinkAI 应用code,选填 +**6.wenxin配置 (可选 model 为 wenxin 时生效)** + ++ `baidu_wenxin_api_key`: 文心一言官网api key。 ++ `baidu_wenxin_secret_key`: 文心一言官网secret key。 + + +**6.Claude配置 (可选 model 为 claude 时生效)** + ++ `claude_api_cookie`: claude官网聊天界面复制完整 cookie 字符串。 ++ `claude_uuid`: 可以指定对话id,默认新建对话实体。 + + +**7.xunfei配置 (可选 model 为 xunfei 时生效)** + ++ `xunfei_app_id`: 讯飞星火app id。 ++ `xunfei_api_key`: 讯飞星火 api key。 ++ `xunfei_api_secret`: 讯飞星火 secret。 + + + **本说明文档可能会未及时更新,当前所有可选的配置项均在该[`config.py`](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/config.py)中列出。** ## 运行 From 22210747d074df3d8fd8e4d8a85943c4da009364 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:40:09 +0800 Subject: [PATCH 20/28] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 352296d..5a95a57 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ 最新版本支持的功能如下: - [x] **多端部署:** 有多种部署方式可选择且功能完备,目前已支持个人微信,微信公众号和企业微信应用等部署方式 -- [x] **基础对话:** 私聊及群聊的消息智能回复,支持多轮会话上下文记忆,支持 GPT-3, GPT-3.5, GPT-4, Claude, 文心一言, 讯飞星火 +- [x] **基础对话:** 私聊及群聊的消息智能回复,支持多轮会话上下文记忆,支持 GPT-3, GPT-3.5, GPT-4, claude, 文心一言, 讯飞星火 - [x] **语音识别:** 可识别语音消息,通过文字或语音回复,支持 azure, baidu, google, openai等多种语音模型 - [x] **图片生成:** 支持图片生成 和 图生图(如照片修复),可选择 Dell-E, stable diffusion, replicate, midjourney模型 - [x] **丰富插件:** 支持个性化插件扩展,已实现多角色切换、文字冒险、敏感词过滤、聊天记录总结等插件 @@ -27,7 +27,7 @@ Demo made by [Visionn](https://www.wangpc.cc/) # 更新日志 ->**2023.09.01:** 接入讯飞星火,Claude机器人 +>**2023.09.01:** 接入讯飞星火,claude机器人 >**2023.08.08:** 接入百度文心一言模型,通过 [插件](https://github.com/zhayujie/chatgpt-on-wechat/tree/master/plugins/linkai) 支持 Midjourney 绘图 From 054f927c057d5f5d68284ec1b6ce89c22e301850 Mon Sep 17 00:00:00 2001 From: zhayujie Date: Fri, 1 Sep 2023 13:45:04 +0800 Subject: [PATCH 21/28] fix: at_list bug in wechat channel --- channel/chat_channel.py | 7 ++++--- config-template.json | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/channel/chat_channel.py b/channel/chat_channel.py index 33b3d7f..f3a6482 100644 --- a/channel/chat_channel.py +++ b/channel/chat_channel.py @@ -109,9 +109,10 @@ class ChatChannel(Channel): flag = True pattern = f"@{re.escape(self.name)}(\u2005|\u0020)" subtract_res = re.sub(pattern, r"", content) - for at in context["msg"].at_list: - pattern = f"@{re.escape(at)}(\u2005|\u0020)" - subtract_res = re.sub(pattern, r"", subtract_res) + if isinstance(context["msg"].at_list, list): + for at in context["msg"].at_list: + pattern = f"@{re.escape(at)}(\u2005|\u0020)" + subtract_res = re.sub(pattern, r"", subtract_res) if subtract_res == content and context["msg"].self_display_name: # 前缀移除后没有变化,使用群昵称再次移除 pattern = f"@{re.escape(context['msg'].self_display_name)}(\u2005|\u0020)" diff --git a/config-template.json b/config-template.json index f995c53..f01633d 100644 --- a/config-template.json +++ b/config-template.json @@ -4,7 +4,6 @@ "channel_type": "wx", "proxy": "", "hot_reload": false, - "claude_api_cookie": "", "single_chat_prefix": [ "bot", "@bot" From 9a1e10deff67008323d4f103de38e63856253258 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:30:31 +0800 Subject: [PATCH 22/28] Create claude_ai_session --- bot/claude/claude_ai_session | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 bot/claude/claude_ai_session diff --git a/bot/claude/claude_ai_session b/bot/claude/claude_ai_session new file mode 100644 index 0000000..ede9e51 --- /dev/null +++ b/bot/claude/claude_ai_session @@ -0,0 +1,9 @@ +from bot.session_manager import Session + + +class ClaudeAiSession(Session): + def __init__(self, session_id, system_prompt=None, model="claude"): + super().__init__(session_id, system_prompt) + self.model = model + # claude逆向不支持role prompt + # self.reset() From 503c6c9b7eab71f5cceec0d34d5497dd755fdab0 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:31:30 +0800 Subject: [PATCH 23/28] Update claude_ai_bot.py --- bot/claude/claude_ai_bot.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/bot/claude/claude_ai_bot.py b/bot/claude/claude_ai_bot.py index 24ff11f..9d97624 100644 --- a/bot/claude/claude_ai_bot.py +++ b/bot/claude/claude_ai_bot.py @@ -4,7 +4,7 @@ import json import uuid from curl_cffi import requests from bot.bot import Bot -from bot.chatgpt.chat_gpt_session import ChatGPTSession +from bot.claude.claude_ai_session import ClaudeAiSession from bot.openai.open_ai_image import OpenAIImage from bot.session_manager import SessionManager from bridge.context import Context, ContextType @@ -16,9 +16,10 @@ from config import conf class ClaudeAIBot(Bot, OpenAIImage): def __init__(self): super().__init__() - self.sessions = SessionManager(ChatGPTSession, model=conf().get("model") or "gpt-3.5-turbo") + self.sessions = SessionManager(ClaudeAiSession, model=conf().get("model") or "gpt-3.5-turbo") self.claude_api_cookie = conf().get("claude_api_cookie") self.proxy = conf().get("proxy") + self.con_uuid_dic = {} if self.proxy: self.proxies = { "http": self.proxy, @@ -27,8 +28,6 @@ class ClaudeAIBot(Bot, OpenAIImage): else: self.proxies = None self.org_uuid = self.get_organization_id() - self.con_uuid = None - self.get_uuid() def generate_uuid(self): random_uuid = uuid.uuid4() @@ -40,8 +39,9 @@ class ClaudeAIBot(Bot, OpenAIImage): if conf().get("claude_uuid") != None: self.con_uuid = conf().get("claude_uuid") else: - self.con_uuid = self.generate_uuid() - self.create_new_chat() + con_uuid = self.generate_uuid() + self.create_new_chat(con_uuid) + def get_organization_id(self): url = "https://claude.ai/api/organizations" @@ -99,10 +99,16 @@ class ClaudeAIBot(Bot, OpenAIImage): print(response.text) return uuid - - def create_new_chat(self): + + def conversation_share_check(self,session_id): + if session_id not in self.con_uuid_dic: + self.con_uuid_dic[session_id] = self.generate_uuid() + self.create_new_chat(self.con_uuid_dic[session_id]) + return self.con_uuid_dic[session_id] + + def create_new_chat(self, con_uuid): url = f"https://claude.ai/api/organizations/{self.org_uuid}/chat_conversations" - payload = json.dumps({"uuid": self.con_uuid, "name": ""}) + payload = json.dumps({"uuid": con_uuid, "name": ""}) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', @@ -118,7 +124,7 @@ class ClaudeAIBot(Bot, OpenAIImage): 'Sec-Fetch-Site': 'same-origin', 'TE': 'trailers' } - response = requests.post( url, headers=headers, data=payload,impersonate="chrome110", proxies= self.proxies) + response = requests.post(url, headers=headers, data=payload,impersonate="chrome110", proxies= self.proxies) # Returns JSON of the newly created conversation information return response.json() @@ -138,6 +144,8 @@ class ClaudeAIBot(Bot, OpenAIImage): try: session_id = context["session_id"] session = self.sessions.session_query(query, session_id) + con_uuid = self.conversation_share_check(session_id) + model = conf().get("model") or "gpt-3.5-turbo" # remove system message if session.messages[0].get("role") == "system": @@ -154,7 +162,7 @@ class ClaudeAIBot(Bot, OpenAIImage): "model": "claude-2" }, "organization_uuid": f"{self.org_uuid}", - "conversation_uuid": f"{self.con_uuid}", + "conversation_uuid": f"{con_uuid}", "text": f"{query}", "attachments": [] }) @@ -190,13 +198,14 @@ class ClaudeAIBot(Bot, OpenAIImage): reply_content = ''.join(completions) logger.info(f"[CLAUDE] reply={reply_content}, total_tokens=invisible") + self.sessions.session_reply(reply_content, session_id, 100) return Reply(ReplyType.TEXT, reply_content) else: response = res.json() error = response.get("error") logger.error(f"[CLAUDE] chat failed, status_code={res.status_code}, " - f"msg={error.get('message')}, type={error.get('type')}, detail: {res.text}, uuid: {self.con_uuid}") + f"msg={error.get('message')}, type={error.get('type')}, detail: {res.text}, uuid: {con_uuid}") if res.status_code >= 500: # server error, need retry @@ -210,4 +219,4 @@ class ClaudeAIBot(Bot, OpenAIImage): # retry time.sleep(2) logger.warn(f"[CLAUDE] do retry, times={retry_count}") - return self._chat(query, context, retry_count + 1) \ No newline at end of file + return self._chat(query, context, retry_count + 1) From 97a26d4a46ed3c42774daaaf275346096c96d69a Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:53:21 +0800 Subject: [PATCH 24/28] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5a95a57..d11714a 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,6 @@ pip3 install azure-cognitiveservices-speech **6.Claude配置 (可选 model 为 claude 时生效)** + `claude_api_cookie`: claude官网聊天界面复制完整 cookie 字符串。 -+ `claude_uuid`: 可以指定对话id,默认新建对话实体。 **7.xunfei配置 (可选 model 为 xunfei 时生效)** From 559194ffb22d381951af1b078a78c039906f59c8 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:54:03 +0800 Subject: [PATCH 25/28] Update config.py --- config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.py b/config.py index 276eb22..622e159 100644 --- a/config.py +++ b/config.py @@ -124,8 +124,7 @@ available_setting = { # wework的通用配置 "wework_smart": True # 配置wework是否使用已登录的企业微信,False为多开 #claude 配置 - "claude_api_cookie":"", - "claude_uuid":"" + "claude_api_cookie":"" } From 081003df471d01c5bea38481e56e3b4476bf299d Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:55:09 +0800 Subject: [PATCH 26/28] Update config.py --- config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.py b/config.py index 622e159..276eb22 100644 --- a/config.py +++ b/config.py @@ -124,7 +124,8 @@ available_setting = { # wework的通用配置 "wework_smart": True # 配置wework是否使用已登录的企业微信,False为多开 #claude 配置 - "claude_api_cookie":"" + "claude_api_cookie":"", + "claude_uuid":"" } From 6ba0baabb0c2024379b7d114843a8a22d84d1b51 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 18:04:39 +0800 Subject: [PATCH 27/28] Update claude_ai_bot.py --- bot/claude/claude_ai_bot.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bot/claude/claude_ai_bot.py b/bot/claude/claude_ai_bot.py index 9d97624..d273f2c 100644 --- a/bot/claude/claude_ai_bot.py +++ b/bot/claude/claude_ai_bot.py @@ -42,7 +42,6 @@ class ClaudeAIBot(Bot, OpenAIImage): con_uuid = self.generate_uuid() self.create_new_chat(con_uuid) - def get_organization_id(self): url = "https://claude.ai/api/organizations" headers = { @@ -78,7 +77,6 @@ class ClaudeAIBot(Bot, OpenAIImage): def get_organization_id(self): url = "https://claude.ai/api/organizations" - headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0', @@ -97,7 +95,6 @@ class ClaudeAIBot(Bot, OpenAIImage): uuid = res[0]['uuid'] except: print(response.text) - return uuid def conversation_share_check(self,session_id): @@ -145,7 +142,6 @@ class ClaudeAIBot(Bot, OpenAIImage): session_id = context["session_id"] session = self.sessions.session_query(query, session_id) con_uuid = self.conversation_share_check(session_id) - model = conf().get("model") or "gpt-3.5-turbo" # remove system message if session.messages[0].get("role") == "system": From 4167f13bacea20d63868d0fb63585334e3b20533 Mon Sep 17 00:00:00 2001 From: resphina <69687075+resphinas@users.noreply.github.com> Date: Fri, 1 Sep 2023 18:12:48 +0800 Subject: [PATCH 28/28] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d11714a..5a95a57 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,7 @@ pip3 install azure-cognitiveservices-speech **6.Claude配置 (可选 model 为 claude 时生效)** + `claude_api_cookie`: claude官网聊天界面复制完整 cookie 字符串。 ++ `claude_uuid`: 可以指定对话id,默认新建对话实体。 **7.xunfei配置 (可选 model 为 xunfei 时生效)**