一个逆向工程的 Python API 封装,用于 Quora 的 Poe,它提供了免费访问 ChatGPT、GPT-4 和 Claude 的功能。
作者:Sec-Labs | 发布时间:
项目地址
https://github.com/ading2210/poe-api
Python Poe API
这是一个对 Quora 的 Poe 进行了逆向工程的 API 包装器,它让你可以自由访问 OpenAI 的 ChatGPT 和 GPT-4,以及 Anthropic 的 Claude。
目录:
目录由 markdown-toc 生成。
功能:
- 使用 Token 登录
- 代理请求 + Websocket
- 下载机器人列表
- 发送消息
- 流式传输机器人响应
- 清除对话上下文
- 下载对话历史
- 删除消息
- 清空整个对话
- 创建自定义机器人
- 编辑你的自定义机器人
- 使用现有的第三方机器人
安装:
你可以通过运行以下命令来安装这个库:
pip3 install poe-api
文档:
例子可以在 /examples 目录中找到。要运行这些例子,请将你的 Token 作为命令行参数传递。
python3 examples/temporary_message.py "TOKEN_HERE"
找到你的 Token:
在任何桌面 Web 浏览器上登录 Poe,然后打开你的浏览器开发工具(也称为“检查”),并在以下菜单中查找 p-b cookie 的值:
- Chromium:Devtools > Application > Cookies > poe.com
- Firefox:Devtools > Storage > Cookies
- Safari:Devtools > Storage > Cookies
使用客户端:
要使用这个库,只需导入 poe 并创建一个 poe.Client 实例。Client 类接受以下参数:
token- 要使用的 Token。proxy = None- 要使用的代理,格式为protocol://host:port。建议使用socks5h协议,因为它还代理了 DNS 查询。device_id = None- 要使用的设备 ID。如果未指定,则会随机生成并存储在磁盘上。headers = headers- 要使用的头信息。默认为poe.headers中指定的头信息。client_identifier = client_identifier- 将传递到 TLS 客户端库中的客户端标识符。默认为poe.client_identifier中指定的标识符。
常规例子:
import poe
client = poe.Client("TOKEN_HERE")
代理例子:
import poe
client = poe.Client("TOKEN_HERE", proxy="socks5h://178.62.100.151:59166")
请注意,以下例子假设 client 是你的 poe.Client 实例的名称。如果 Token 无效,将引发 RuntimeError。
下载可用的机器人:
客户端在初始化时下载所有可用的机器人,并将它们存储在 client.bots 中。将机器人代码名称映射到其显示名称的字典可以在 client.bot_names 中找到。如果你想刷新这些值,可以调用 client.get_bots。此函数接受以下参数:
download_next_data = True- 是否重新下载__NEXT_DATA__,如果机器人列表已更改,则需要此数据。
print(json.dumps(client.bot_names, indent=2))
"""
{
"capybara": "Sage",
"a2": "Claude-instant",
"nutria": "Dragonfly",
"a2_100k": "Claude-instant-100k",
"beaver": "GPT-4",
"chinchilla": "ChatGPT",
"a2_2": "Claude+"
}
"""
请注意,在免费帐户上,Claude+(a2_2)每天有 3 条消息的限制,GPT-4(beaver)每天有 1 条消息的限制。对于所有其他聊天机器人,似乎有每分钟 10 条消息的速率限制。
使用第三方机器人:
要获取第三方机器人的列表,请使用 client.explore_bots,它接受以下参数:
end_cursor = None- 获取列表时要使用的游标。count = 25- 返回的机器人数量。
该函数将返回一个包含机器人列表和下一页游标的字典:
print(json.dumps(client.explore_bots(count=1), indent=2))
"""
{
"bots": [
{
"id": "Qm90OjEwMzI2MDI=",
"displayName": "leocooks",
"deletionState": "not_deleted",
"image": {
"__typename": "UrlBotImage",
"url": "https://qph.cf2.quoracdn.net/main-thumb-pb-1032602-200-uorvomwowfgmatdvrtwajtwwqlujmmgu.jpeg"
},
"botId": 1032602,
"followerCount": 1922,
"description": "Above average meals for average cooks, made simple by world-renowned chef, Leonardo",
"__typename": "Bot"
}
],
"end_cursor": "1000172"
}
"""
要获取特定的第三方机器人,可以使用 client.get_bot_by_codename,它接受机器人的代码名称作为其唯一参数。
client.get_bot_by_codename("JapaneseTutor")
由于自定义机器人的显示名称与代码名称相同,因此你只需将机器人的显示名称传递到 client.send_message 中即可向其发送消息。
创建新机器人:
你可以使用 client.create_bot 函数创建新的机器人,它接受以下参数:
handle- 新机器人的 Handle。prompt = ""- 新机器人的提示。base_model = "chinchilla"- 新机器人使用的模型。这必须是"chinchilla"(ChatGPT)或"a2"(Claude)之一。description = ""- 新机器人的描述。intro_message = ""- 新机器人的介绍消息。如果这是一个空字符串,则机器人将没有介绍消息。prompt_public = True- 提示是否应该公开可见。pfp_url = None- 机器人资料图片的 URL。目前,使用此库没有上传自定义图片的方法。linkification = False- 机器人是否应该将响应中的某些文本转换为可点击的链接。markdown_rendering = True- 是否要启用机器人响应的 Markdown 渲染。suggested_replies = False- 机器人是否应该在每次响应后建议可能的回复。private = False- 机器人是否应该是私有的。
如果要让新机器人使用自己的 API(如此处所述 链接):
api_key = None- 新机器人的 API 密钥。api_bot = False- 机器人是否已启用 API 功能。api_url = None- 新机器人的 API URL。
有关如何创建和编辑机器人的完整示例位于 examples/create_bot.py 中。
new_bot = client.create_bot(bot_name, "prompt goes here", base_model="a2")
编辑机器人:
你可以使用 client.edit_bot 函数编辑自定义机器人,它接受以下参数:
bot_id- 要编辑的机器人的botId。handle- 要编辑的机器人的 Handle。prompt- 新机器人的提示。base_model = "chinchilla"- 新模型机器人使用的模型。这必须是"chinchilla"(ChatGPT)或"a2"(Claude)之一。以前,它可以设置为"beaver"(GPT-4),从而绕过免费帐户的限制,但现在已修复。description = ""- 新机器人的描述。intro_message = ""- 新机器人的介绍消息。如果这是一个空字符串,则机器人将没有介绍消息。prompt_public = True- 提示是否应该公开可见。pfp_url = None- 机器人资料图片的 URL。目前,使用此库没有上传自定义图片的方法。linkification = False- 机器人是否应该将响应中的某些文本转换为可点击的链接。markdown_rendering = True- 是否要启用机器人响应的 Markdown 渲染。suggested_replies = False- 机器人是否应该在每次响应后建议可能的回复。private = False- 机器人是否应该是私有的。
机器人 API 相关参数:
api_key = None- 机器人的新 API 密钥。api_url = None- 机器人的新 API URL。
有关如何创建和编辑机器人的完整示例位于 examples/create_bot.py 中。
edit_result = client.edit_bot(1086981, "bot_handle_here", base_model="a2")
发送消息:
你可以使用 client.send_message 函数向聊天机器人发送消息,它接受以下参数:
chatbot- 聊天机器人的代码名称。(例如:capybara)message- 要发送给聊天机器人的消息。with_chat_break = False- 是否应清除对话上下文。timeout = 20- 接收到的块之间的最大秒数,直到引发RuntimeError。
该函数是一个生成器,每当生成的消息更新时,它就会返回最新版本的消息。
流示例:
message = "Summarize the GNU GPL v3"
for chunk in client.send_message("capybara", message):
print(chunk["text_new"], end="", flush=True)
非流示例:
message = "Summarize the GNU GPL v3"
for chunk in client.send_message("capybara", message):
pass
print(chunk["text"])
你还可以使用 threading 并行发送多条消息,并分别接收它们的响应,如 /examples/parallel_messages.py 中所示。请注意,如果发送消息过快,服务器会给出错误,但请求最终会成功。
清除对话上下文:
如果你想在不发送消息的情况下清除对话的上下文,可以使用 client.send_chat_break。唯一的参数是要清除其上下文的机器人的代码名称。
client.send_chat_break("capybara")
该函数返回表示聊天中断的消息。
下载对话历史记录:
要下载会话中的过去消息,请使用 client.get_message_history 函数,它接受以下参数:
chatbot- 聊天机器人的代码名称。count = 25- 要下载的消息数。cursor = None- 要从其中开始而不是从最新消息开始的消息 ID。
请注意,如果您不指定光标,则客户端必须执行额外的请求以确定最新的光标。
返回的消息按照从旧到新的顺序排列。
message_history = client.get_message_history("capybara", count=10)
print(json.dumps(message_history, indent=2))
"""
[
{
"node": {
"id": "TWVzc2FnZToxMDEwNzYyODU=",
"messageId": 101076285,
"creationTime": 1679298157718888,
"text": "",
"author": "chat_break",
"linkifiedText": "",
"state": "complete",
"suggestedReplies": [],
"vote": null,
"voteReason": null,
"__typename": "Message"
},
"cursor": "101076285",
"id": "TWVzc2FnZUVkZ2U6MTAxMDc2Mjg1OjEwMTA3NjI4NQ=="
},
...
]
"""
删除消息:
要删除消息,请使用 client.delete_message 函数,它接受一个参数。你可以将单个消息 ID 传递给它以删除单个消息,或者你可以传递消息 ID 的列表以一次删除多个消息。
#删除单个消息
client.delete_message(96105719)
#一次删除多个消息
client.delete_message([96105719, 96097108, 96097078, 96084421, 96084402])
清空对话:
要清空整个对话或仅删除最后几条消息,你可以使用 client.purge_conversation 函数。此函数接受以下参数:
chatbot- 聊天机器人的代码名称。count = -1- 要删除的消息数,从最新的消息开始计算。默认行为是删除每个单独的消息。
#仅清空最后10条消息
client.purge_conversation("capybara", count=10)
#清空整个对话
client.purge_conversation("capybara")
清空所有对话:
要清空帐户中的所有对话,使用 client.purge_all_conversations 函数。此函数不需要任何参数。
>>> client.purge_all_conversations()
获取剩余消息数:
要获取对话配额中剩余的消息数,请使用 client.get_remaining_messages 函数。此函数接受以下参数:
chatbot- 聊天机器人的代码名称。
该函数将返回剩余的消息数,如果机器人没有配额,则返回 None。
>>> client.get_remaining_messages("beaver")
1
其他:
更改日志级别:
如果要显示调试消息,只需调用 poe.logger.setLevel。
import poe
import logging
poe.logger.setLevel(logging.INFO)
设置自定义 User-Agent:
如果要更改伪造的标头,请在导入库后设置 poe.headers。
要使用你的浏览器自己的标头,请访问此网站,并复制粘贴其内容。
import poe
poe.headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-US,en;q=0.5",
"Te": "trailers",
"Upgrade-Insecure-Requests": "1"
}
以下标头将被忽略和覆盖:
{
"Referrer": "https://poe.com/",
"Origin": "https://poe.com",
"Host": "poe.com",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin"
}
以前,这是通过 poe.user_agent 进行的,但现在该变量完全被忽略。
你还需要更改 poe.client_identifier 以匹配你设置的用户代理。请参阅 Python-TLS-Client 文档 获取一些示例值。请注意,伪造 Chrome/Firefox 版本 >= 110 可能是可检测的。
poe.client_identifier = "chrome_107"
设置自定义设备 ID:
如果要更改伪造的设备 ID,可以使用 poe.set_device_id,它接受以下参数:
user_id- 要更改设备 ID 的帐户的用户 ID。用户 ID 可在client.viewer["poeUser"]["id"]处找到。device_id- 新的设备 ID。这是一个32个字符的 UUID 字符串,格式如下:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
poe.set_device_id("UGMlVXqlcLYyMOATMDsKNTMz", "6d659b04-043a-41f8-97c7-fb7d7fe9ad34")
设备 ID 保存在 Unix-like 系统中的 ~/.config/poe-api/device_id.json,在 Windows 中的 C:\Users\<user>\AppData\Roaming\poe-api\device_id.json 中。
此外,可以使用 poe.get_device_id 函数或 client.device_id 来检索保存的设备 ID。
>>> poe.get_device_id("UGMlVXqlcLYyMOATMDsKNTMz")
#6d659b04-043a-41f8-97c7-fb7d7fe9ad34
>>> client.device_id
#6d659b04-043a-41f8-97c7-fb7d7fe9ad34