返回提交历史
Modified
poe/__init__.py
+2
-3
Modified
poe/api.py
+116
-31
Modified
poe/cookies.txt
+6
-0
Modified
poe/graphql/ChatListPaginationQuery.graphql
+69
-7
Added
poe/graphql/SendMessageMutation.graphql
+40
-0
Added
testing/poe_test.py
+13
-0
XFEstudio/gpt4free
updated poe api (gpt4)
fixed tls_client issue by switching to request Session, and update the poe api
76571f25
代码差异
6 个文件
+246
-41
@@ -1,6 +1,6 @@
1
1
from poe.api import Client as PoeClient
2
2
from poe.mail import Mail
3
from tls_client import Session
3
from requests import Session
4
4
from re import search, findall
5
5
from json import loads
6
6
from time import sleep, time
@@ -48,11 +48,10 @@ class PoeResponse:
48
48
def json(self) -> dict:
49
49
return self.response_dict
50
50
51
52
51
class Account:
53
52
def create(proxy: None or str = None, logging: bool = False):
54
53
55
client = Session(client_identifier = "chrome110")
54
client = Session()
56
55
client.proxies = {
57
56
'http': f'http://{proxy}',
58
57
'https': f'http://{proxy}'} if proxy else None
@@ -22,6 +22,7 @@ import logging
22
22
import time
23
23
import queue
24
24
import threading
25
import traceback
25
26
import websocket
26
27
from pathlib import Path
27
28
from urllib.parse import urlparse
@@ -124,6 +125,15 @@ class Client:
124
125
125
126
return next_data
126
127
128
def get_bot(self, display_name):
129
url = f'https://poe.com/_next/data/{self.next_data["buildId"]}/{display_name}.json'
130
logger.info("Downloading "+url)
131
132
r = request_with_retries(self.session.get, url)
133
134
chat_data = r.json()["pageProps"]["payload"]["chatOfBotDisplayName"]
135
return chat_data
136
127
137
def get_bots(self):
128
138
viewer = self.next_data["props"]["pageProps"]["payload"]["viewer"]
129
139
if not "availableBots" in viewer:
@@ -132,13 +142,7 @@ class Client:
132
142
133
143
bots = {}
134
144
for bot in bot_list:
135
url = f'https://poe.com/_next/data/{self.next_data["buildId"]}/{bot["displayName"].lower()}.json'
136
logger.info("Downloading "+url)
137
138
r = request_with_retries(self.session.get, url)
139
140
chat_data = r.json()[
141
"pageProps"]["payload"]["chatOfBotDisplayName"]
145
chat_data = self.get_bot(bot["displayName"].lower())
142
146
bots[chat_data["defaultBotObject"]["nickname"]] = chat_data
143
147
144
148
return bots
@@ -165,11 +169,8 @@ class Client:
165
169
return f'wss://{self.ws_domain}.tch.{channel["baseHost"]}/up/{channel["boxName"]}/updates'+query
166
170
167
171
def send_query(self, query_name, variables):
168
# print(f'send_query: {query_name} {variables}')
169
170
172
for i in range(20):
171
173
payload = generate_payload(query_name, variables)
172
# print(f'query_payload: {query_name} {variables}')
173
174
r = request_with_retries(
174
175
self.session.post, self.gql_url, json=payload, headers=self.gql_headers)
175
176
data = r.json()
@@ -216,7 +217,8 @@ class Client:
216
217
header={"User-Agent": user_agent},
217
218
on_message=self.on_message,
218
219
on_open=self.on_ws_connect,
219
on_error=self.on_ws_error
220
on_error=self.on_ws_error,
221
on_close=self.on_ws_close
220
222
)
221
223
t = threading.Thread(target=self.ws_run_thread, daemon=True)
222
224
t.start()
@@ -231,27 +233,44 @@ class Client:
231
233
def on_ws_connect(self, ws):
232
234
self.ws_connected = True
233
235
236
def on_ws_close(self, ws, close_status_code):
237
self.ws_connected = False
238
logger.warn(f"Websocket closed with status {close_status_code}")
239
234
240
def on_ws_error(self, ws, error):
235
logger.warn(f"Websocket returned error: {error}")
236
241
self.disconnect_ws()
237
242
self.connect_ws()
238
243
239
244
def on_message(self, ws, msg):
240
data = json.loads(msg)
241
message = json.loads(data["messages"][0])[
242
"payload"]["data"]["messageAdded"]
243
244
copied_dict = self.active_messages.copy()
245
for key, value in copied_dict.items():
246
# add the message to the appropriate queue
247
if value == message["messageId"] and key in self.message_queues:
248
self.message_queues[key].put(message)
245
try:
246
data = json.loads(msg)
247
248
if not "messages" in data:
249
249
return
250
250
251
# indicate that the response id is tied to the human message id
252
elif key != "pending" and value == None and message["state"] != "complete":
253
self.active_messages[key] = message["messageId"]
254
self.message_queues[key].put(message)
251
for message_str in data["messages"]:
252
message_data = json.loads(message_str)
253
if message_data["message_type"] != "subscriptionUpdate":
254
continue
255
message = message_data["payload"]["data"]["messageAdded"]
256
257
copied_dict = self.active_messages.copy()
258
for key, value in copied_dict.items():
259
# add the message to the appropriate queue
260
if value == message["messageId"] and key in self.message_queues:
261
self.message_queues[key].put(message)
262
return
263
264
# indicate that the response id is tied to the human message id
265
elif key != "pending" and value == None and message["state"] != "complete":
266
self.active_messages[key] = message["messageId"]
267
self.message_queues[key].put(message)
268
return
269
270
except Exception:
271
logger.error(traceback.format_exc())
272
self.disconnect_ws()
273
self.connect_ws()
255
274
256
275
def send_message(self, chatbot, message, with_chat_break=False, timeout=20):
257
276
# if there is another active message, wait until it has finished sending
@@ -262,8 +281,11 @@ class Client:
262
281
self.active_messages["pending"] = None
263
282
264
283
logger.info(f"Sending message to {chatbot}: {message}")
265
266
message_data = self.send_query("AddHumanMessageMutation", {
284
# reconnect websocket
285
if not self.ws_connected:
286
self.disconnect_ws()
287
self.connect_ws()
288
message_data = self.send_query("SendMessageMutation", {
267
289
"bot": chatbot,
268
290
"query": message,
269
291
"chatId": self.bots[chatbot]["chatId"],
@@ -272,11 +294,11 @@ class Client:
272
294
})
273
295
del self.active_messages["pending"]
274
296
275
if not message_data["data"]["messageCreateWithStatus"]["messageLimit"]["canSend"]:
297
if not message_data["data"]["messageEdgeCreate"]["message"]:
276
298
raise RuntimeError(f"Daily limit reached for {chatbot}.")
277
299
try:
278
human_message = message_data["data"]["messageCreateWithStatus"]
279
human_message_id = human_message["message"]["messageId"]
300
human_message = message_data["data"]["messageEdgeCreate"]["message"]
301
human_message_id = human_message["node"]["messageId"]
280
302
except TypeError:
281
303
raise RuntimeError(
282
304
f"An unknown error occured. Raw response data: {message_data}")
@@ -313,4 +335,67 @@ class Client:
313
335
del self.active_messages[human_message_id]
314
336
del self.message_queues[human_message_id]
315
337
316
load_queries()
338
def send_chat_break(self, chatbot):
339
logger.info(f"Sending chat break to {chatbot}")
340
result = self.send_query("AddMessageBreakMutation", {
341
"chatId": self.bots[chatbot]["chatId"]
342
})
343
return result["data"]["messageBreakCreate"]["message"]
344
345
def get_message_history(self, chatbot, count=25, cursor=None):
346
logger.info(f"Downloading {count} messages from {chatbot}")
347
348
if cursor == None:
349
chat_data = self.get_bot(self.bot_names[chatbot])
350
if not chat_data["messagesConnection"]["edges"]:
351
return []
352
cursor = chat_data["messagesConnection"]["edges"][-1]["cursor"]
353
354
cursor = str(cursor)
355
if count > 50:
356
messages = self.get_message_history(
357
chatbot, count=50, cursor=cursor)
358
while count > 0:
359
new_cursor = messages[0]["cursor"]
360
new_messages = self.get_message_history(
361
chatbot, min(50, count), cursor=new_cursor)
362
messages = new_messages + messages
363
count -= 50
364
return messages
365
366
result = self.send_query("ChatListPaginationQuery", {
367
"count": count,
368
"cursor": cursor,
369
"id": self.bots[chatbot]["id"]
370
})
371
return result["data"]["node"]["messagesConnection"]["edges"]
372
373
def delete_message(self, message_ids):
374
logger.info(f"Deleting messages: {message_ids}")
375
if not type(message_ids) is list:
376
message_ids = [int(message_ids)]
377
378
result = self.send_query("DeleteMessageMutation", {
379
"messageIds": message_ids
380
})
381
382
def purge_conversation(self, chatbot, count=-1):
383
logger.info(f"Purging messages from {chatbot}")
384
last_messages = self.get_message_history(chatbot, count=50)[::-1]
385
while last_messages:
386
message_ids = []
387
for message in last_messages:
388
if count == 0:
389
break
390
count -= 1
391
message_ids.append(message["node"]["messageId"])
392
393
self.delete_message(message_ids)
394
395
if count == 0:
396
return
397
last_messages = self.get_message_history(chatbot, count=50)[::-1]
398
logger.info(f"No more messages left to delete.")
399
400
401
load_queries()
@@ -1 +1,7 @@
1
1
SmPiNXZI9hBTuf3viz74PA==
2
zw7RoKQfeEehiaelYMRWeA==
3
NEttgJ_rRQdO05Tppx6hFw==
4
3OnmC0r9njYdNWhWszdQJg==
5
8hZKR7MxwUTEHvO45TEViw==
6
Eea6BqK0AmosTKzoI3AAow==
7
pUEbtxobN_QUSpLIR8RGww==
@@ -11,6 +11,12 @@ query ChatListPaginationQuery(
11
11
}
12
12
13
13
fragment BotImage_bot on Bot {
14
displayName
15
...botHelpers_useDeletion_bot
16
...BotImage_useProfileImage_bot
17
}
18
19
fragment BotImage_useProfileImage_bot on Bot {
14
20
image {
15
21
__typename
16
22
... on LocalBotImage {
@@ -20,7 +26,7 @@ fragment BotImage_bot on Bot {
20
26
url
21
27
}
22
28
}
23
displayName
29
...botHelpers_useDeletion_bot
24
30
}
25
31
26
32
fragment ChatMessageDownvotedButton_message on Message {
@@ -33,7 +39,7 @@ fragment ChatMessageDropdownMenu_message on Message {
33
39
messageId
34
40
vote
35
41
text
36
linkifiedText
42
author
37
43
...chatHelpers_isBotMessage
38
44
}
39
45
@@ -54,6 +60,9 @@ fragment ChatMessageInputView_chat on Chat {
54
60
dailyBalance
55
61
shouldShowRemainingMessageCount
56
62
}
63
hasClearContext
64
isDown
65
...botHelpers_useDeletion_bot
57
66
id
58
67
}
59
68
shouldShowDisclaimer
@@ -88,6 +97,10 @@ fragment ChatMessageSuggestedReplies_SuggestedReplyButton_message on Message {
88
97
fragment ChatMessageSuggestedReplies_chat on Chat {
89
98
...ChatWelcomeView_chat
90
99
...ChatMessageSuggestedReplies_SuggestedReplyButton_chat
100
defaultBotObject {
101
hasWelcomeTopics
102
id
103
}
91
104
}
92
105
93
106
fragment ChatMessageSuggestedReplies_message on Message {
@@ -97,10 +110,13 @@ fragment ChatMessageSuggestedReplies_message on Message {
97
110
98
111
fragment ChatMessage_chat on Chat {
99
112
defaultBotObject {
100
...ChatPageDisclaimer_bot
113
hasWelcomeTopics
114
hasSuggestedReplies
115
disclaimerText
101
116
messageLimit {
102
117
...ChatPageRateLimitedBanner_messageLimit
103
118
}
119
...ChatPageDisclaimer_bot
104
120
id
105
121
}
106
122
...ChatMessageSuggestedReplies_chat
@@ -114,6 +130,7 @@ fragment ChatMessage_message on Message {
114
130
author
115
131
linkifiedText
116
132
state
133
contentType
117
134
...ChatMessageSuggestedReplies_message
118
135
...ChatMessageFeedbackButtons_message
119
136
...ChatMessageOverflowButton_message
@@ -122,12 +139,15 @@ fragment ChatMessage_message on Message {
122
139
...chatHelpers_isChatBreak
123
140
...chatHelpers_useTimeoutLevel
124
141
...MarkdownLinkInner_message
142
...IdAnnotation_node
125
143
}
126
144
127
145
fragment ChatMessagesView_chat on Chat {
128
146
...ChatMessage_chat
129
147
...ChatWelcomeView_chat
148
...IdAnnotation_node
130
149
defaultBotObject {
150
hasWelcomeTopics
131
151
messageLimit {
132
152
...ChatPageRateLimitedBanner_messageLimit
133
153
}
@@ -152,23 +172,42 @@ fragment ChatPageDeleteFooter_chat on Chat {
152
172
}
153
173
154
174
fragment ChatPageDisclaimer_bot on Bot {
155
disclaimer
175
disclaimerText
176
}
177
178
fragment ChatPageMainFooter_chat on Chat {
179
defaultBotObject {
180
...ChatPageMainFooter_useAccessMessage_bot
181
id
182
}
183
...ChatMessageInputView_chat
184
...ChatPageShareFooter_chat
185
...ChatPageDeleteFooter_chat
186
}
187
188
fragment ChatPageMainFooter_edges on MessageEdge {
189
...ChatMessageInputView_edges
190
}
191
192
fragment ChatPageMainFooter_useAccessMessage_bot on Bot {
193
...botHelpers_useDeletion_bot
194
...botHelpers_useViewerCanAccessPrivateBot
156
195
}
157
196
158
197
fragment ChatPageMain_chat_1G22uz on Chat {
159
198
id
160
199
chatId
161
...ChatMessageInputView_chat
162
200
...ChatPageShareFooter_chat
163
201
...ChatPageDeleteFooter_chat
164
202
...ChatMessagesView_chat
165
203
...MarkdownLinkInner_chat
166
204
...chatHelpers_useUpdateStaleChat_chat
167
205
...ChatSubscriptionPaywallContextWrapper_chat
206
...ChatPageMainFooter_chat
168
207
messagesConnection(last: $count, before: $cursor) {
169
208
edges {
170
209
...ChatMessagesView_edges
171
...ChatMessageInputView_edges
210
...ChatPageMainFooter_edges
172
211
...MarkdownLinkInner_edges
173
212
node {
174
213
...chatHelpers_useUpdateStaleChat_message
@@ -217,6 +256,11 @@ fragment ChatWelcomeView_chat on Chat {
217
256
}
218
257
}
219
258
259
fragment IdAnnotation_node on Node {
260
__isNode: __typename
261
id
262
}
263
220
264
fragment MarkdownLinkInner_chat on Chat {
221
265
id
222
266
chatId
@@ -263,6 +307,15 @@ fragment SubscriptionPaywallModal_bot on Bot {
263
307
...BotImage_bot
264
308
}
265
309
310
fragment botHelpers_useDeletion_bot on Bot {
311
deletionState
312
}
313
314
fragment botHelpers_useViewerCanAccessPrivateBot on Bot {
315
isPrivateBot
316
viewerIsCreator
317
}
318
266
319
fragment chatHelpers_isBotMessage on Message {
267
320
...chatHelpers_isHumanMessage
268
321
...chatHelpers_isChatBreak
@@ -292,8 +345,8 @@ fragment chatHelpers_useSendMessage_chat on Chat {
292
345
id
293
346
chatId
294
347
defaultBotObject {
295
nickname
296
348
id
349
nickname
297
350
}
298
351
shouldShowDisclaimer
299
352
}
@@ -303,10 +356,19 @@ fragment chatHelpers_useTimeoutLevel on Message {
303
356
state
304
357
text
305
358
messageId
359
chat {
360
chatId
361
defaultBotNickname
362
id
363
}
306
364
}
307
365
308
366
fragment chatHelpers_useUpdateStaleChat_chat on Chat {
309
367
chatId
368
defaultBotObject {
369
contextClearWindowSecs
370
id
371
}
310
372
...chatHelpers_useSendChatBreak_chat
311
373
}
312
374
@@ -0,0 +1,40 @@
1
mutation chatHelpers_sendMessageMutation_Mutation(
2
$chatId: BigInt!
3
$bot: String!
4
$query: String!
5
$source: MessageSource
6
$withChatBreak: Boolean!
7
) {
8
messageEdgeCreate(chatId: $chatId, bot: $bot, query: $query, source: $source, withChatBreak: $withChatBreak) {
9
chatBreak {
10
cursor
11
node {
12
id
13
messageId
14
text
15
author
16
suggestedReplies
17
creationTime
18
state
19
}
20
id
21
}
22
message {
23
cursor
24
node {
25
id
26
messageId
27
text
28
author
29
suggestedReplies
30
creationTime
31
state
32
chat {
33
shouldShowDisclaimer
34
id
35
}
36
}
37
id
38
}
39
}
40
}
@@ -0,0 +1,13 @@
1
import poe
2
from time import sleep
3
4
token = poe.Account.create(proxy = 'xtekky:ogingoi2n3g@geo.iproyal.com:12321',logging = True)
5
print('token', token)
6
7
sleep(2)
8
9
for response in poe.StreamingCompletion.create(model = 'gpt-4',
10
prompt = 'hello world',
11
token = token):
12
13
print(response.completion.choices[0].text, end="", flush=True)