返回提交历史
Modified
g4f/api/__init__.py
+1
-1
Modified
g4f/requests/cdp.py
+41
-17
XFEstudio/gpt4free
Fix headless mode detection and enhance button click handling in Google AI Mode
cff1e04c
代码差异
2 个文件
+42
-18
@@ -1392,7 +1392,7 @@ class Api:
1392
1392
try:
1393
1393
async with lock:
1394
1394
from g4f.requests.cdp import CDPSession
1395
session = CDPSession(headless="&headless=false" not in url)
1395
session = CDPSession(headless="headless=false" not in url)
1396
1396
await session.start()
1397
1397
try:
1398
1398
screenshot_path = await session.capture_screenshot(url, 1 if "q=" in url else 3)
@@ -693,7 +693,8 @@ const targetTexts = [
693
693
'Accept All Cookies', 'Accept all cookies',
694
694
'Einwilligen', 'Alle akzeptieren',
695
695
'Zustimmen und weiter', 'Zustimmen',
696
'Run'
696
'Run',
697
...params.getAll('click')
697
698
];
698
699
const acceptBtns = (() => {
699
700
function searchDocument(doc, offsetX = 0, offsetY = 0) {
@@ -702,7 +703,7 @@ const acceptBtns = (() => {
702
703
if (!doc) return [];
703
704
704
705
// 1. Search buttons in the current document
705
const buttons = doc.querySelectorAll('button, input[type="submit"], [role="button"], a');
706
const buttons = doc.querySelectorAll('button, input[type="submit"], [role="button"], a, h2');
706
707
for (let button of buttons) {
707
708
const text = (button.innerText || button.value || button.textContent || '').trim();
708
709
if (targetTexts.includes(text)) {
@@ -749,23 +750,31 @@ if (acceptBtns && acceptBtns.length > 0) {
749
750
}
750
751
751
752
// 4. Enable Google AI Mode if the URL has the ai-mode parameter
753
let googleAiModeButton = null;
752
754
function enableGoogleAiMode() {
753
755
// Enable Google AI Mode if the URL has the ai-mode parameter
754
756
const aiMode = params.has('ai-mode');
755
757
if (aiMode) {
756
const b = Array.from(document.querySelectorAll("a, button")).filter(a => {
758
googleAiModeButton = Array.from(document.querySelectorAll("a, button")).filter(a => {
757
759
return a.textContent.endsWith("KI‑Modus") || a.textContent.endsWith("AI Mode");
758
760
}).pop();
759
b ? b.click() : null;
761
googleAiModeButton ? googleAiModeButton.click() : null;
760
762
setTimeout(() => {
761
b ? b.click() : null;
763
googleAiModeButton ? googleAiModeButton.click() : null;
762
764
}, 1000);
765
return !!googleAiModeButton;
763
766
}
767
return false;
764
768
}
765
769
enableGoogleAiMode();
766
770
767
771
// 5. Find the textarea
768
const textarea = document.querySelector('textarea[name="prompt"], [class^="MessageInput__TextArea--"], [placeholder="Type a message..."]');
772
const fieldSelectors = [
773
'textarea[name="prompt"]',
774
'[class^="MessageInput__TextArea--"]',
775
'[placeholder="Type a message..."]',
776
];
777
const textarea = document.querySelector(fieldSelectors.join(', '));
769
778
770
779
// 6. Only proceed if we found a query and the textarea exists
771
780
if (searchQuery && textarea) {
@@ -825,7 +834,7 @@ if (searchQuery && textarea) {
825
834
})();
826
835
827
836
828
// 8. Click the send button if it exists
837
// 8. Click the send / submit button if it exists
829
838
const sendButtonSelectors = [
830
839
'[data-send-label="Send message"]',
831
840
'[aria-label="Send message"]',
@@ -833,27 +842,40 @@ const sendButtonSelectors = [
833
842
'.send-button-container',
834
843
'.send-button',
835
844
'#send-message-button', // z.ai
845
'[data-testid="chat-submit"]', // grok.com
836
846
];
837
document.querySelector(sendButtonSelectors.join(', '))?.click();
847
const sendButton = document.querySelector(sendButtonSelectors.join(', '));
848
if (sendButton) {
849
sendButton.click();
850
}
838
851
839
852
// 8. Click the send button on gemini.google.com
840
const trigger = (el, etype) => {
841
el?.dispatchEvent( new Event( etype, { bubbles: true } ) );
842
};
843
setTimeout(() =>
844
trigger(document.querySelector(`.send-button`), `click`),
845
1000);
853
const geminiSendButton = document.querySelector(`.send-button`);
854
if (geminiSendButton) {
855
setTimeout(() => {
856
geminiSendButton.dispatchEvent(new Event('click', {bubbles: true}));
857
}, 1000);
858
}
846
859
847
860
// 8. Click the send button on chat.deepseek.com
848
document.querySelector('[style="width: fit-content;"] [role="button"]')?.click();
861
const deepseekSendButton = document.querySelector('[style="width: fit-content;"] [role="button"]');
862
if (deepseekSendButton) {
863
deepseekSendButton.click();
864
}
865
866
// 9. Return the text content of the first found send button for logging/debugging
867
(
868
sendButton || geminiSendButton || deepseekSendButton || (acceptBtns && acceptBtns[0]) || googleAiModeButton
869
)?.textContent.trim();
849
870
"""
850
871
try:
851
872
rect = await self.evaluate_js(js_code)
852
if rect:
853
debug.log(f"Accept button rect: {rect}")
854
873
if rect and isinstance(rect, list) and len(rect) == 2:
855
874
await self.click(int(rect[0]), int(rect[1]))
856
875
return True
876
elif rect and isinstance(rect, str):
877
debug.log(f"Clicked button with text: {rect}")
878
return True
857
879
except Exception as e:
858
880
debug.log(f"Failed to click accept button: {e}")
859
881
return False
@@ -909,6 +931,8 @@ document.querySelector('[style="width: fit-content;"] [role="button"]')?.click()
909
931
if await self.evaluate_js('!document.doctype'):
910
932
raise RuntimeError(f"Failed to load page {url} for screenshot, document.doctype={await self.evaluate_js('String(document.doctype)')}")
911
933
934
await self.bypass_turnstile()
935
912
936
result = None
913
937
for i in range(n):
914
938
await asyncio.sleep(1)