@apmantza/greedysearch-pi 1.7.2 → 1.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -94
- package/README.md +73 -73
- package/bin/coding-task.mjs +5 -27
- package/bin/search.mjs +159 -185
- package/extractors/bing-copilot.mjs +8 -20
- package/extractors/common.mjs +44 -2
- package/extractors/gemini.mjs +20 -35
- package/extractors/google-ai.mjs +11 -43
- package/index.ts +18 -18
- package/package.json +46 -46
package/extractors/google-ai.mjs
CHANGED
|
@@ -16,53 +16,17 @@ import {
|
|
|
16
16
|
handleError,
|
|
17
17
|
outputJson,
|
|
18
18
|
parseArgs,
|
|
19
|
+
TIMING,
|
|
19
20
|
validateQuery,
|
|
21
|
+
waitForStreamComplete,
|
|
20
22
|
} from "./common.mjs";
|
|
21
23
|
import { dismissConsent, handleVerification } from "./consent.mjs";
|
|
22
24
|
import { SELECTORS } from "./selectors.mjs";
|
|
23
25
|
|
|
24
26
|
const S = SELECTORS.google;
|
|
25
27
|
|
|
26
|
-
const STREAM_POLL_INTERVAL = 600;
|
|
27
|
-
const STREAM_STABLE_ROUNDS = 3;
|
|
28
|
-
const STREAM_TIMEOUT = 45000;
|
|
29
28
|
const MIN_ANSWER_LENGTH = 50;
|
|
30
29
|
|
|
31
|
-
// ============================================================================
|
|
32
|
-
// Google AI-specific helpers
|
|
33
|
-
// ============================================================================
|
|
34
|
-
|
|
35
|
-
async function waitForGoogleStreamComplete(tab) {
|
|
36
|
-
const deadline = Date.now() + STREAM_TIMEOUT;
|
|
37
|
-
let stableCount = 0;
|
|
38
|
-
let lastLen = -1;
|
|
39
|
-
|
|
40
|
-
while (Date.now() < deadline) {
|
|
41
|
-
await new Promise((r) => setTimeout(r, STREAM_POLL_INTERVAL));
|
|
42
|
-
|
|
43
|
-
const lenStr = await cdp([
|
|
44
|
-
"eval",
|
|
45
|
-
tab,
|
|
46
|
-
`(document.querySelector('${S.answerContainer}')?.innerText?.length || 0) + ''`,
|
|
47
|
-
]).catch(() => "0");
|
|
48
|
-
|
|
49
|
-
const len = parseInt(lenStr, 10) || 0;
|
|
50
|
-
|
|
51
|
-
if (len >= MIN_ANSWER_LENGTH && len === lastLen) {
|
|
52
|
-
stableCount++;
|
|
53
|
-
if (stableCount >= STREAM_STABLE_ROUNDS) return len;
|
|
54
|
-
} else {
|
|
55
|
-
stableCount = 0;
|
|
56
|
-
lastLen = len;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (lastLen >= MIN_ANSWER_LENGTH) return lastLen;
|
|
61
|
-
throw new Error(
|
|
62
|
-
`Google AI answer did not stabilise within ${STREAM_TIMEOUT}ms`,
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
30
|
async function extractAnswer(tab) {
|
|
67
31
|
const excludeFilter = S.sourceExclude
|
|
68
32
|
.map((e) => `!a.href.includes('${e}')`)
|
|
@@ -105,9 +69,9 @@ async function main() {
|
|
|
105
69
|
await cdp(["list"]);
|
|
106
70
|
const tab = await getOrOpenTab(tabPrefix);
|
|
107
71
|
|
|
108
|
-
const url = `https://www.google.com/search?q=${encodeURIComponent(query)}&udm=50`;
|
|
72
|
+
const url = `https://www.google.com/search?q=${encodeURIComponent(query)}&udm=50&hl=en`;
|
|
109
73
|
await cdp(["nav", tab, url], 35000);
|
|
110
|
-
await new Promise((r) => setTimeout(r,
|
|
74
|
+
await new Promise((r) => setTimeout(r, TIMING.postNav));
|
|
111
75
|
await dismissConsent(tab, cdp);
|
|
112
76
|
|
|
113
77
|
// If consent redirected us away, navigate back
|
|
@@ -116,7 +80,7 @@ async function main() {
|
|
|
116
80
|
);
|
|
117
81
|
if (!currentUrl.includes("google.com/search")) {
|
|
118
82
|
await cdp(["nav", tab, url], 35000);
|
|
119
|
-
await new Promise((r) => setTimeout(r,
|
|
83
|
+
await new Promise((r) => setTimeout(r, TIMING.postNav));
|
|
120
84
|
}
|
|
121
85
|
|
|
122
86
|
// Handle "verify you're human" — auto-click simple buttons, wait for user on hard CAPTCHA
|
|
@@ -128,10 +92,14 @@ async function main() {
|
|
|
128
92
|
if (verifyResult === "clicked" || verifyResult === "cleared-by-user") {
|
|
129
93
|
// Re-navigate to the search URL after verification
|
|
130
94
|
await cdp(["nav", tab, url], 35000);
|
|
131
|
-
await new Promise((r) => setTimeout(r,
|
|
95
|
+
await new Promise((r) => setTimeout(r, TIMING.postNav));
|
|
132
96
|
}
|
|
133
97
|
|
|
134
|
-
await
|
|
98
|
+
await waitForStreamComplete(tab, {
|
|
99
|
+
timeout: 45000,
|
|
100
|
+
selector: `document.querySelector('${S.answerContainer}')`,
|
|
101
|
+
minLength: MIN_ANSWER_LENGTH,
|
|
102
|
+
});
|
|
135
103
|
|
|
136
104
|
const { answer, sources } = await extractAnswer(tab);
|
|
137
105
|
if (!answer)
|
package/index.ts
CHANGED
|
@@ -23,9 +23,9 @@ const __dir = dirname(fileURLToPath(import.meta.url));
|
|
|
23
23
|
|
|
24
24
|
const ALL_ENGINES = ["perplexity", "bing", "google"] as const;
|
|
25
25
|
|
|
26
|
-
function cdpAvailable(): boolean {
|
|
27
|
-
return existsSync(join(__dir, "bin", "cdp.mjs"));
|
|
28
|
-
}
|
|
26
|
+
function cdpAvailable(): boolean {
|
|
27
|
+
return existsSync(join(__dir, "bin", "cdp.mjs"));
|
|
28
|
+
}
|
|
29
29
|
|
|
30
30
|
function runSearch(
|
|
31
31
|
engine: string,
|
|
@@ -34,14 +34,14 @@ function runSearch(
|
|
|
34
34
|
signal?: AbortSignal,
|
|
35
35
|
onProgress?: (engine: string, status: "done" | "error") => void,
|
|
36
36
|
): Promise<Record<string, unknown>> {
|
|
37
|
-
return new Promise((resolve, reject) => {
|
|
38
|
-
const proc = spawn(
|
|
39
|
-
"node",
|
|
40
|
-
[join(__dir, "bin", "search.mjs"), engine, "--inline", ...flags, query],
|
|
41
|
-
{
|
|
42
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
43
|
-
},
|
|
44
|
-
);
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const proc = spawn(
|
|
39
|
+
"node",
|
|
40
|
+
[join(__dir, "bin", "search.mjs"), engine, "--inline", ...flags, query],
|
|
41
|
+
{
|
|
42
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
45
|
let out = "";
|
|
46
46
|
let err = "";
|
|
47
47
|
|
|
@@ -355,13 +355,13 @@ export default function greedySearchExtension(pi: ExtensionAPI) {
|
|
|
355
355
|
|
|
356
356
|
const data = await new Promise<Record<string, unknown>>(
|
|
357
357
|
(resolve, reject) => {
|
|
358
|
-
const proc = spawn(
|
|
359
|
-
"node",
|
|
360
|
-
[join(__dir, "bin", "coding-task.mjs"), task, ...flags],
|
|
361
|
-
{
|
|
362
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
363
|
-
},
|
|
364
|
-
);
|
|
358
|
+
const proc = spawn(
|
|
359
|
+
"node",
|
|
360
|
+
[join(__dir, "bin", "coding-task.mjs"), task, ...flags],
|
|
361
|
+
{
|
|
362
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
363
|
+
},
|
|
364
|
+
);
|
|
365
365
|
let out = "";
|
|
366
366
|
let err = "";
|
|
367
367
|
|
package/package.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@apmantza/greedysearch-pi",
|
|
3
|
-
"version": "1.7.
|
|
4
|
-
"description": "Pi extension: multi-engine AI search (Perplexity, Bing Copilot, Google AI) via browser automation -- NO API KEYS needed. Extracts answers with sources, optional Gemini synthesis. Grounded AI answers from real browser interactions.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"pi-package"
|
|
8
|
-
],
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/apmantza/GreedySearch-pi.git"
|
|
12
|
-
},
|
|
13
|
-
"author": "Apostolos Mantzaris",
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"scripts": {
|
|
16
|
-
"test": "./test.sh",
|
|
17
|
-
"test:quick": "./test.sh quick",
|
|
18
|
-
"test:smoke": "./test.sh smoke"
|
|
19
|
-
},
|
|
20
|
-
"files": [
|
|
21
|
-
"index.ts",
|
|
22
|
-
"bin/",
|
|
23
|
-
"src/",
|
|
24
|
-
"skills/",
|
|
25
|
-
"extractors/",
|
|
26
|
-
"CHANGELOG.md",
|
|
27
|
-
"README.md"
|
|
28
|
-
],
|
|
29
|
-
"pi": {
|
|
30
|
-
"extensions": [
|
|
31
|
-
"./index.ts"
|
|
32
|
-
],
|
|
33
|
-
"skills": [
|
|
34
|
-
"./skills"
|
|
35
|
-
]
|
|
36
|
-
},
|
|
37
|
-
"dependencies": {
|
|
38
|
-
"jsdom": "^24.0.0",
|
|
39
|
-
"@mozilla/readability": "^0.5.0",
|
|
40
|
-
"turndown": "^7.1.2"
|
|
41
|
-
},
|
|
42
|
-
"peerDependencies": {
|
|
43
|
-
"@mariozechner/pi-coding-agent": "*",
|
|
44
|
-
"@sinclair/typebox": "*"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@apmantza/greedysearch-pi",
|
|
3
|
+
"version": "1.7.4",
|
|
4
|
+
"description": "Pi extension: multi-engine AI search (Perplexity, Bing Copilot, Google AI) via browser automation -- NO API KEYS needed. Extracts answers with sources, optional Gemini synthesis. Grounded AI answers from real browser interactions.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"pi-package"
|
|
8
|
+
],
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/apmantza/GreedySearch-pi.git"
|
|
12
|
+
},
|
|
13
|
+
"author": "Apostolos Mantzaris",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "./test.sh",
|
|
17
|
+
"test:quick": "./test.sh quick",
|
|
18
|
+
"test:smoke": "./test.sh smoke"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"index.ts",
|
|
22
|
+
"bin/",
|
|
23
|
+
"src/",
|
|
24
|
+
"skills/",
|
|
25
|
+
"extractors/",
|
|
26
|
+
"CHANGELOG.md",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"pi": {
|
|
30
|
+
"extensions": [
|
|
31
|
+
"./index.ts"
|
|
32
|
+
],
|
|
33
|
+
"skills": [
|
|
34
|
+
"./skills"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"jsdom": "^24.0.0",
|
|
39
|
+
"@mozilla/readability": "^0.5.0",
|
|
40
|
+
"turndown": "^7.1.2"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@mariozechner/pi-coding-agent": "*",
|
|
44
|
+
"@sinclair/typebox": "*"
|
|
45
|
+
}
|
|
46
|
+
}
|