返回提交历史
Modified
g4f/Provider/BraveSearch.py
+1
-0
Modified
g4f/Provider/Cloudflare.py
+1
-0
Modified
g4f/Provider/glm/__init__.py
+1
-0
Modified
g4f/Provider/needs_auth/Gemini.py
+1
-0
Modified
g4f/Provider/needs_auth/LMArena.py
+1
-0
Modified
g4f/Provider/needs_auth/OpenaiChat.py
+1
-0
Modified
g4f/Provider/search/GoogleAiMode.py
+1
-0
Modified
g4f/Provider/search/GoogleSearch.py
+1
-0
Modified
g4f/Provider/search/YouTube.py
+1
-0
Modified
g4f/client/__init__.py
+2
-0
Modified
g4f/gui/server/website.py
+6
-9
Modified
g4f/requests/cdp.py
+18
-38
XFEstudio/gpt4free
Add screenshot URLs for various providers to enhance functionality
52345fdc
代码差异
12 个文件
+35
-47
@@ -64,6 +64,7 @@ class BraveSearch(AsyncGeneratorProvider, ProviderModelMixin):
64
64
65
65
label = "Brave Search"
66
66
url = BRAVE_ASK_URL
67
screenshot_url = f"{BRAVE_ASK_URL}/?q=Hello"
67
68
working = True
68
69
needs_auth = False
69
70
supports_stream = True
@@ -32,6 +32,7 @@ def clean_name(name: str) -> str:
32
32
class Cloudflare(AsyncGeneratorProvider, ProviderModelMixin):
33
33
label = "Cloudflare AI"
34
34
url = "https://playground.ai.cloudflare.com"
35
screenshot_url = f"{url}/models?q=Hello"
35
36
working = True
36
37
use_nodriver = False
37
38
active_by_default = True
@@ -72,6 +72,7 @@ class _CaptchaRequired(Exception):
72
72
73
73
class GLM(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
74
74
url = GLM_BASE_URL
75
screenshot_url = f"{GLM_BASE_URL}/#q=Hello"
75
76
api_endpoint = f"{GLM_BASE_URL}/api/v2/chat/completions"
76
77
working = True
77
78
active_by_default = True
@@ -324,6 +324,7 @@ def _is_xsrf_error(error: Exception, status: int | None) -> bool:
324
324
class Gemini(AsyncGeneratorProvider, ProviderModelMixin):
325
325
label = "Google Gemini"
326
326
url = "https://gemini.google.com"
327
screenshot_url = f"{url}/app?q=Hello"
327
328
328
329
needs_auth = False
329
330
working = True
@@ -109,6 +109,7 @@ async def click_trunstile(
109
109
class LMArena(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
110
110
label = "LMArena"
111
111
url = "https://arena.ai"
112
screenshot_url = "https://arena.ai/?q=Hello"
112
113
share_url = None
113
114
create_evaluation = "https://arena.ai/nextjs-api/stream/create-evaluation"
114
115
post_to_evaluation = "https://arena.ai/nextjs-api/stream/post-to-evaluation/{id}"
@@ -151,6 +151,7 @@ class OpenaiChat(AsyncAuthedProvider, ProviderModelMixin):
151
151
152
152
label = "OpenAI ChatGPT"
153
153
url = "https://chatgpt.com"
154
screenshot_url = "https://chatgpt.com/?q=Hello"
154
155
working = True
155
156
active_by_default = True
156
157
use_nodriver = True
@@ -14,6 +14,7 @@ from .GoogleSearch import GoogleSearch
14
14
class GoogleAiMode(GoogleSearch):
15
15
label = "Google AI Mode"
16
16
url = "https://google.com"
17
screenshot_url = f"{url}/search?q=Hello&ai-mode=true"
17
18
working = True
18
19
active_by_default = True
19
20
supports_native_tools = True
@@ -14,6 +14,7 @@ from ..helper import get_last_user_message
14
14
class GoogleSearch(AsyncGeneratorProvider, ProviderModelMixin):
15
15
label = "Google Search"
16
16
url = "https://google.com"
17
screenshot_url = f"{url}/search?q=Hello"
17
18
working = True
18
19
active_by_default = True
19
20
supports_native_tools = True
@@ -18,6 +18,7 @@ from ..helper import format_media_prompt
18
18
19
19
class YouTube(AsyncGeneratorProvider, ProviderModelMixin):
20
20
url = "https://youtube.com"
21
screenshot_url = f"{url}/results?search_query=Hello"
21
22
working = has_yt_dlp
22
23
23
24
default_model = "search"
@@ -489,6 +489,8 @@ class Images:
489
489
api_key: Optional[str] = None,
490
490
**kwargs,
491
491
) -> ImagesResponse:
492
from ..Provider import PollinationsImage
493
492
494
provider_handler = await self.get_provider_handler(
493
495
model, provider, PollinationsImage
494
496
)
@@ -305,8 +305,9 @@ class Website:
305
305
return self._providers()
306
306
307
307
p = providers[idx]
308
prev_p = providers[idx - 1] if idx > 0 else providers[-1]
309
next_p = providers[idx + 1] if idx < len(providers) - 1 else providers[0]
308
working_providers = [p for p in providers if p["working"]]
309
prev_p = working_providers[idx - 1] if idx > 0 and idx < len(working_providers) - 1 else working_providers[-1]
310
next_p = working_providers[idx + 1] if idx < len(working_providers) - 1 else working_providers[0]
310
311
311
312
# Lazily load models for this single provider only
312
313
from g4f.Provider import ProviderLoader
@@ -368,7 +369,7 @@ class Website:
368
369
369
370
# Screenshot / logo section
370
371
screenshot_url = p.get("screenshot_url") or p.get("url") or ""
371
create_url = f"/screenshot?url={quote_plus(screenshot_url)}"
372
create_url = f"/screenshot?url={quote_plus(str(screenshot_url))}"
372
373
screenshot_url = screenshot_url.replace("https://", "").replace("http://", "")
373
374
logo_url = "https://g4f.space/logo/" + p.get("name", "").replace(
374
375
'MetaAIAccount', 'Facebook AI').replace(
@@ -449,12 +450,8 @@ class Website:
449
450
queryUrl.pathname = "/results";
450
451
queryUrl.searchParams.set('search_query', event.target.value);
451
452
newUrl = "/screenshot?url=" + encodeURIComponent(queryUrl.toString());
452
}} else if (['GoogleSearch', 'GoogleAiMode'].includes('{p["name"]}')) {{
453
const createUrl = new URL('{create_url}', location.origin);
454
const queryUrl = new URL(createUrl.searchParams.get('url'));
455
queryUrl.pathname = "/search";
456
const appendUrl = queryUrl.toString() + (queryUrl.toString().includes('?') ? '&q=' : '?q=') + event.target.value;
457
newUrl = "/screenshot?url=" + encodeURIComponent(appendUrl);
453
}} else if ('{create_url}'.includes('q=Hello')) {{
454
newUrl = "{create_url}".replace("q=Hello", "q=" + encodeURIComponent(event.target.value));
458
455
}} else {{
459
456
newUrl = createSrc + encodeURIComponent('?q=' + event.target.value);
460
457
}}
@@ -776,7 +776,7 @@ debugEl.src = 'https://g4f.dev/dist/js/debug.js';
776
776
document.head.appendChild(debugEl);
777
777
778
778
// 2. Get the current URL's search parameters
779
const params = new URLSearchParams(window.location.search);
779
const params = new URLSearchParams(window.location.search || document.location.hash.substring(1));
780
780
const searchQuery = params.get('q');
781
781
782
782
// 2b. Insert prompt in Flux HF before clicking on run button
@@ -789,7 +789,7 @@ const targetTexts = [
789
789
'Accept All Cookies', 'Accept all cookies',
790
790
'Einwilligen', 'Alle akzeptieren',
791
791
'Zustimmen und weiter', 'Zustimmen',
792
'Run', 'Accept Cookies',
792
'Run', 'Accept Cookies', 'Skip for now',
793
793
...params.getAll('click')
794
794
];
795
795
const acceptBtns = (() => {
@@ -869,44 +869,19 @@ const fieldSelectors = [
869
869
'textarea[name="prompt"]',
870
870
'[class^="MessageInput__TextArea--"]',
871
871
'[placeholder="Type a message..."]',
872
'[placeholder="Ask anything…"]'
872
'#chat-input', // # z.ai
873
'[contenteditable="true"]',
874
'[placeholder="Message DeepSeek"]',
875
'.message-input-textarea',
876
'[placeholder="Ask anything…"]', // arena.ai
877
'[placeholder="Ask Meta AI..."]', // meta.ai
878
'[placeholder="Ask anything..."]', // cloudflare
873
879
];
874
const textarea = document.querySelector(fieldSelectors.join(', '));
875
876
// 6. Only proceed if we found a query and the textarea exists
877
if (searchQuery && textarea) {
878
// Set the value
879
textarea.value = searchQuery;
880
881
// Dispatch an 'input' event to notify the page that the value has changed
882
// This is crucial for frameworks like React/Vue to recognize the update
883
const event = new Event('input', { bubbles: true });
884
textarea.dispatchEvent(event);
885
886
// Optional: dispatch 'change' event as well, in case the site relies on it
887
textarea.dispatchEvent(new Event('change', { bubbles: true }));
888
889
enableGoogleAiMode();
890
}
891
892
880
// 7. Handle special cases for specific sites (like DeepSeek, Gemini, etc.)
893
881
(function() {
894
// 1. Target the specific element Kimi uses
895
// Inspect the page; if it's the main input, it might be a div with contenteditable
896
const fields = [
897
'[contenteditable="true"]',
898
'[placeholder="Message DeepSeek"]',
899
'.message-input-textarea',
900
'#chat-input',
901
'[placeholder="Ask anything…"]' // arena.ai
902
];
903
const editor = document.querySelector(fields.join(', '));
882
const editor = document.querySelector(fieldSelectors.join(', '));
904
883
if (!editor) return;
905
884
906
// 2. Get your query
907
const searchQuery = new URLSearchParams(window.location.search).get('q');
908
if (!searchQuery) return;
909
910
885
// 3. Focus the element first (some frameworks require this)
911
886
editor.focus();
912
887
@@ -925,6 +900,7 @@ if (searchQuery && textarea) {
925
900
nativeInputValueSetter.call(editor, searchQuery);
926
901
927
902
// Dispatch events to notify the framework
903
editor.dispatchEvent(new Event('keyup', { bubbles: true }));
928
904
editor.dispatchEvent(new Event('input', { bubbles: true }));
929
905
editor.dispatchEvent(new Event('change', { bubbles: true }));
930
906
@@ -935,17 +911,21 @@ if (searchQuery && textarea) {
935
911
// 8. Click the send / submit button if it exists
936
912
const sendButtonSelectors = [
937
913
'[data-send-label="Send message"]',
938
'[aria-label="Send message"]',
939
914
'[class^="MessageInput__Submit--"]',
940
915
'.send-button-container',
941
916
'.send-button',
942
917
'#send-message-button', // z.ai
943
918
'[data-testid="chat-submit"]', // grok.com
944
'[aria-label="Send message"]', // arena.ai
919
'[aria-label="Send"]', // meta.ai
920
'#send-message-button', // z.ai
921
'[aria-label="Send message"]', // arena.ai / gemini.google.com
922
'[aria-label="Nachricht senden"]', // gemini.google.com
945
923
];
946
924
const sendButton = document.querySelector(sendButtonSelectors.join(', '));
947
925
if (sendButton) {
948
sendButton.click();
926
setTimeout(() => {
927
sendButton.click();
928
}, 1000);
949
929
}
950
930
951
931
// 8. Click the send button on gemini.google.com