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

XFEstudio/gpt4free

Add AI Model to Google Search

fd950a00
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

3 个文件 +87 -17
Modified g4f/Provider/search/GoogleSearch.py +72 -6
@@ -16,8 +16,10 @@ class GoogleSearch(AsyncGeneratorProvider, ProviderModelMixin):
16 16 label = "Google Search"
17 17 url = "https://google.com"
18 18 working = True
19 active_by_default = True
19 20 supports_native_tools = True
20 21 default_model = "search"
22 models = [default_model, "ai-mode"]
21 23
22 24 @classmethod
23 25 async def create_async_generator(
@@ -35,11 +37,77 @@ class GoogleSearch(AsyncGeneratorProvider, ProviderModelMixin):
35 37
36 38 try:
37 39 await session.navigate(search_url)
38
39 40 await session.click_accept_button()
41 except Exception as e:
42 await session.close()
43 raise e
44
45 # Enable AI mode if the model is like "ai"
46 try:
47 if model == "ai-mode":
48 await session.wait_for_network_idle(idle_time=1, timeout=10.0)
49 for _ in range(10):
50 result = await session.evaluate_js("""const b =Array.from(document.querySelectorAll("a, button")).filter(a=>a.textContent.endsWith("KI‑Modus")).pop(); b ? b.click() : null; !!b""")
51 debug.log(f"Google Search: Attempted #{_+1} to enable AI mode, result: {result}")
52 await asyncio.sleep(1)
53 if not result:
54 continue
55 await session.wait_for_network_idle(idle_time=1, timeout=10.0)
56 results = await session.call("Runtime.evaluate", expression="""
57 const cyrb53 = (str, seed = 0) => {
58 let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
59 for(let i = 0, ch; i < str.length; i++) {
60 ch = str.charCodeAt(i);
61 h1 = Math.imul(h1 ^ ch, 2654435761);
62 h2 = Math.imul(h2 ^ ch, 1597334677);
63 }
64 h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
65 h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
66 h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
67 h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
68
69 return 4294967296 * (2097151 & h2) + (h1 >>> 0);
70 };
71
72 const result = [];
73 for (const nodes of Array.from(document.querySelector('[decode-data-ved="1"]').querySelectorAll('*')).map(e=>Array.from(e.childNodes))) {
74 for (const node of nodes) {result.push(node)}
75 }
76
77 const lines = result.map(n=>n.textContent).filter(c=>!c.startsWith('TgQPHd|'));
78 const keepLines = { };
79
80 for (let l of lines) {
81 if (l.startsWith('TgQPHd')) continue;
82 if (l.startsWith("KI-Antworten können Fehler enthalten.")) break;
83 if (!l) continue;
84
85 // Sucht nach n._setImageSrc('ID', 'BASE64_DATEN') und extrahiert die Bilddaten
86 const imgMatch = l.match(/_setImageSrc\\([^,]+,\\s*'([^']+)'\\)/);
87 if (imgMatch) {
88 // Bereinigt eventuelle doppelte Backslashes aus dem Daten-String (z.B. data:image\\/png)
89 l = `\\n![](${imgMatch[1]})`;
90 }
91 const fileMath = l.match(/\\[\\{.+\\]^/);
92 if (fileMath) {
93 l = l.replace(fileMath[0], '');
94 }
95
96 const hash = cyrb53(l);
97 keepLines[hash] = l;
98 }
99 Object.values(keepLines);
100 """, returnByValue=True);
101 debug.log(f"Google Search: AI mode results: {results}")
102 if results:
103 for text in results.get("result", {}).get("value", []):
104 yield f"{text}\n"
105 return
106 if model == "ai-mode":
107 raise RuntimeError("No AI mode results found.")
40 108
41 109 # Wait for Google search results page to load
42 for _ in range(30):
110 for _ in range(10):
43 111 try:
44 112 has_results = await session.evaluate_js(
45 113 "document.querySelectorAll('div.g, h3').length > 0"
@@ -51,7 +119,7 @@ class GoogleSearch(AsyncGeneratorProvider, ProviderModelMixin):
51 119 await asyncio.sleep(1)
52 120
53 121 # Extract search results from the DOM
54 results_json = await session.evaluate_js(
122 results = await session.evaluate_js(
55 123 """
56 124 (() => {
57 125 const results = [];
@@ -74,13 +142,11 @@ class GoogleSearch(AsyncGeneratorProvider, ProviderModelMixin):
74 142 results.push({ title, link: link.toString(), snippet });
75 143 }
76 144 });
77 return JSON.stringify(results);
145 return results;
78 146 })()
79 147 """
80 148 )
81 149
82 results = json.loads(results_json) if results_json else []
83
84 150 if not results:
85 151 raise RuntimeError("No search results found.")
86 152 yield SearchResults(results)
Modified g4f/mcp/pa_downloader.py +1 -1
@@ -378,7 +378,7 @@ def auto_download_pa_providers(
378 378 return []
379 379
380 380 if written:
381 print(f"pa-providers: auto-downloaded {len(written)} provider(s) from {repo}")
381 pass
382 382 else:
383 383 debug.log("pa-providers: auto-download found nothing new to install")
384 384 return written
Modified g4f/requests/cdp.py +14 -10
@@ -783,6 +783,13 @@ class CDPSession:
783 783
784 784 async def capture_screenshot(self, url: str, n: int = 3) -> AsyncIterator[str]:
785 785 """Navigate to a URL and capture a screenshot, caching the result."""
786 url_without_suffix = url[:-6] if url.endswith("_2.jpg") or url.endswith("_3.jpg") else url
787 url_with_noads = f"{url_without_suffix}&noads={int(time.time())}" if "?" in url_without_suffix else f"{url_without_suffix}?noads={int(time.time())}"
788 await self.navigate(url_with_noads)
789
790 if await self.evaluate_js('!document.doctype'):
791 raise RuntimeError(f"Failed to load page {url} for screenshot, document.doctype={await self.evaluate_js('String(document.doctype)')}")
792
786 793 result = None
787 794 for i in range(n):
788 795 await asyncio.sleep(1)
@@ -803,20 +810,17 @@ class CDPSession:
803 810 if os.path.exists(filepath):
804 811 debug.log(f"Screenshot already exists: {filepath}")
805 812 return filepath
806 url_with_noads = f"{url_without_suffix}&noads={int(time.time())}" if "?" in url_without_suffix else f"{url_without_suffix}?noads={int(time.time())}"
807 await self.navigate(url_with_noads)
808 813 # Wait for network activity to settle before capturing
809 814 await self.wait_for_network_idle(idle_time=5, timeout=15.0)
810 if await self.evaluate_js('!document.doctype'):
811 raise RuntimeError(f"Failed to load page {url} for screenshot, doctype={await self.evaluate_js('String(document.doctype)')}")
812 815 # Try to click any "Accept" or "Einwilligen" cookie consent buttons
813 for _ in range(5):
814 debug.log("Attempting to click accept button...")
815 await asyncio.sleep(1)
816 if await self.click_accept_button():
817 debug.log("Clicked accept button.")
816 if n != 1:
817 for _ in range(2):
818 debug.log("Attempting to click accept button...")
818 819 await asyncio.sleep(1)
819 break
820 if await self.click_accept_button():
821 debug.log("Clicked accept button.")
822 await asyncio.sleep(1)
823 break
820 824 await self.wait_for_network_idle(idle_time=5, timeout=15.0)
821 825 result = await self.call("Page.captureScreenshot")
822 826 image_bytes = base64.b64decode(result["data"])