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/17] 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 000000000..827e8eddf
--- /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/17] 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 513eb7868..da12f952d 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 8c9a2504a..00f83e803 100644
--- a/bot/chatgpt/chat_gpt_bot.py
+++ b/bot/chatgpt/chat_gpt_bot.py
@@ -106,6 +106,10 @@ def reply(self, query, context=None):
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 000000000..bb1cbd8fb
--- /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 202243842..4a0ef4f1b 100644
--- a/bridge/bridge.py
+++ b/bridge/bridge.py
@@ -29,6 +29,8 @@ def __init__(self):
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 827e8eddf..000000000
--- 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 000000000..049614af8
--- /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 505ab71fa..ce3eac45e 100644
--- a/common/const.py
+++ b/common/const.py
@@ -5,7 +5,8 @@
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 f02a365b7..ac64530e2 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 f01633d61..003fbb670 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 5853b0dc8..cb043d14f 100644
--- a/config.py
+++ b/config.py
@@ -120,7 +120,9 @@
"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 f842f1f53..20726dd9b 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 85c0ca2eb..cdeb6fb15 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 086312536..4d5bfe4e0 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/17] 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 00f83e803..88a52f19b 100644
--- a/bot/chatgpt/chat_gpt_bot.py
+++ b/bot/chatgpt/chat_gpt_bot.py
@@ -106,10 +106,7 @@ def reply(self, query, context=None):
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 ce3eac45e..a85fec71d 100644
--- a/common/const.py
+++ b/common/const.py
@@ -5,7 +5,9 @@
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 20726dd9b..558889bf4 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 4d5bfe4e0..74bc96eb2 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/17] 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 003fbb670..6956a24aa 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/17] 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 6956a24aa..3af9fbcde 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/17] 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 bb1cbd8fb..71cc97018 100644
--- a/bot/claude/claude_ai_bot.py
+++ b/bot/claude/claude_ai_bot.py
@@ -2,7 +2,6 @@
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 @@
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 @@ def __init__(self):
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 @@ def get_uuid(self):
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 @@ def get_organization_id(self):
'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 @@ def get_organization_id(self):
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 @@ def create_new_chat(self):
'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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
}
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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
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/17] =?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 bb1cbd8fb..21ec5a9c6 100644
--- a/bot/claude/claude_ai_bot.py
+++ b/bot/claude/claude_ai_bot.py
@@ -2,7 +2,6 @@
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 @@
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 @@ def __init__(self):
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 @@ def get_uuid(self):
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 @@ def get_organization_id(self):
'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 @@ def get_organization_id(self):
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 @@ def create_new_chat(self):
'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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
}
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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
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 @@ def _chat(self, query, context, retry_count=0) -> Reply:
# 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 a85fec71d..20e9f89f7 100644
--- a/common/const.py
+++ b/common/const.py
@@ -5,10 +5,6 @@
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 ac64530e2..3f2829408 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 003fbb670..38d3ef6b1 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 558889bf4..f842f1f53 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 cdeb6fb15..85c0ca2eb 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/17] 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 21ec5a9c6..611561404 100644
--- a/bot/claude/claude_ai_bot.py
+++ b/bot/claude/claude_ai_bot.py
@@ -19,10 +19,13 @@ def __init__(self):
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/17] 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 611561404..24ff11fa3 100644
--- a/bot/claude/claude_ai_bot.py
+++ b/bot/claude/claude_ai_bot.py
@@ -141,7 +141,7 @@ def _chat(self, query, context, retry_count=0) -> Reply:
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/17] Update const.py
---
common/const.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/common/const.py b/common/const.py
index 20e9f89f7..959b4c1e4 100644
--- a/common/const.py
+++ b/common/const.py
@@ -5,6 +5,8 @@
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/17] 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 88a52f19b..8c9a2504a 100644
--- a/bot/chatgpt/chat_gpt_bot.py
+++ b/bot/chatgpt/chat_gpt_bot.py
@@ -106,7 +106,6 @@ def reply(self, query, context=None):
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/17] 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 3f2829408..f02a365b7 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/17] Update config-template.json
---
config-template.json | 1 -
1 file changed, 1 deletion(-)
diff --git a/config-template.json b/config-template.json
index 3af9fbcde..779b44d3c 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/17] 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 049614af8..000000000
--- 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/17] Update config-template.json
---
config-template.json | 2 --
1 file changed, 2 deletions(-)
diff --git a/config-template.json b/config-template.json
index 779b44d3c..f995c53ed 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/17] Update requirements.txt
---
requirements.txt | 1 -
1 file changed, 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index 74bc96eb2..086312536 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/17] Update requirements-optional.txt
---
requirements-optional.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/requirements-optional.txt b/requirements-optional.txt
index 1cb8a5521..17c4c1f73 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