spectrawl 0.3.11 → 0.3.13
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/README.md +11 -6
- package/package.json +1 -1
- package/src/search/index.js +17 -8
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The unified web layer for AI agents. Search, browse, authenticate, and act on platforms — one tool, self-hosted, free.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**5,000 free searches/month** with Google-quality results via Gemini Grounded Search. Better answers than Tavily. Self-hosted.
|
|
6
6
|
|
|
7
7
|
## What It Does
|
|
8
8
|
|
|
@@ -57,18 +57,23 @@ export GEMINI_API_KEY=your-free-key # Get one at aistudio.google.com
|
|
|
57
57
|
const { Spectrawl } = require('spectrawl')
|
|
58
58
|
const web = new Spectrawl()
|
|
59
59
|
|
|
60
|
-
// Deep search —
|
|
60
|
+
// Deep search — returns sources for your agent/LLM to process
|
|
61
61
|
const result = await web.deepSearch('how to build an MCP server in Node.js')
|
|
62
|
-
console.log(result.answer) // AI-generated answer with [1] [2] citations
|
|
63
62
|
console.log(result.sources) // [{ title, url, content, score }]
|
|
64
63
|
|
|
64
|
+
// With AI summary (opt-in — uses extra Gemini call)
|
|
65
|
+
const withAnswer = await web.deepSearch('query', { summarize: true })
|
|
66
|
+
console.log(withAnswer.answer) // AI-generated answer with [1] [2] citations
|
|
67
|
+
|
|
65
68
|
// Fast mode — snippets only, skip scraping
|
|
66
69
|
const fast = await web.deepSearch('query', { mode: 'fast' })
|
|
67
70
|
|
|
68
|
-
// Basic search — raw results
|
|
71
|
+
// Basic search — raw results
|
|
69
72
|
const basic = await web.search('query')
|
|
70
73
|
```
|
|
71
74
|
|
|
75
|
+
> **Why no summary by default?** Your agent already has an LLM. If we summarize AND your agent summarizes, you're paying two LLMs for one answer. We return rich sources — your agent does the rest.
|
|
76
|
+
|
|
72
77
|
## vs Tavily
|
|
73
78
|
|
|
74
79
|
| | Tavily | Spectrawl |
|
|
@@ -77,7 +82,7 @@ const basic = await web.search('query')
|
|
|
77
82
|
| Answer quality | Generic (3 items) | **Detailed** (12+ items) ✅ |
|
|
78
83
|
| Inline citations | ❌ | **[1] [2] [3]** ✅ |
|
|
79
84
|
| Results per query | 10 | **12-19** ✅ |
|
|
80
|
-
| Cost | $0.01/query | **Free** ✅ |
|
|
85
|
+
| Cost | $0.01/query | **Free** (5K/mo) ✅ |
|
|
81
86
|
| Self-hosted | No | **Yes** ✅ |
|
|
82
87
|
| Source ranking | No | **Domain trust scoring** ✅ |
|
|
83
88
|
| Stealth scraping | No | **Yes** ✅ |
|
|
@@ -110,7 +115,7 @@ Query → Gemini Grounded + DDG (parallel)
|
|
|
110
115
|
→ Merge & deduplicate (12-19 results)
|
|
111
116
|
→ Source quality ranking (boost GitHub/SO/Reddit, penalize SEO spam)
|
|
112
117
|
→ Parallel scraping (Jina → readability → Playwright fallback)
|
|
113
|
-
→
|
|
118
|
+
→ Returns sources to your agent (AI summary opt-in with summarize: true)
|
|
114
119
|
```
|
|
115
120
|
|
|
116
121
|
### What you get without any keys
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spectrawl",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.13",
|
|
4
4
|
"description": "The unified web layer for AI agents. Search (6 engines), stealth browse (Camoufox + Playwright), auth (cookies, multi-account), act (24 adapters, 30+ platforms), proxy rotation. Self-hosted, free.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "index.d.ts",
|
package/src/search/index.js
CHANGED
|
@@ -37,6 +37,13 @@ class SearchEngine {
|
|
|
37
37
|
this.reranker = geminiKey ? new Reranker({ apiKey: geminiKey, ...config.reranker }) : null
|
|
38
38
|
this.expander = geminiKey ? new QueryExpander({ apiKey: geminiKey, ...config.expander }) : null
|
|
39
39
|
this.sourceRanker = new SourceRanker(config.sourceRanker || {})
|
|
40
|
+
|
|
41
|
+
// One-time warning if no Gemini key
|
|
42
|
+
if (!geminiKey && !SearchEngine._keyWarned) {
|
|
43
|
+
SearchEngine._keyWarned = true
|
|
44
|
+
console.warn('\n⚠️ No GEMINI_API_KEY set. Using DDG fallback (limited quality, unreliable from servers).')
|
|
45
|
+
console.warn(' Get a free key (no credit card): https://aistudio.google.com/apikey\n')
|
|
46
|
+
}
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
/**
|
|
@@ -188,16 +195,18 @@ class SearchEngine {
|
|
|
188
195
|
}
|
|
189
196
|
}
|
|
190
197
|
|
|
191
|
-
// Step 6: Summarize with citations
|
|
198
|
+
// Step 6: Summarize with citations (opt-in — most agents have their own LLM)
|
|
192
199
|
let answer = null
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
200
|
+
if (opts.summarize === true) {
|
|
201
|
+
const summarizer = this.summarizer || (process.env.GEMINI_API_KEY ? new Summarizer({
|
|
202
|
+
provider: 'gemini',
|
|
203
|
+
model: 'gemini-2.5-flash',
|
|
204
|
+
apiKey: process.env.GEMINI_API_KEY
|
|
205
|
+
}) : null)
|
|
198
206
|
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
if (summarizer) {
|
|
208
|
+
answer = await summarizer.summarize(query, results)
|
|
209
|
+
}
|
|
201
210
|
}
|
|
202
211
|
|
|
203
212
|
const response = {
|