返回提交历史
Modified
g4f/Provider/Copilot.py
+2
-1
Modified
g4f/Provider/CopilotSession.py
+5
-1
Modified
g4f/Provider/Yupp.py
+68
-32
XFEstudio/gpt4free
feat: enhance Copilot and Yupp classes with session ID and credit fetching functionality
4aa01b58
代码差异
3 个文件
+75
-34
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
3
3
import os
4
4
import json
5
import uuid
5
6
import asyncio
6
7
import base64
7
8
import random
@@ -135,7 +136,7 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
135
136
if not has_curl_cffi:
136
137
raise MissingRequirementsError('Install or update "curl_cffi" package | pip install -U curl_cffi')
137
138
model = cls.get_model(model)
138
websocket_url = cls.websocket_url
139
websocket_url = cls.websocket_url + f"&clientSessionId={uuid.uuid4()}"
139
140
headers = DEFAULT_HEADERS.copy()
140
141
headers["origin"] = cls.url
141
142
headers["referer"] = cls.url + "/"
@@ -69,6 +69,7 @@ class CopilotSession(AsyncAuthedProvider, ProviderModelMixin):
69
69
cls,
70
70
model: str,
71
71
messages: Messages,
72
auth_result: AuthResult,
72
73
proxy: str = None,
73
74
timeout: int = 30,
74
75
prompt: str = None,
@@ -87,9 +88,12 @@ class CopilotSession(AsyncAuthedProvider, ProviderModelMixin):
87
88
page = await session.get(url)
88
89
await page.send(cdp.network.enable())
89
90
queue = asyncio.Queue()
91
def handle_ws_message(event):
92
if hasattr(event, "response") and event.response.payload_data:
93
queue.put_nowait((event.request_id, event.response.payload_data))
90
94
page.add_handler(
91
95
cdp.network.WebSocketFrameReceived,
92
lambda event: queue.put_nowait((event.request_id, event.response.payload_data)),
96
handle_ws_message
93
97
)
94
98
textarea = await page.select("textarea")
95
99
if textarea is not None:
@@ -2,6 +2,7 @@ import asyncio
2
2
import hashlib
3
3
import json
4
4
import os
5
import random
5
6
import re
6
7
import time
7
8
import uuid
@@ -159,32 +160,28 @@ async def claim_yupp_reward(
159
160
def sync_record_model_feedback(
160
161
scraper: CloudScraper,
161
162
account: Dict[str, Any],
162
turn_id: str,
163
left_message_id: str,
164
right_message_id: str,
163
reward_kw: Dict[str, str]
165
164
) -> Optional[str]:
166
165
try:
167
log_debug(f"Recording model feedback for turn {turn_id}...")
168
url = "https://yupp.ai/api/trpc/evals.recordModelFeedback?batch=1"
169
payload = {
170
"0": {
171
"json": {
172
"turnId": turn_id,
173
"evalType": "SELECTION",
174
"messageEvals": [
175
{
176
"messageId": right_message_id,
177
"rating": "GOOD",
178
"reasons": ["Fast"],
179
},
180
{"messageId": left_message_id, "rating": "BAD", "reasons": []},
181
],
182
"comment": "",
183
"requireReveal": False,
184
}
185
}
186
}
166
url = "https://yupp.ai/api/trpc/evals.getTurnAnnotations"
167
payload = {"0": {"json": {"turnId": reward_kw["turn_id"]}}}
187
168
scraper.cookies.set("__Secure-yupp.session-token", account["token"])
169
response = scraper.get(url, params={"batch": "1", "input": json.dumps(payload)})
170
data = response.json()
171
positive_notes = []
172
for result in data:
173
json_data = result.get("result", {}).get("data", {}).get("json", {})
174
positive_notes = [row[0] for row in json_data.get("positive_notes", [])]
175
positive_notes = [random.choice(positive_notes)] if positive_notes else []
176
log_debug(f"Recording feedback for turn {reward_kw['turn_id']}: {positive_notes}")
177
url = "https://yupp.ai/api/trpc/evals.recordModelFeedback?batch=1"
178
selected_message_id = reward_kw.get("left_message_id") if reward_kw.get("selection") == "left" else reward_kw.get("right_message_id")
179
variant_message_id = reward_kw.get("right_message_id") if reward_kw.get("selection") == "left" else reward_kw.get("left_message_id")
180
payload = {"0":{"json":{"turnId":reward_kw["turn_id"],"isOnboarding":False,"evalType":"SELECTION","messageEvals":[
181
{"messageId":selected_message_id,"rating":"GOOD","reasons":positive_notes},
182
{"messageId":variant_message_id,"rating":"BAD","reasons":[]}
183
],"comment":"","requireReveal":False}}}
184
188
185
response = scraper.post(url, json=payload)
189
186
response.raise_for_status()
190
187
data = response.json()
@@ -206,9 +203,7 @@ def sync_record_model_feedback(
206
203
async def record_model_feedback(
207
204
scraper: CloudScraper,
208
205
account: Dict[str, Any],
209
turn_id: str,
210
left_message_id: str,
211
right_message_id: str,
206
reward_kw: Dict[str, str]
212
207
) -> Optional[str]:
213
208
loop = asyncio.get_event_loop()
214
209
return await loop.run_in_executor(
@@ -216,9 +211,7 @@ async def record_model_feedback(
216
211
sync_record_model_feedback,
217
212
scraper,
218
213
account,
219
turn_id,
220
left_message_id,
221
right_message_id,
214
reward_kw
222
215
)
223
216
224
217
@@ -289,6 +282,22 @@ async def make_chat_private(
289
282
_executor, sync_make_chat_private, scraper, account, chat_id
290
283
)
291
284
285
async def get_credits(scraper: CloudScraper, account: Dict[str, Any]) -> Optional[float]:
286
try:
287
log_debug("Fetching credit balance...")
288
url = "https://yupp.ai/api/trpc/credits.getCredits?batch=1&input=%7B%220%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%2C%22v%22%3A1%7D%7D%7D"
289
scraper.cookies.set("__Secure-yupp.session-token", account["token"])
290
def sync_fetch_credits():
291
response = scraper.get(url)
292
response.raise_for_status()
293
data = response.json()
294
balance = data[0]["result"]["data"]["json"]
295
return balance
296
loop = asyncio.get_event_loop()
297
return await loop.run_in_executor(_executor, sync_fetch_credits)
298
except Exception as e:
299
log_debug(f"Failed to fetch credit balance: {e}")
300
return None
292
301
293
302
def log_debug(message: str):
294
303
if os.getenv("DEBUG_MODE", "false").lower() == "true":
@@ -495,6 +504,26 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
495
504
)
496
505
response.raise_for_status()
497
506
return response
507
508
@classmethod
509
async def get_quota(cls, api_key: str = None) -> Optional[float]:
510
if not api_key:
511
api_key = AuthManager.load_api_key(cls)
512
if not api_key:
513
api_key = get_cookies("yupp.ai", False).get("__Secure-yupp.session-token")
514
if api_key:
515
load_yupp_accounts(api_key)
516
else:
517
raise MissingAuthError(
518
"No Yupp accounts configured. Set YUPP_API_KEY environment variable."
519
)
520
credits = await get_credits(create_scraper(), await get_best_yupp_account())
521
return {
522
"credits": {
523
"remaining": credits,
524
"total": 5000
525
}
526
}
498
527
499
528
@classmethod
500
529
async def create_async_generator(
@@ -546,6 +575,14 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
546
575
scraper = create_scraper()
547
576
if proxy:
548
577
scraper.proxies = {"http": proxy, "https": proxy}
578
579
credits = await get_credits(scraper, account)
580
log_debug(f"Account ...{account['token'][-4:]} has {credits} credits")
581
if credits is not None and credits <= 100:
582
log_debug(f"Account ...{account['token'][-4:]} has low credits, rotating")
583
async with account_rotation_lock:
584
account["error_count"] += 1
585
continue
549
586
550
587
# Initialize token extractor for automatic token swapping
551
588
token_extractor = get_token_extractor(
@@ -943,6 +980,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
943
980
target_stream_id = extract_ref_id(
944
981
select_stream[i].get("next")
945
982
)
983
reward_kw["selection"] = "left" if i == 0 else "right"
946
984
provider_info["modelLabel"] = selection.get(
947
985
"shortLabel"
948
986
)
@@ -1073,9 +1111,7 @@ class Yupp(AsyncGeneratorProvider, ProviderModelMixin):
1073
1111
eval_id = await record_model_feedback(
1074
1112
scraper,
1075
1113
account,
1076
reward_kw["turn_id"],
1077
reward_kw["left_message_id"],
1078
reward_kw["right_message_id"],
1114
reward_kw
1079
1115
)
1080
1116
if eval_id:
1081
1117
await claim_yupp_reward(scraper, account, eval_id)