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

XFEstudio/gpt4free

Fix Perchance API (image generation Turnstile flow & request format) and CDP settings

0427e129
kqlio67 <kqlio67@users.noreply.github.com>
提交于

代码差异

3 个文件 +69 -15
Modified g4f/Provider/Perchance.py +20 -9
@@ -40,8 +40,15 @@ class Perchance(AsyncGeneratorProvider, ProviderModelMixin):
40 40 session = CDPSession(headless=False)
41 41 await session.start()
42 42 try:
43 verify_url = "https://image-generation.perchance.org/embed" if is_image else cls.verify_url
44 origin = "https://image-generation.perchance.org" if is_image else "https://text-generation.perchance.org"
43 if is_image:
44 import urllib.parse
45 hash_data = {"prompt": "a", "resolution": "512x512", "guidanceScale": 7, "channel": "ai-text-to-image-generator", "subChannel": "public", "seed": -1, "requestId": "a"}
46 hash_str = urllib.parse.quote(json.dumps(hash_data))
47 verify_url = f"https://image-generation.perchance.org/embed#{hash_str}"
48 origin = "https://image-generation.perchance.org"
49 else:
50 verify_url = cls.verify_url
51 origin = "https://text-generation.perchance.org"
45 52
46 53 await session.navigate(verify_url)
47 54
@@ -57,9 +64,10 @@ class Perchance(AsyncGeneratorProvider, ProviderModelMixin):
57 64 await session.evaluate_js(setup_js)
58 65
59 66 # Always trigger verifyUser to ensure Turnstile solving/checking is executed
60 verify_js = """
61 window.postMessage({type: "verifyUser"}, window.location.origin);
62 """
67 if is_image:
68 verify_js = "if(typeof start === 'function') start({reloadPageOnFail: false});"
69 else:
70 verify_js = 'window.postMessage({type: "verifyUser"}, window.location.origin);'
63 71 await session.evaluate_js(verify_js)
64 72
65 73 # Anti-detect: warm up the browser and disable debugger overhead DURING Turnstile check
@@ -130,22 +138,25 @@ class Perchance(AsyncGeneratorProvider, ProviderModelMixin):
130 138 "seed": -1,
131 139 "resolution": "512x512",
132 140 "guidanceScale": 7,
133 "channel": "text-to-image-plugin-example",
141 "channel": "ai-text-to-image-generator",
134 142 "subChannel": "public",
135 143 "userKey": cls._image_user_key,
136 144 "adAccessCode": ad_access_code,
137 145 "requestId": str(req_id)
138 146 }
139 147
140 gen_url = f"{cls.image_api_endpoint}?userKey={cls._image_user_key}&requestId={req_id}&adAccessCode={ad_access_code}&__cacheBust={random.random()}"
148 gen_url = f"{cls.image_api_endpoint}?userKey={cls._image_user_key}&requestId={req_id}&adAccessCode={ad_access_code}&__cacheBust={random.random()}&bdf={random.random()}"
149
150 headers = cls._image_headers.copy()
151 headers["Content-Type"] = "text/plain;charset=UTF-8"
141 152
142 153 async with StreamSession(
143 headers=cls._image_headers,
154 headers=headers,
144 155 cookies=cls._image_cookies,
145 156 proxies={"all": proxy} if proxy else None,
146 157 impersonate="chrome"
147 158 ) as session:
148 async with session.post(gen_url, json=payload, proxy=proxy) as response:
159 async with session.post(gen_url, data=json.dumps(payload), proxy=proxy) as response:
149 160 if response.status in (401, 403):
150 161 cls._image_user_key = cls._image_cookies = cls._image_headers = None
151 162 raise RuntimeError("auth_failed")
Modified g4f/Provider/needs_auth/__init__.py +1 -0
@@ -12,6 +12,7 @@ from .Cohere import Cohere
12 12 from .CopilotAccount import CopilotAccount
13 13 from .Custom import Custom
14 14 from .Custom import Feature
15 from .DeepSeek import DeepSeek
15 16 from .FenayAI import FenayAI
16 17 from .Gemini import Gemini
17 18 from .GeminiPro import GeminiPro
Modified g4f/requests/cdp.py +48 -6
@@ -210,8 +210,7 @@ def get_shared_browser(host: str, preferred_port: int, headless: bool = True) ->
210 210 chrome_path,
211 211 f"--remote-debugging-port={port}",
212 212 f"--user-data-dir={user_data_dir}",
213 "--window-position=-2000,-2000",
214 "--window-size=1024,768",
213 "--window-size=1920,1080",
215 214 "--no-default-browser-check",
216 215 "--disable-suggestions-ui",
217 216 "--no-first-run",
@@ -219,6 +218,7 @@ def get_shared_browser(host: str, preferred_port: int, headless: bool = True) ->
219 218 "--disable-popup-blocking",
220 219 "--hide-crash-restore-bubble",
221 220 "--disable-features=PrivacySandboxSettings4",
221 "--disable-blink-features=AutomationControlled",
222 222 "--remote-allow-origins=*"
223 223 ]
224 224 if headless:
@@ -497,6 +497,42 @@ class CDPSession:
497 497 await asyncio.sleep(delay)
498 498 await self.call("Input.dispatchMouseEvent", type="mouseReleased", button="left", clickCount=1, x=x, y=y)
499 499
500 async def click_turnstile_checkbox(self) -> bool:
501 """Find the Cloudflare Turnstile iframe on the page and click its center."""
502 js_code = """
503 (() => {
504 const iframes = document.querySelectorAll('iframe');
505 let cfIframe = null;
506 for (let iframe of iframes) {
507 if (iframe.src && iframe.src.includes('challenges.cloudflare.com')) {
508 cfIframe = iframe;
509 break;
510 }
511 }
512 if (!cfIframe) return null;
513
514 const rect = cfIframe.getBoundingClientRect();
515 return {
516 x: rect.left + window.scrollX,
517 y: rect.top + window.scrollY,
518 width: rect.width,
519 height: rect.height
520 };
521 })()
522 """
523 try:
524 rect = await self.evaluate_js(js_code)
525 if rect and isinstance(rect, dict) and rect.get('width', 0) > 0:
526 # Center of the Turnstile checkbox (usually left aligned in the iframe)
527 center_x = int(rect['x'] + rect['width'] / 4)
528 center_y = int(rect['y'] + rect['height'] / 2)
529
530 await self.click(center_x, center_y)
531 return True
532 except Exception as e:
533 logger.debug(f"Failed to auto-click Turnstile: {e}")
534 return False
535
500 536 async def bypass_turnstile(self):
501 537 """Execute a sequence of anti-detect actions to bypass Cloudflare Turnstile."""
502 538 import random
@@ -518,19 +554,25 @@ class CDPSession:
518 554 await self.mouse_move(int(x), int(y))
519 555 await asyncio.sleep(random.uniform(0.05, 0.1))
520 556
521 # 3. Click randomly to gain focus
522 await self.click(end_x, end_y)
557 # 3. Try to click the specific Cloudflare Turnstile checkbox
558 clicked_cf = await self.click_turnstile_checkbox()
523 559
524 # 4. Scroll down slightly
560 # 4. If Cloudflare iframe not found, click randomly to gain focus
561 if not clicked_cf:
562 await self.click(end_x, end_y)
563
564 # 5. Scroll down slightly
525 565 await self.evaluate_js(f"window.scrollBy(0, {random.randint(100, 300)})")
526 566 await asyncio.sleep(0.2)
527 567
528 # 5. Temporarily disable Network interception to hide debugger overhead
568 # 6. Temporarily disable Network and Runtime interception to hide debugger overhead
529 569 try:
530 570 await self.call("Network.disable")
571 await self.call("Runtime.disable")
531 572 await asyncio.sleep(2)
532 573 finally:
533 574 await self.call("Network.enable")
575 await self.call("Runtime.enable")
534 576
535 577 async def close(self):
536 578 """Close WebSocket session and close the specific target tab."""