XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/gpt4free

updated quora(poe) (token creation patched atm)

8c0f5e96
t.me/xtekky <98614666+xtekky@users.noreply.github.com>
提交于

代码差异

5 个文件 +86 -60
Modified quora/__init__.py +33 -15
@@ -8,6 +8,9 @@ from pathlib import Path
8 8 from random import choice, choices, randint
9 9 from string import ascii_letters, digits
10 10 from urllib import parse
11 from os import urandom
12 from hashlib import md5
13 from json import dumps
11 14
12 15 class PoeResponse:
13 16
@@ -91,6 +94,7 @@ class Model:
91 94 "sec-ch-ua" : "\"Chromium\";v=\"112\", \"Google Chrome\";v=\"112\", \"Not:A-Brand\";v=\"99\"",
92 95 "sec-ch-ua-mobile" : "?0",
93 96 "sec-ch-ua-platform": "\"macOS\"",
97 "content-type" : "application/json",
94 98 "sec-fetch-site" : "same-origin",
95 99 "sec-fetch-mode" : "cors",
96 100 "sec-fetch-dest" : "empty",
@@ -155,6 +159,7 @@ class Account:
155 159 "accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
156 160 "sec-fetch-site" : "same-origin",
157 161 "sec-fetch-mode" : "navigate",
162 "content-type" : "application/json",
158 163 "sec-fetch-user" : "?1",
159 164 "sec-fetch-dest" : "document",
160 165 "accept-encoding" : "gzip, deflate, br",
@@ -167,17 +172,21 @@ class Account:
167 172
168 173 client.headers["poe-formkey"] = next_data['props']['formkey']
169 174 client.headers["poe-tchannel"] = client.get('https://poe.com/api/settings').json()['tchannelData']['channel']
170
171 payload = {
172 "queryName": "MainSignupLoginSection_sendVerificationCodeMutation_Mutation",
173 "variables": {
174 "emailAddress": mail_address,
175 "phoneNumber" : None
175
176 payload = dumps(separators = (',', ':'), obj = {
177 'queryName': 'MainSignupLoginSection_sendVerificationCodeMutation_Mutation',
178 'variables': {
179 'emailAddress': mail_address,
180 'phoneNumber': None,
181 'recaptchaToken': None,
176 182 },
177 "query": "mutation MainSignupLoginSection_sendVerificationCodeMutation_Mutation(\n $emailAddress: String\n $phoneNumber: String\n) {\n sendVerificationCode(verificationReason: login, emailAddress: $emailAddress, phoneNumber: $phoneNumber) {\n status\n errorMessage\n }\n}\n"
178 }
183 'query': 'mutation MainSignupLoginSection_sendVerificationCodeMutation_Mutation(\n $emailAddress: String\n $phoneNumber: String\n $recaptchaToken: String\n) {\n sendVerificationCode(verificationReason: login, emailAddress: $emailAddress, phoneNumber: $phoneNumber, recaptchaToken: $recaptchaToken) {\n status\n errorMessage\n }\n}\n',
184 })
185
186 base_string = payload + client.headers["poe-formkey"] + 'WpuLMiXEKKE98j56k'
187 client.headers["poe-tag-id"] = md5(base_string.encode()).hexdigest()
179 188
180 response = client.post('https://poe.com/api/gql_POST', json=payload)
189 response = client.post('https://poe.com/api/gql_POST', data=payload)
181 190 if 'Bad Request' in response.text:
182 191 if logging: print('bad request, retrying...' , response.json())
183 192 Account.create(proxy = proxy, logging = logging)
@@ -197,7 +206,7 @@ class Account:
197 206
198 207 if logging: print('code', mail_token)
199 208
200 payload = {
209 payload = dumps(separators = (',', ':'), obj={
201 210 "queryName": "SignupOrLoginWithCodeSection_signupWithVerificationCodeMutation_Mutation",
202 211 "variables": {
203 212 "verificationCode" : mail_token,
@@ -205,9 +214,12 @@ class Account:
205 214 "phoneNumber" : None
206 215 },
207 216 "query": "mutation SignupOrLoginWithCodeSection_signupWithVerificationCodeMutation_Mutation(\n $verificationCode: String!\n $emailAddress: String\n $phoneNumber: String\n) {\n signupWithVerificationCode(verificationCode: $verificationCode, emailAddress: $emailAddress, phoneNumber: $phoneNumber) {\n status\n errorMessage\n }\n}\n"
208 }
217 })
218
219 base_string = payload + client.headers["poe-formkey"] + 'WpuLMiXEKKE98j56k'
220 client.headers["poe-tag-id"] = md5(base_string.encode()).hexdigest()
209 221
210 response = client.post('https://poe.com/api/gql_POST', json = payload)
222 response = client.post('https://poe.com/api/gql_POST', data = payload)
211 223 if logging: print('verify_code', response.json())
212 224
213 225 token = parse.unquote(client.cookies.get_dict()['p-b'])
@@ -216,11 +228,17 @@ class Account:
216 228 f.write(f'{token}\n')
217 229
218 230 if enable_bot_creation:
219 client.post("https://poe.com/api/gql_POST", json = {
231
232 payload = {
220 233 "queryName": "UserProfileConfigurePreviewModal_markMultiplayerNuxCompleted_Mutation",
221 234 "variables": {},
222 235 "query": "mutation UserProfileConfigurePreviewModal_markMultiplayerNuxCompleted_Mutation {\n markMultiplayerNuxCompleted {\n viewer {\n hasCompletedMultiplayerNux\n id\n }\n }\n}\n"
223 })
236 }
237
238 base_string = dumps(payload, separators = (',', ':')) + client.headers["poe-formkey"] + 'WpuLMiXEKKE98j56k'
239 client.headers["poe-tag-id"] = md5(base_string.encode()).hexdigest()
240
241 client.post("https://poe.com/api/gql_POST", json = payload)
224 242
225 243 return token
226 244
@@ -305,4 +323,4 @@ class Completion:
305 323 'completion_tokens' : len(chunk["text"]),
306 324 'total_tokens' : len(prompt) + len(chunk["text"])
307 325 }
308 })
326 })
Modified quora/api.py +50 -44
@@ -1,19 +1,3 @@
1 # ading2210/poe-api: a reverse engineered Python API wrapepr for Quora's Poe
2 # Copyright (C) 2023 ading2210
3
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17 1 import requests
18 2 import re
19 3 import json
@@ -71,14 +55,6 @@ class Client:
71 55 home_url = "https://poe.com"
72 56 settings_url = "https://poe.com/api/settings"
73 57
74 formkey = ""
75 next_data = {}
76 bots = {}
77 active_messages = {}
78 message_queues = {}
79 ws = None
80 ws_connected = False
81
82 58 def __init__(self, token, proxy=None):
83 59 self.proxy = proxy
84 60 self.session = requests.Session()
@@ -90,6 +66,9 @@ class Client:
90 66 }
91 67 logger.info(f"Proxy enabled: {self.proxy}")
92 68
69 self.active_messages = {}
70 self.message_queues = {}
71
93 72 self.session.cookies.set("p-b", token, domain="poe.com")
94 73 self.headers = {
95 74 "User-Agent": user_agent,
@@ -99,10 +78,10 @@ class Client:
99 78 self.ws_domain = f"tch{random.randint(1, 1e6)}"
100 79
101 80 self.session.headers.update(self.headers)
102 self.next_data = self.get_next_data()
81 self.next_data = self.get_next_data(overwrite_vars=True)
103 82 self.channel = self.get_channel_data()
104 83 self.connect_ws()
105 self.bots = self.get_bots()
84 self.bots = self.get_bots(download_next_data=False)
106 85 self.bot_names = self.get_bot_names()
107 86
108 87 self.gql_headers = {
@@ -112,7 +91,7 @@ class Client:
112 91 self.gql_headers = {**self.gql_headers, **self.headers}
113 92 self.subscribe()
114 93
115 def get_next_data(self):
94 def get_next_data(self, overwrite_vars=False):
116 95 logger.info("Downloading next_data...")
117 96
118 97 r = request_with_retries(self.session.get, self.home_url)
@@ -120,8 +99,9 @@ class Client:
120 99 json_text = re.search(json_regex, r.text).group(1)
121 100 next_data = json.loads(json_text)
122 101
123 self.formkey = next_data["props"]["formkey"]
124 self.viewer = next_data["props"]["pageProps"]["payload"]["viewer"]
102 if overwrite_vars:
103 self.formkey = next_data["props"]["formkey"]
104 self.viewer = next_data["props"]["pageProps"]["payload"]["viewer"]
125 105
126 106 return next_data
127 107
@@ -134,17 +114,23 @@ class Client:
134 114 chat_data = r.json()["pageProps"]["payload"]["chatOfBotDisplayName"]
135 115 return chat_data
136 116
137 def get_bots(self):
138 viewer = self.next_data["props"]["pageProps"]["payload"]["viewer"]
139 if not "availableBots" in viewer:
140 raise RuntimeError("Invalid token.")
141 bot_list = viewer["availableBots"]
117 def get_bots(self, download_next_data=True):
118 if download_next_data:
119 next_data = self.get_next_data()
120 else:
121 next_data = self.next_data
122
123 if not "availableBots" in self.viewer:
124 raise RuntimeError("Invalid token or no bots are available.")
125 bot_list = self.viewer["availableBots"]
142 126
143 127 bots = {}
144 128 for bot in bot_list:
145 chat_data = self.get_bot(bot["displayName"].lower())
129 chat_data = self.get_bot(bot["displayName"])
146 130 bots[chat_data["defaultBotObject"]["nickname"]] = chat_data
147 131
132 self.bots = bots
133 self.bot_names = self.get_bot_names()
148 134 return bots
149 135
150 136 def get_bot_names(self):
@@ -170,9 +156,20 @@ class Client:
170 156
171 157 def send_query(self, query_name, variables):
172 158 for i in range(20):
173 payload = generate_payload(query_name, variables)
159 json_data = generate_payload(query_name, variables)
160 payload = json.dumps(json_data, separators=(',', ':'))
161
162 base_string = payload + self.gql_headers['poe-formkey'] + 'WpuLMiXEKKE98j56k'
163
164 from hashlib import md5
165 headers = self.gql_headers |{
166 "content-type": "application/json",
167 "poe-tag-id": md5(base_string.encode()).hexdigest()
168 }
169
174 170 r = request_with_retries(
175 self.session.post, self.gql_url, json=payload, headers=self.gql_headers)
171 self.session.post, self.gql_url, data=payload, headers=headers)
172
176 173 data = r.json()
177 174 if data["data"] == None:
178 175 logger.warn(
@@ -212,6 +209,7 @@ class Client:
212 209 self.ws.run_forever(**kwargs)
213 210
214 211 def connect_ws(self):
212 self.ws_connected = False
215 213 self.ws = websocket.WebSocketApp(
216 214 self.get_websocket_url(),
217 215 header={"User-Agent": user_agent},
@@ -233,9 +231,10 @@ class Client:
233 231 def on_ws_connect(self, ws):
234 232 self.ws_connected = True
235 233
236 def on_ws_close(self, ws, close_status_code):
234 def on_ws_close(self, ws, close_status_code, close_message):
237 235 self.ws_connected = False
238 logger.warn(f"Websocket closed with status {close_status_code}")
236 logger.warn(
237 f"Websocket closed with status {close_status_code}: {close_message}")
239 238
240 239 def on_ws_error(self, ws, error):
241 240 self.disconnect_ws()
@@ -345,22 +344,27 @@ class Client:
345 344 def get_message_history(self, chatbot, count=25, cursor=None):
346 345 logger.info(f"Downloading {count} messages from {chatbot}")
347 346
347 messages = []
348 348 if cursor == None:
349 349 chat_data = self.get_bot(self.bot_names[chatbot])
350 350 if not chat_data["messagesConnection"]["edges"]:
351 351 return []
352 cursor = chat_data["messagesConnection"]["edges"][-1]["cursor"]
352 messages = chat_data["messagesConnection"]["edges"][:count]
353 cursor = chat_data["messagesConnection"]["pageInfo"]["startCursor"]
354 count -= len(messages)
353 355
354 356 cursor = str(cursor)
355 357 if count > 50:
356 358 messages = self.get_message_history(
357 chatbot, count=50, cursor=cursor)
359 chatbot, count=50, cursor=cursor) + messages
358 360 while count > 0:
361 count -= 50
359 362 new_cursor = messages[0]["cursor"]
360 363 new_messages = self.get_message_history(
361 364 chatbot, min(50, count), cursor=new_cursor)
362 365 messages = new_messages + messages
363 count -= 50
366 return messages
367 elif count <= 0:
364 368 return messages
365 369
366 370 result = self.send_query("ChatListPaginationQuery", {
@@ -368,7 +372,9 @@ class Client:
368 372 "cursor": cursor,
369 373 "id": self.bots[chatbot]["id"]
370 374 })
371 return result["data"]["node"]["messagesConnection"]["edges"]
375 query_messages = result["data"]["node"]["messagesConnection"]["edges"]
376 messages = query_messages + messages
377 return messages
372 378
373 379 def delete_message(self, message_ids):
374 380 logger.info(f"Deleting messages: {message_ids}")
@@ -398,4 +404,4 @@ class Client:
398 404 logger.info(f"No more messages left to delete.")
399 405
400 406
401 load_queries()
407 load_queries()
Modified quora/cookies.txt +2 -0
@@ -13,3 +13,5 @@ UP2wQVds17VFHh6IfCQFrA==
13 13 FNgKEpc2r-XqWe0rHBfYpg==
14 14 juCAh6kB0sUpXHvKik2woA==
15 15 nBvuNYRLaE4xE4HuzBPiIQ==
16 oyae3iClomSrk6RJywZ4iw==
17 1Z27Ul8BTdNOhncT5H6wdg==
Modified testing/poe_test.py +1 -1
@@ -6,7 +6,7 @@ print('token', token)
6 6
7 7 sleep(2)
8 8
9 for response in quora.StreamingCompletion.create(model = 'gpt-4',
9 for response in quora.StreamingCompletion.create(model = 'gpt-3.5-turbo',
10 10 prompt = 'hello world',
11 11 token = token):
12 12
Renamed testing/t3nsor_test.py +0 -0
此文件没有可显示的逐行差异。