g4f 7.0.0__py3-none-any.whl → 7.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- g4f/Provider/DeepInfra.py +0 -2
- g4f/Provider/PollinationsAI.py +1 -1
- g4f/Provider/Yupp.py +305 -152
- g4f/Provider/needs_auth/Antigravity.py +1505 -0
- g4f/Provider/needs_auth/GeminiCLI.py +573 -2
- g4f/Provider/needs_auth/OpenaiChat.py +2 -0
- g4f/Provider/needs_auth/__init__.py +1 -0
- g4f/Provider/qwen/QwenCode.py +162 -2
- g4f/Provider/yupp/constants.py +33 -0
- g4f/Provider/yupp/token_extractor.py +384 -0
- g4f/cli/client.py +3 -2
- g4f/gui/server/api.py +0 -2
- g4f/models.py +1 -1
- {g4f-7.0.0.dist-info → g4f-7.0.1.dist-info}/METADATA +1 -1
- {g4f-7.0.0.dist-info → g4f-7.0.1.dist-info}/RECORD +19 -16
- g4f-7.0.1.dist-info/entry_points.txt +6 -0
- g4f-7.0.0.dist-info/entry_points.txt +0 -3
- {g4f-7.0.0.dist-info → g4f-7.0.1.dist-info}/WHEEL +0 -0
- {g4f-7.0.0.dist-info → g4f-7.0.1.dist-info}/licenses/LICENSE +0 -0
- {g4f-7.0.0.dist-info → g4f-7.0.1.dist-info}/top_level.txt +0 -0
g4f/Provider/Yupp.py
CHANGED
|
@@ -11,16 +11,24 @@ from typing import Optional, Dict, Any, List
|
|
|
11
11
|
try:
|
|
12
12
|
import cloudscraper
|
|
13
13
|
from cloudscraper import CloudScraper
|
|
14
|
+
|
|
14
15
|
has_cloudscraper = True
|
|
15
16
|
except ImportError:
|
|
16
17
|
from typing import Type as CloudScraper
|
|
18
|
+
|
|
17
19
|
has_cloudscraper = False
|
|
18
20
|
|
|
19
21
|
from .helper import get_last_user_message
|
|
20
22
|
from .yupp.models import YuppModelManager
|
|
23
|
+
from .yupp.token_extractor import get_token_extractor
|
|
21
24
|
from ..cookies import get_cookies
|
|
22
25
|
from ..debug import log
|
|
23
|
-
from ..errors import
|
|
26
|
+
from ..errors import (
|
|
27
|
+
RateLimitError,
|
|
28
|
+
ProviderException,
|
|
29
|
+
MissingAuthError,
|
|
30
|
+
MissingRequirementsError,
|
|
31
|
+
)
|
|
24
32
|
from ..image import is_accepted_format, to_bytes
|
|
25
33
|
from ..providers.base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
|
26
34
|
from ..providers.response import (
|
|
@@ -49,25 +57,27 @@ MAX_CACHE_SIZE = 1000
|
|
|
49
57
|
def create_scraper():
|
|
50
58
|
scraper = cloudscraper.create_scraper(
|
|
51
59
|
browser={
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
"browser": "chrome",
|
|
61
|
+
"platform": "windows",
|
|
62
|
+
"desktop": True,
|
|
63
|
+
"mobile": False,
|
|
56
64
|
},
|
|
57
65
|
delay=10,
|
|
58
|
-
interpreter=
|
|
66
|
+
interpreter="nodejs",
|
|
67
|
+
)
|
|
68
|
+
scraper.headers.update(
|
|
69
|
+
{
|
|
70
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0",
|
|
71
|
+
"Accept": "text/x-component, */*",
|
|
72
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
73
|
+
"Sec-Fetch-Dest": "empty",
|
|
74
|
+
"Sec-Fetch-Mode": "cors",
|
|
75
|
+
"Sec-Fetch-Site": "same-origin",
|
|
76
|
+
"Sec-Ch-Ua": '"Microsoft Edge";v="137", "Chromium";v="137", "Not/A)Brand";v="24"',
|
|
77
|
+
"Sec-Ch-Ua-Mobile": "?0",
|
|
78
|
+
"Sec-Ch-Ua-Platform": '"Windows"',
|
|
79
|
+
}
|
|
59
80
|
)
|
|
60
|
-
scraper.headers.update({
|
|
61
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0",
|
|
62
|
-
"Accept": "text/x-component, */*",
|
|
63
|
-
"Accept-Language": "en-US,en;q=0.9",
|
|
64
|
-
"Sec-Fetch-Dest": "empty",
|
|
65
|
-
"Sec-Fetch-Mode": "cors",
|
|
66
|
-
"Sec-Fetch-Site": "same-origin",
|
|
67
|
-
"Sec-Ch-Ua": '"Microsoft Edge";v="137", "Chromium";v="137", "Not/A)Brand";v="24"',
|
|
68
|
-
"Sec-Ch-Ua-Mobile": "?0",
|
|
69
|
-
"Sec-Ch-Ua-Platform": '"Windows"'
|
|
70
|
-
})
|
|
71
81
|
return scraper
|
|
72
82
|
|
|
73
83
|
|
|
@@ -77,14 +87,9 @@ def load_yupp_accounts(tokens_str: str):
|
|
|
77
87
|
return
|
|
78
88
|
if not tokens_str:
|
|
79
89
|
return
|
|
80
|
-
tokens = [token.strip() for token in tokens_str.split(
|
|
90
|
+
tokens = [token.strip() for token in tokens_str.split(",") if token.strip()]
|
|
81
91
|
YUPP_ACCOUNTS = [
|
|
82
|
-
{
|
|
83
|
-
"token": token,
|
|
84
|
-
"is_valid": True,
|
|
85
|
-
"error_count": 0,
|
|
86
|
-
"last_used": 0.0
|
|
87
|
-
}
|
|
92
|
+
{"token": token, "is_valid": True, "error_count": 0, "last_used": 0.0}
|
|
88
93
|
for token in tokens
|
|
89
94
|
]
|
|
90
95
|
_accounts_loaded = True
|
|
@@ -122,12 +127,14 @@ async def get_best_yupp_account() -> Optional[Dict[str, Any]]:
|
|
|
122
127
|
return account
|
|
123
128
|
|
|
124
129
|
|
|
125
|
-
def sync_claim_yupp_reward(
|
|
130
|
+
def sync_claim_yupp_reward(
|
|
131
|
+
scraper: CloudScraper, account: Dict[str, Any], eval_id: str
|
|
132
|
+
):
|
|
126
133
|
try:
|
|
127
134
|
log_debug(f"Claiming reward {eval_id}...")
|
|
128
135
|
url = "https://yupp.ai/api/trpc/reward.claim?batch=1"
|
|
129
136
|
payload = {"0": {"json": {"evalId": eval_id}}}
|
|
130
|
-
scraper.cookies.set("__Secure-yupp.session-token", account[
|
|
137
|
+
scraper.cookies.set("__Secure-yupp.session-token", account["token"])
|
|
131
138
|
response = scraper.post(url, json=payload)
|
|
132
139
|
response.raise_for_status()
|
|
133
140
|
data = response.json()
|
|
@@ -139,9 +146,13 @@ def sync_claim_yupp_reward(scraper: CloudScraper, account: Dict[str, Any], eval_
|
|
|
139
146
|
return None
|
|
140
147
|
|
|
141
148
|
|
|
142
|
-
async def claim_yupp_reward(
|
|
149
|
+
async def claim_yupp_reward(
|
|
150
|
+
scraper: CloudScraper, account: Dict[str, Any], eval_id: str
|
|
151
|
+
):
|
|
143
152
|
loop = asyncio.get_event_loop()
|
|
144
|
-
return await loop.run_in_executor(
|
|
153
|
+
return await loop.run_in_executor(
|
|
154
|
+
_executor, sync_claim_yupp_reward, scraper, account, eval_id
|
|
155
|
+
)
|
|
145
156
|
|
|
146
157
|
|
|
147
158
|
def sync_record_model_feedback(
|
|
@@ -149,7 +160,7 @@ def sync_record_model_feedback(
|
|
|
149
160
|
account: Dict[str, Any],
|
|
150
161
|
turn_id: str,
|
|
151
162
|
left_message_id: str,
|
|
152
|
-
right_message_id: str
|
|
163
|
+
right_message_id: str,
|
|
153
164
|
) -> Optional[str]:
|
|
154
165
|
try:
|
|
155
166
|
log_debug(f"Recording model feedback for turn {turn_id}...")
|
|
@@ -163,20 +174,16 @@ def sync_record_model_feedback(
|
|
|
163
174
|
{
|
|
164
175
|
"messageId": right_message_id,
|
|
165
176
|
"rating": "GOOD",
|
|
166
|
-
"reasons": ["Fast"]
|
|
177
|
+
"reasons": ["Fast"],
|
|
167
178
|
},
|
|
168
|
-
{
|
|
169
|
-
"messageId": left_message_id,
|
|
170
|
-
"rating": "BAD",
|
|
171
|
-
"reasons": []
|
|
172
|
-
}
|
|
179
|
+
{"messageId": left_message_id, "rating": "BAD", "reasons": []},
|
|
173
180
|
],
|
|
174
181
|
"comment": "",
|
|
175
|
-
"requireReveal": False
|
|
182
|
+
"requireReveal": False,
|
|
176
183
|
}
|
|
177
184
|
}
|
|
178
185
|
}
|
|
179
|
-
scraper.cookies.set("__Secure-yupp.session-token", account[
|
|
186
|
+
scraper.cookies.set("__Secure-yupp.session-token", account["token"])
|
|
180
187
|
response = scraper.post(url, json=payload)
|
|
181
188
|
response.raise_for_status()
|
|
182
189
|
data = response.json()
|
|
@@ -200,25 +207,34 @@ async def record_model_feedback(
|
|
|
200
207
|
account: Dict[str, Any],
|
|
201
208
|
turn_id: str,
|
|
202
209
|
left_message_id: str,
|
|
203
|
-
right_message_id: str
|
|
210
|
+
right_message_id: str,
|
|
204
211
|
) -> Optional[str]:
|
|
205
212
|
loop = asyncio.get_event_loop()
|
|
206
213
|
return await loop.run_in_executor(
|
|
207
|
-
_executor,
|
|
214
|
+
_executor,
|
|
215
|
+
sync_record_model_feedback,
|
|
216
|
+
scraper,
|
|
217
|
+
account,
|
|
218
|
+
turn_id,
|
|
219
|
+
left_message_id,
|
|
220
|
+
right_message_id,
|
|
208
221
|
)
|
|
209
222
|
|
|
210
223
|
|
|
211
|
-
def sync_delete_chat(
|
|
224
|
+
def sync_delete_chat(
|
|
225
|
+
scraper: CloudScraper, account: Dict[str, Any], chat_id: str
|
|
226
|
+
) -> bool:
|
|
212
227
|
try:
|
|
213
228
|
log_debug(f"Deleting chat {chat_id}...")
|
|
214
229
|
url = "https://yupp.ai/api/trpc/chat.deleteChat?batch=1"
|
|
215
230
|
payload = {"0": {"json": {"chatId": chat_id}}}
|
|
216
|
-
scraper.cookies.set("__Secure-yupp.session-token", account[
|
|
231
|
+
scraper.cookies.set("__Secure-yupp.session-token", account["token"])
|
|
217
232
|
response = scraper.post(url, json=payload)
|
|
218
233
|
response.raise_for_status()
|
|
219
234
|
data = response.json()
|
|
220
235
|
if (
|
|
221
|
-
isinstance(data, list)
|
|
236
|
+
isinstance(data, list)
|
|
237
|
+
and len(data) > 0
|
|
222
238
|
and data[0].get("result", {}).get("data", {}).get("json") is None
|
|
223
239
|
):
|
|
224
240
|
log_debug(f"Chat {chat_id} deleted successfully")
|
|
@@ -230,29 +246,29 @@ def sync_delete_chat(scraper: CloudScraper, account: Dict[str, Any], chat_id: st
|
|
|
230
246
|
return False
|
|
231
247
|
|
|
232
248
|
|
|
233
|
-
async def delete_chat(
|
|
249
|
+
async def delete_chat(
|
|
250
|
+
scraper: CloudScraper, account: Dict[str, Any], chat_id: str
|
|
251
|
+
) -> bool:
|
|
234
252
|
loop = asyncio.get_event_loop()
|
|
235
|
-
return await loop.run_in_executor(
|
|
253
|
+
return await loop.run_in_executor(
|
|
254
|
+
_executor, sync_delete_chat, scraper, account, chat_id
|
|
255
|
+
)
|
|
236
256
|
|
|
237
257
|
|
|
238
|
-
def sync_make_chat_private(
|
|
258
|
+
def sync_make_chat_private(
|
|
259
|
+
scraper: CloudScraper, account: Dict[str, Any], chat_id: str
|
|
260
|
+
) -> bool:
|
|
239
261
|
try:
|
|
240
262
|
log_debug(f"Setting chat {chat_id} to PRIVATE...")
|
|
241
263
|
url = "https://yupp.ai/api/trpc/chat.updateSharingSettings?batch=1"
|
|
242
|
-
payload = {
|
|
243
|
-
|
|
244
|
-
"json": {
|
|
245
|
-
"chatId": chat_id,
|
|
246
|
-
"status": "PRIVATE"
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
scraper.cookies.set("__Secure-yupp.session-token", account['token'])
|
|
264
|
+
payload = {"0": {"json": {"chatId": chat_id, "status": "PRIVATE"}}}
|
|
265
|
+
scraper.cookies.set("__Secure-yupp.session-token", account["token"])
|
|
251
266
|
response = scraper.post(url, json=payload)
|
|
252
267
|
response.raise_for_status()
|
|
253
268
|
data = response.json()
|
|
254
269
|
if (
|
|
255
|
-
isinstance(data, list)
|
|
270
|
+
isinstance(data, list)
|
|
271
|
+
and len(data) > 0
|
|
256
272
|
and "json" in data[0].get("result", {}).get("data", {})
|
|
257
273
|
):
|
|
258
274
|
log_debug(f"Chat {chat_id} is now PRIVATE")
|
|
@@ -264,9 +280,13 @@ def sync_make_chat_private(scraper: CloudScraper, account: Dict[str, Any], chat_
|
|
|
264
280
|
return False
|
|
265
281
|
|
|
266
282
|
|
|
267
|
-
async def make_chat_private(
|
|
283
|
+
async def make_chat_private(
|
|
284
|
+
scraper: CloudScraper, account: Dict[str, Any], chat_id: str
|
|
285
|
+
) -> bool:
|
|
268
286
|
loop = asyncio.get_event_loop()
|
|
269
|
-
return await loop.run_in_executor(
|
|
287
|
+
return await loop.run_in_executor(
|
|
288
|
+
_executor, sync_make_chat_private, scraper, account, chat_id
|
|
289
|
+
)
|
|
270
290
|
|
|
271
291
|
|
|
272
292
|
def log_debug(message: str):
|
|
@@ -285,13 +305,17 @@ def format_messages_for_yupp(messages: Messages) -> str:
|
|
|
285
305
|
|
|
286
306
|
formatted = []
|
|
287
307
|
|
|
288
|
-
system_messages = [
|
|
308
|
+
system_messages = [
|
|
309
|
+
msg for msg in messages if msg.get("role") in ["developer", "system"]
|
|
310
|
+
]
|
|
289
311
|
if system_messages:
|
|
290
312
|
for sys_msg in system_messages:
|
|
291
313
|
content = sys_msg.get("content", "")
|
|
292
314
|
formatted.append(content)
|
|
293
315
|
|
|
294
|
-
user_assistant_msgs = [
|
|
316
|
+
user_assistant_msgs = [
|
|
317
|
+
msg for msg in messages if msg.get("role") in ["user", "assistant"]
|
|
318
|
+
]
|
|
295
319
|
for msg in user_assistant_msgs:
|
|
296
320
|
role = "Human" if msg.get("role") == "user" else "Assistant"
|
|
297
321
|
content = msg.get("content", "")
|
|
@@ -312,7 +336,9 @@ def format_messages_for_yupp(messages: Messages) -> str:
|
|
|
312
336
|
def evict_cache_if_needed():
|
|
313
337
|
global ImagesCache
|
|
314
338
|
if len(ImagesCache) > MAX_CACHE_SIZE:
|
|
315
|
-
keys_to_remove = list(ImagesCache.keys())[
|
|
339
|
+
keys_to_remove = list(ImagesCache.keys())[
|
|
340
|
+
: len(ImagesCache) - MAX_CACHE_SIZE + 100
|
|
341
|
+
]
|
|
316
342
|
for key in keys_to_remove:
|
|
317
343
|
del ImagesCache[key]
|
|
318
344
|
|
|
@@ -331,23 +357,37 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
331
357
|
if not api_key:
|
|
332
358
|
api_key = AuthManager.load_api_key(cls)
|
|
333
359
|
if not api_key:
|
|
334
|
-
api_key = get_cookies("yupp.ai", False).get(
|
|
360
|
+
api_key = get_cookies("yupp.ai", False).get(
|
|
361
|
+
"__Secure-yupp.session-token"
|
|
362
|
+
)
|
|
335
363
|
if not api_key:
|
|
336
|
-
raise MissingAuthError(
|
|
364
|
+
raise MissingAuthError(
|
|
365
|
+
"No Yupp accounts configured. Set YUPP_API_KEY environment variable."
|
|
366
|
+
)
|
|
337
367
|
manager = YuppModelManager(api_key=api_key, session=create_scraper())
|
|
338
368
|
models = manager.client.fetch_models()
|
|
339
369
|
if models:
|
|
340
|
-
cls.models_tags = {
|
|
370
|
+
cls.models_tags = {
|
|
371
|
+
model.get("name"): manager.processor.generate_tags(model)
|
|
372
|
+
for model in models
|
|
373
|
+
}
|
|
341
374
|
cls.models = [model.get("name") for model in models]
|
|
342
|
-
cls.image_models = [
|
|
375
|
+
cls.image_models = [
|
|
376
|
+
model.get("name")
|
|
377
|
+
for model in models
|
|
378
|
+
if model.get("isImageGeneration")
|
|
379
|
+
]
|
|
343
380
|
cls.vision_models = [
|
|
344
|
-
model.get("name")
|
|
381
|
+
model.get("name")
|
|
382
|
+
for model in models
|
|
345
383
|
if "image/*" in model.get("supportedAttachmentMimeTypes", [])
|
|
346
384
|
]
|
|
347
385
|
return cls.models
|
|
348
386
|
|
|
349
387
|
@classmethod
|
|
350
|
-
def sync_prepare_files(
|
|
388
|
+
def sync_prepare_files(
|
|
389
|
+
cls, media, scraper: CloudScraper, account: Dict[str, Any]
|
|
390
|
+
) -> list:
|
|
351
391
|
files = []
|
|
352
392
|
if not media:
|
|
353
393
|
return files
|
|
@@ -362,13 +402,19 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
362
402
|
files.append(cached_file)
|
|
363
403
|
continue
|
|
364
404
|
|
|
365
|
-
scraper.cookies.set("__Secure-yupp.session-token", account[
|
|
405
|
+
scraper.cookies.set("__Secure-yupp.session-token", account["token"])
|
|
366
406
|
presigned_resp = scraper.post(
|
|
367
407
|
"https://yupp.ai/api/trpc/chat.createPresignedURLForUpload?batch=1",
|
|
368
408
|
json={
|
|
369
|
-
"0": {
|
|
409
|
+
"0": {
|
|
410
|
+
"json": {
|
|
411
|
+
"fileName": name,
|
|
412
|
+
"fileSize": len(data),
|
|
413
|
+
"contentType": is_accepted_format(data),
|
|
414
|
+
}
|
|
415
|
+
}
|
|
370
416
|
},
|
|
371
|
-
headers={"Content-Type": "application/json"}
|
|
417
|
+
headers={"Content-Type": "application/json"},
|
|
372
418
|
)
|
|
373
419
|
presigned_resp.raise_for_status()
|
|
374
420
|
upload_info = presigned_resp.json()[0]["result"]["data"]["json"]
|
|
@@ -379,8 +425,8 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
379
425
|
data=data,
|
|
380
426
|
headers={
|
|
381
427
|
"Content-Type": is_accepted_format(data),
|
|
382
|
-
"Content-Length": str(len(data))
|
|
383
|
-
}
|
|
428
|
+
"Content-Length": str(len(data)),
|
|
429
|
+
},
|
|
384
430
|
)
|
|
385
431
|
|
|
386
432
|
attachment_resp = scraper.post(
|
|
@@ -390,11 +436,11 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
390
436
|
"json": {
|
|
391
437
|
"fileName": name,
|
|
392
438
|
"contentType": is_accepted_format(data),
|
|
393
|
-
"fileId": upload_info["fileId"]
|
|
439
|
+
"fileId": upload_info["fileId"],
|
|
394
440
|
}
|
|
395
441
|
}
|
|
396
442
|
},
|
|
397
|
-
cookies={"__Secure-yupp.session-token": account["token"]}
|
|
443
|
+
cookies={"__Secure-yupp.session-token": account["token"]},
|
|
398
444
|
)
|
|
399
445
|
attachment_resp.raise_for_status()
|
|
400
446
|
attachment = attachment_resp.json()[0]["result"]["data"]["json"]
|
|
@@ -402,7 +448,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
402
448
|
"fileName": attachment["file_name"],
|
|
403
449
|
"contentType": attachment["content_type"],
|
|
404
450
|
"attachmentId": attachment["attachment_id"],
|
|
405
|
-
"chatMessageId": ""
|
|
451
|
+
"chatMessageId": "",
|
|
406
452
|
}
|
|
407
453
|
evict_cache_if_needed()
|
|
408
454
|
ImagesCache[image_hash] = file_info
|
|
@@ -410,9 +456,13 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
410
456
|
return files
|
|
411
457
|
|
|
412
458
|
@classmethod
|
|
413
|
-
async def prepare_files(
|
|
459
|
+
async def prepare_files(
|
|
460
|
+
cls, media, scraper: CloudScraper, account: Dict[str, Any]
|
|
461
|
+
) -> list:
|
|
414
462
|
loop = asyncio.get_event_loop()
|
|
415
|
-
return await loop.run_in_executor(
|
|
463
|
+
return await loop.run_in_executor(
|
|
464
|
+
_executor, cls.sync_prepare_files, media, scraper, account
|
|
465
|
+
)
|
|
416
466
|
|
|
417
467
|
@classmethod
|
|
418
468
|
def sync_get_signed_image(cls, scraper: CloudScraper, image_id: str) -> str:
|
|
@@ -421,10 +471,8 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
421
471
|
url,
|
|
422
472
|
params={
|
|
423
473
|
"batch": "1",
|
|
424
|
-
"input": json.dumps(
|
|
425
|
-
|
|
426
|
-
)
|
|
427
|
-
}
|
|
474
|
+
"input": json.dumps({"0": {"json": {"imageId": image_id}}}),
|
|
475
|
+
},
|
|
428
476
|
)
|
|
429
477
|
resp.raise_for_status()
|
|
430
478
|
data = resp.json()[0]["result"]["data"]["json"]
|
|
@@ -433,11 +481,17 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
433
481
|
@classmethod
|
|
434
482
|
async def get_signed_image(cls, scraper: CloudScraper, image_id: str) -> str:
|
|
435
483
|
loop = asyncio.get_event_loop()
|
|
436
|
-
return await loop.run_in_executor(
|
|
484
|
+
return await loop.run_in_executor(
|
|
485
|
+
_executor, cls.sync_get_signed_image, scraper, image_id
|
|
486
|
+
)
|
|
437
487
|
|
|
438
488
|
@classmethod
|
|
439
|
-
def sync_stream_request(
|
|
440
|
-
|
|
489
|
+
def sync_stream_request(
|
|
490
|
+
cls, scraper: CloudScraper, url: str, payload: list, headers: dict, timeout: int
|
|
491
|
+
):
|
|
492
|
+
response = scraper.post(
|
|
493
|
+
url, json=payload, headers=headers, stream=True, timeout=timeout
|
|
494
|
+
)
|
|
441
495
|
response.raise_for_status()
|
|
442
496
|
return response
|
|
443
497
|
|
|
@@ -462,7 +516,9 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
462
516
|
load_yupp_accounts(api_key)
|
|
463
517
|
log_debug(f"Yupp provider initialized with {len(YUPP_ACCOUNTS)} accounts")
|
|
464
518
|
else:
|
|
465
|
-
raise MissingAuthError(
|
|
519
|
+
raise MissingAuthError(
|
|
520
|
+
"No Yupp accounts configured. Set YUPP_API_KEY environment variable."
|
|
521
|
+
)
|
|
466
522
|
|
|
467
523
|
conversation = kwargs.get("conversation")
|
|
468
524
|
url_uuid = conversation.url_uuid if conversation else None
|
|
@@ -488,17 +544,21 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
488
544
|
try:
|
|
489
545
|
scraper = create_scraper()
|
|
490
546
|
if proxy:
|
|
491
|
-
scraper.proxies = {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
547
|
+
scraper.proxies = {"http": proxy, "https": proxy}
|
|
548
|
+
|
|
549
|
+
# Initialize token extractor for automatic token swapping
|
|
550
|
+
token_extractor = get_token_extractor(
|
|
551
|
+
jwt_token=account["token"], scraper=scraper
|
|
552
|
+
)
|
|
495
553
|
|
|
496
554
|
turn_id = str(uuid.uuid4())
|
|
497
555
|
|
|
498
556
|
media = kwargs.get("media")
|
|
499
557
|
if media:
|
|
500
558
|
media_ = list(merge_media(media, messages))
|
|
501
|
-
files = await cls.prepare_files(
|
|
559
|
+
files = await cls.prepare_files(
|
|
560
|
+
media_, scraper=scraper, account=account
|
|
561
|
+
)
|
|
502
562
|
else:
|
|
503
563
|
files = []
|
|
504
564
|
|
|
@@ -514,14 +574,19 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
514
574
|
"$undefined",
|
|
515
575
|
files,
|
|
516
576
|
"$undefined",
|
|
517
|
-
[{"modelName": model, "promptModifierId": "$undefined"}]
|
|
577
|
+
[{"modelName": model, "promptModifierId": "$undefined"}]
|
|
578
|
+
if model
|
|
579
|
+
else "none",
|
|
518
580
|
mode,
|
|
519
581
|
True,
|
|
520
582
|
"$undefined",
|
|
521
583
|
]
|
|
522
584
|
url = f"https://yupp.ai/chat/{url_uuid}?stream=true"
|
|
523
585
|
yield JsonConversation(url_uuid=url_uuid)
|
|
524
|
-
next_action = kwargs.get(
|
|
586
|
+
next_action = kwargs.get(
|
|
587
|
+
"next_action",
|
|
588
|
+
await token_extractor.get_token("new_conversation"),
|
|
589
|
+
)
|
|
525
590
|
else:
|
|
526
591
|
payload = [
|
|
527
592
|
url_uuid,
|
|
@@ -529,12 +594,17 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
529
594
|
prompt,
|
|
530
595
|
False,
|
|
531
596
|
[],
|
|
532
|
-
[{"modelName": model, "promptModifierId": "$undefined"}]
|
|
597
|
+
[{"modelName": model, "promptModifierId": "$undefined"}]
|
|
598
|
+
if model
|
|
599
|
+
else [],
|
|
533
600
|
mode,
|
|
534
|
-
files
|
|
601
|
+
files,
|
|
535
602
|
]
|
|
536
603
|
url = f"https://yupp.ai/chat/{url_uuid}?stream=true"
|
|
537
|
-
next_action = kwargs.get(
|
|
604
|
+
next_action = kwargs.get(
|
|
605
|
+
"next_action",
|
|
606
|
+
await token_extractor.get_token("existing_conversation"),
|
|
607
|
+
)
|
|
538
608
|
|
|
539
609
|
headers = {
|
|
540
610
|
"accept": "text/x-component",
|
|
@@ -544,7 +614,9 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
544
614
|
}
|
|
545
615
|
|
|
546
616
|
log_debug(f"Sending request to: {url}")
|
|
547
|
-
log_debug(
|
|
617
|
+
log_debug(
|
|
618
|
+
f"Payload structure: {type(payload)}, length: {len(str(payload))}"
|
|
619
|
+
)
|
|
548
620
|
|
|
549
621
|
_timeout = kwargs.get("timeout")
|
|
550
622
|
if isinstance(_timeout, (int, float)):
|
|
@@ -560,11 +632,13 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
560
632
|
url,
|
|
561
633
|
payload,
|
|
562
634
|
headers,
|
|
563
|
-
timeout
|
|
635
|
+
timeout,
|
|
564
636
|
)
|
|
565
637
|
|
|
566
638
|
try:
|
|
567
|
-
async for chunk in cls._process_stream_response(
|
|
639
|
+
async for chunk in cls._process_stream_response(
|
|
640
|
+
response, account, scraper, prompt, model
|
|
641
|
+
):
|
|
568
642
|
yield chunk
|
|
569
643
|
finally:
|
|
570
644
|
response.close()
|
|
@@ -573,23 +647,66 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
573
647
|
return
|
|
574
648
|
|
|
575
649
|
except RateLimitError:
|
|
576
|
-
log_debug(
|
|
650
|
+
log_debug(
|
|
651
|
+
f"Account ...{account['token'][-4:]} hit rate limit, rotating"
|
|
652
|
+
)
|
|
577
653
|
async with account_rotation_lock:
|
|
578
654
|
account["error_count"] += 1
|
|
579
655
|
continue
|
|
580
656
|
|
|
581
657
|
except ProviderException as e:
|
|
582
658
|
log_debug(f"Account ...{account['token'][-4:]} failed: {str(e)}")
|
|
659
|
+
error_msg = str(e).lower()
|
|
660
|
+
|
|
661
|
+
# Check if this is a token-related error
|
|
662
|
+
if any(
|
|
663
|
+
x in error_msg
|
|
664
|
+
for x in [
|
|
665
|
+
"auth",
|
|
666
|
+
"401",
|
|
667
|
+
"403",
|
|
668
|
+
"404",
|
|
669
|
+
"invalid action",
|
|
670
|
+
"action",
|
|
671
|
+
"next-action",
|
|
672
|
+
]
|
|
673
|
+
):
|
|
674
|
+
# Mark token as failed to trigger extraction
|
|
675
|
+
token_type = (
|
|
676
|
+
"new_conversation"
|
|
677
|
+
if is_new_conversation
|
|
678
|
+
else "existing_conversation"
|
|
679
|
+
)
|
|
680
|
+
await token_extractor.mark_token_failed(token_type, next_action)
|
|
681
|
+
log_debug(
|
|
682
|
+
f"Token failure detected, marked for extraction: {token_type}"
|
|
683
|
+
)
|
|
684
|
+
|
|
583
685
|
async with account_rotation_lock:
|
|
584
|
-
if "auth" in
|
|
686
|
+
if "auth" in error_msg or "401" in error_msg or "403" in error_msg:
|
|
585
687
|
account["is_valid"] = False
|
|
586
688
|
else:
|
|
587
689
|
account["error_count"] += 1
|
|
588
690
|
continue
|
|
589
691
|
|
|
590
692
|
except Exception as e:
|
|
591
|
-
log_debug(
|
|
693
|
+
log_debug(
|
|
694
|
+
f"Unexpected error with account ...{account['token'][-4:]}: {str(e)}"
|
|
695
|
+
)
|
|
592
696
|
error_str = str(e).lower()
|
|
697
|
+
|
|
698
|
+
# Check for token-related errors in generic exceptions too
|
|
699
|
+
if any(x in error_str for x in ["404", "401", "403", "invalid action"]):
|
|
700
|
+
token_type = (
|
|
701
|
+
"new_conversation"
|
|
702
|
+
if is_new_conversation
|
|
703
|
+
else "existing_conversation"
|
|
704
|
+
)
|
|
705
|
+
await token_extractor.mark_token_failed(token_type, next_action)
|
|
706
|
+
log_debug(
|
|
707
|
+
f"Token failure detected in exception handler: {token_type}"
|
|
708
|
+
)
|
|
709
|
+
|
|
593
710
|
if "500" in error_str or "internal server error" in error_str:
|
|
594
711
|
async with account_rotation_lock:
|
|
595
712
|
account["error_count"] += 1
|
|
@@ -607,7 +724,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
607
724
|
account: Dict[str, Any],
|
|
608
725
|
scraper: CloudScraper,
|
|
609
726
|
prompt: str,
|
|
610
|
-
model_id: str
|
|
727
|
+
model_id: str,
|
|
611
728
|
) -> AsyncResult:
|
|
612
729
|
line_pattern = re.compile(b"^([0-9a-fA-F]+):(.*)")
|
|
613
730
|
target_stream_id = None
|
|
@@ -617,13 +734,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
617
734
|
normal_content = ""
|
|
618
735
|
quick_content = ""
|
|
619
736
|
variant_text = ""
|
|
620
|
-
stream = {
|
|
621
|
-
"target": [],
|
|
622
|
-
"variant": [],
|
|
623
|
-
"quick": [],
|
|
624
|
-
"thinking": [],
|
|
625
|
-
"extra": []
|
|
626
|
-
}
|
|
737
|
+
stream = {"target": [], "variant": [], "quick": [], "thinking": [], "extra": []}
|
|
627
738
|
select_stream = [None, None]
|
|
628
739
|
capturing_ref_id: Optional[str] = None
|
|
629
740
|
capturing_lines: List[bytes] = []
|
|
@@ -631,7 +742,11 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
631
742
|
image_blocks: Dict[str, str] = {}
|
|
632
743
|
|
|
633
744
|
def extract_ref_id(ref):
|
|
634
|
-
return
|
|
745
|
+
return (
|
|
746
|
+
ref[2:]
|
|
747
|
+
if ref and isinstance(ref, str) and ref.startswith("$@")
|
|
748
|
+
else None
|
|
749
|
+
)
|
|
635
750
|
|
|
636
751
|
def extract_ref_name(ref: str) -> Optional[str]:
|
|
637
752
|
if not isinstance(ref, str):
|
|
@@ -647,14 +762,18 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
647
762
|
return False
|
|
648
763
|
return True
|
|
649
764
|
|
|
650
|
-
async def process_content_chunk(
|
|
765
|
+
async def process_content_chunk(
|
|
766
|
+
content: str, chunk_id: str, line_count: int, *, for_target: bool = False
|
|
767
|
+
):
|
|
651
768
|
nonlocal normal_content
|
|
652
769
|
|
|
653
770
|
if not is_valid_content(content):
|
|
654
771
|
return
|
|
655
772
|
|
|
656
773
|
if '<yapp class="image-gen">' in content:
|
|
657
|
-
img_block =
|
|
774
|
+
img_block = (
|
|
775
|
+
content.split('<yapp class="image-gen">').pop().split("</yapp>")[0]
|
|
776
|
+
)
|
|
658
777
|
image_id = json.loads(img_block).get("image_id")
|
|
659
778
|
signed_url = await cls.get_signed_image(scraper, image_id)
|
|
660
779
|
img = ImageResponse(signed_url, prompt)
|
|
@@ -674,7 +793,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
674
793
|
think_start = text.find("<think>")
|
|
675
794
|
think_end = text.find("</think>")
|
|
676
795
|
if think_start != -1 and think_end != -1 and think_end > think_start:
|
|
677
|
-
inner = text[think_start + len("<think>"):think_end].strip()
|
|
796
|
+
inner = text[think_start + len("<think>") : think_end].strip()
|
|
678
797
|
if inner:
|
|
679
798
|
think_blocks[ref_id] = inner
|
|
680
799
|
|
|
@@ -682,7 +801,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
682
801
|
if yapp_start != -1:
|
|
683
802
|
yapp_end = text.find("</yapp>", yapp_start)
|
|
684
803
|
if yapp_end != -1:
|
|
685
|
-
yapp_block = text[yapp_start:yapp_end + len("</yapp>")]
|
|
804
|
+
yapp_block = text[yapp_start : yapp_end + len("</yapp>")]
|
|
686
805
|
image_blocks[ref_id] = yapp_block
|
|
687
806
|
|
|
688
807
|
try:
|
|
@@ -712,7 +831,9 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
712
831
|
|
|
713
832
|
while True:
|
|
714
833
|
try:
|
|
715
|
-
line = await loop.run_in_executor(
|
|
834
|
+
line = await loop.run_in_executor(
|
|
835
|
+
_executor, lambda: next(lines_iterator, None)
|
|
836
|
+
)
|
|
716
837
|
if line is None:
|
|
717
838
|
break
|
|
718
839
|
except StopIteration:
|
|
@@ -728,7 +849,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
728
849
|
|
|
729
850
|
if b"</yapp>" in line:
|
|
730
851
|
idx = line.find(b"</yapp>")
|
|
731
|
-
suffix = line[idx + len(b"</yapp>"):]
|
|
852
|
+
suffix = line[idx + len(b"</yapp>") :]
|
|
732
853
|
finalize_capture_block(capturing_ref_id, capturing_lines)
|
|
733
854
|
capturing_ref_id = None
|
|
734
855
|
capturing_lines = []
|
|
@@ -762,7 +883,11 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
762
883
|
except json.JSONDecodeError:
|
|
763
884
|
continue
|
|
764
885
|
|
|
765
|
-
if
|
|
886
|
+
if (
|
|
887
|
+
chunk_id == reward_id
|
|
888
|
+
and isinstance(data, dict)
|
|
889
|
+
and "unclaimedRewardInfo" in data
|
|
890
|
+
):
|
|
766
891
|
reward_info = data
|
|
767
892
|
log_debug(f"Found reward info")
|
|
768
893
|
|
|
@@ -773,39 +898,68 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
773
898
|
right_stream = data.get("rightStream", {})
|
|
774
899
|
if data.get("quickResponse", {}) != "$undefined":
|
|
775
900
|
quick_response_id = extract_ref_id(
|
|
776
|
-
data.get("quickResponse", {})
|
|
901
|
+
data.get("quickResponse", {})
|
|
902
|
+
.get("stream", {})
|
|
903
|
+
.get("next")
|
|
777
904
|
)
|
|
778
905
|
|
|
779
906
|
if data.get("turnId", {}) != "$undefined":
|
|
780
907
|
turn_id = extract_ref_id(data.get("turnId", {}).get("next"))
|
|
781
908
|
if data.get("persistedTurn", {}) != "$undefined":
|
|
782
|
-
persisted_turn_id = extract_ref_id(
|
|
909
|
+
persisted_turn_id = extract_ref_id(
|
|
910
|
+
data.get("persistedTurn", {}).get("next")
|
|
911
|
+
)
|
|
783
912
|
if data.get("leftMessageId", {}) != "$undefined":
|
|
784
|
-
left_message_id = extract_ref_id(
|
|
913
|
+
left_message_id = extract_ref_id(
|
|
914
|
+
data.get("leftMessageId", {}).get("next")
|
|
915
|
+
)
|
|
785
916
|
if data.get("rightMessageId", {}) != "$undefined":
|
|
786
|
-
right_message_id = extract_ref_id(
|
|
917
|
+
right_message_id = extract_ref_id(
|
|
918
|
+
data.get("rightMessageId", {}).get("next")
|
|
919
|
+
)
|
|
787
920
|
|
|
788
|
-
reward_id =
|
|
789
|
-
|
|
790
|
-
|
|
921
|
+
reward_id = (
|
|
922
|
+
extract_ref_id(data.get("pendingRewardActionResult", ""))
|
|
923
|
+
or reward_id
|
|
924
|
+
)
|
|
925
|
+
routing_id = (
|
|
926
|
+
extract_ref_id(data.get("routingResultPromise", ""))
|
|
927
|
+
or routing_id
|
|
928
|
+
)
|
|
929
|
+
nudge_new_chat_id = (
|
|
930
|
+
extract_ref_id(data.get("nudgeNewChatPromise", ""))
|
|
931
|
+
or nudge_new_chat_id
|
|
932
|
+
)
|
|
791
933
|
select_stream = [left_stream, right_stream]
|
|
792
934
|
|
|
793
935
|
elif chunk_id == routing_id:
|
|
794
936
|
yield PlainTextResponse(line.decode(errors="ignore"))
|
|
795
937
|
if isinstance(data, dict):
|
|
796
938
|
provider_info = cls.get_dict()
|
|
797
|
-
provider_info[
|
|
939
|
+
provider_info["model"] = model_id
|
|
798
940
|
for i, selection in enumerate(data.get("modelSelections", [])):
|
|
799
941
|
if selection.get("selectionSource") == "USER_SELECTED":
|
|
800
|
-
target_stream_id = extract_ref_id(
|
|
801
|
-
|
|
942
|
+
target_stream_id = extract_ref_id(
|
|
943
|
+
select_stream[i].get("next")
|
|
944
|
+
)
|
|
945
|
+
provider_info["modelLabel"] = selection.get(
|
|
946
|
+
"shortLabel"
|
|
947
|
+
)
|
|
802
948
|
provider_info["modelUrl"] = selection.get("externalUrl")
|
|
803
949
|
log_debug(f"Found target stream ID: {target_stream_id}")
|
|
804
950
|
else:
|
|
805
|
-
variant_stream_id = extract_ref_id(
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
951
|
+
variant_stream_id = extract_ref_id(
|
|
952
|
+
select_stream[i].get("next")
|
|
953
|
+
)
|
|
954
|
+
provider_info["variantLabel"] = selection.get(
|
|
955
|
+
"shortLabel"
|
|
956
|
+
)
|
|
957
|
+
provider_info["variantUrl"] = selection.get(
|
|
958
|
+
"externalUrl"
|
|
959
|
+
)
|
|
960
|
+
log_debug(
|
|
961
|
+
f"Found variant stream ID: {variant_stream_id}"
|
|
962
|
+
)
|
|
809
963
|
yield ProviderInfo.from_dict(provider_info)
|
|
810
964
|
|
|
811
965
|
elif target_stream_id and chunk_id == target_stream_id:
|
|
@@ -815,7 +969,9 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
815
969
|
content = data.get("curr", "")
|
|
816
970
|
if content:
|
|
817
971
|
ref_name = extract_ref_name(content)
|
|
818
|
-
if ref_name and (
|
|
972
|
+
if ref_name and (
|
|
973
|
+
ref_name in think_blocks or ref_name in image_blocks
|
|
974
|
+
):
|
|
819
975
|
if ref_name in think_blocks:
|
|
820
976
|
t_text = think_blocks[ref_name]
|
|
821
977
|
if t_text:
|
|
@@ -828,17 +984,14 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
828
984
|
img_block_text,
|
|
829
985
|
ref_name,
|
|
830
986
|
line_count,
|
|
831
|
-
for_target=True
|
|
987
|
+
for_target=True,
|
|
832
988
|
):
|
|
833
989
|
stream["target"].append(chunk)
|
|
834
990
|
is_started = True
|
|
835
991
|
yield chunk
|
|
836
992
|
else:
|
|
837
993
|
async for chunk in process_content_chunk(
|
|
838
|
-
content,
|
|
839
|
-
chunk_id,
|
|
840
|
-
line_count,
|
|
841
|
-
for_target=True
|
|
994
|
+
content, chunk_id, line_count, for_target=True
|
|
842
995
|
):
|
|
843
996
|
stream["target"].append(chunk)
|
|
844
997
|
is_started = True
|
|
@@ -851,10 +1004,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
851
1004
|
content = data.get("curr", "")
|
|
852
1005
|
if content:
|
|
853
1006
|
async for chunk in process_content_chunk(
|
|
854
|
-
content,
|
|
855
|
-
chunk_id,
|
|
856
|
-
line_count,
|
|
857
|
-
for_target=False
|
|
1007
|
+
content, chunk_id, line_count, for_target=False
|
|
858
1008
|
):
|
|
859
1009
|
stream["variant"].append(chunk)
|
|
860
1010
|
if isinstance(chunk, ImageResponse):
|
|
@@ -870,10 +1020,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
870
1020
|
content = data.get("curr", "")
|
|
871
1021
|
if content:
|
|
872
1022
|
async for chunk in process_content_chunk(
|
|
873
|
-
content,
|
|
874
|
-
chunk_id,
|
|
875
|
-
line_count,
|
|
876
|
-
for_target=False
|
|
1023
|
+
content, chunk_id, line_count, for_target=False
|
|
877
1024
|
):
|
|
878
1025
|
stream["quick"].append(chunk)
|
|
879
1026
|
quick_content += content
|
|
@@ -895,16 +1042,18 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
895
1042
|
content = data.get("curr", "")
|
|
896
1043
|
if content:
|
|
897
1044
|
async for chunk in process_content_chunk(
|
|
898
|
-
content,
|
|
899
|
-
chunk_id,
|
|
900
|
-
line_count,
|
|
901
|
-
for_target=False
|
|
1045
|
+
content, chunk_id, line_count, for_target=False
|
|
902
1046
|
):
|
|
903
1047
|
stream["extra"].append(chunk)
|
|
904
|
-
if
|
|
1048
|
+
if (
|
|
1049
|
+
isinstance(chunk, str)
|
|
1050
|
+
and "<streaming stopped unexpectedly" in chunk
|
|
1051
|
+
):
|
|
905
1052
|
yield FinishReason(chunk)
|
|
906
1053
|
|
|
907
|
-
yield PlainTextResponse(
|
|
1054
|
+
yield PlainTextResponse(
|
|
1055
|
+
"[Extra] " + line.decode(errors="ignore")
|
|
1056
|
+
)
|
|
908
1057
|
|
|
909
1058
|
if variant_image is not None:
|
|
910
1059
|
yield variant_image
|
|
@@ -915,13 +1064,17 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
|
|
|
915
1064
|
|
|
916
1065
|
finally:
|
|
917
1066
|
log_debug(f"Get Reward: {reward_kw}")
|
|
918
|
-
if
|
|
1067
|
+
if (
|
|
1068
|
+
reward_kw.get("turn_id")
|
|
1069
|
+
and reward_kw.get("left_message_id")
|
|
1070
|
+
and reward_kw.get("right_message_id")
|
|
1071
|
+
):
|
|
919
1072
|
eval_id = await record_model_feedback(
|
|
920
1073
|
scraper,
|
|
921
1074
|
account,
|
|
922
1075
|
reward_kw["turn_id"],
|
|
923
1076
|
reward_kw["left_message_id"],
|
|
924
|
-
reward_kw["right_message_id"]
|
|
1077
|
+
reward_kw["right_message_id"],
|
|
925
1078
|
)
|
|
926
1079
|
if eval_id:
|
|
927
1080
|
await claim_yupp_reward(scraper, account, eval_id)
|