search-web-api 1.0.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 +307 -0
- package/demo/index.ts +38 -0
- package/demo/openapi.ts +402 -0
- package/demo/routes/autocomplete.ts +124 -0
- package/demo/routes/search.ts +61 -0
- package/docs/AUTOCOMPLETE.md +296 -0
- package/docs/CATEGORY_SEARCH.md +265 -0
- package/package.json +32 -0
- package/src/autocomplete/autocomplete-ai-next-word-predictor.ts +47 -0
- package/src/autocomplete/autocomplete-search-engine-backends.ts +231 -0
- package/src/category-registry.ts +6 -0
- package/src/config/search-engine-constants.ts +216 -0
- package/src/constants.ts +6 -0
- package/src/engine-descriptions.ts +7 -0
- package/src/engine-status.ts +7 -0
- package/src/engine.ts +6 -0
- package/src/registry/search-engine-category-registry.ts +200 -0
- package/src/registry/search-engine-descriptions.ts +121 -0
- package/src/registry/search-engine-status-tracker.ts +240 -0
- package/src/result-container.ts +8 -0
- package/src/search/search-engines-registry-list.ts +205 -0
- package/src/search/search-query-executor.ts +168 -0
- package/src/search/search-result-container.ts +421 -0
- package/src/search-web-types.ts +7 -0
- package/src/search.ts +10 -0
- package/src/sources/academic/arxiv.ts +72 -0
- package/src/sources/academic/core.ts +65 -0
- package/src/sources/academic/crossref.ts +75 -0
- package/src/sources/academic/doaj.ts +63 -0
- package/src/sources/academic/google_scholar.ts +53 -0
- package/src/sources/academic/openalex.ts +75 -0
- package/src/sources/academic/pubmed.ts +96 -0
- package/src/sources/academic/semantic_scholar.ts +77 -0
- package/src/sources/academic/wikidata.ts +44 -0
- package/src/sources/general/baidu.ts +59 -0
- package/src/sources/general/bing.ts +30 -0
- package/src/sources/general/brave.ts +54 -0
- package/src/sources/general/duckduckgo.ts +49 -0
- package/src/sources/general/google.ts +68 -0
- package/src/sources/general/mojeek.ts +56 -0
- package/src/sources/general/qwant.ts +37 -0
- package/src/sources/general/startpage.ts +44 -0
- package/src/sources/general/yahoo.ts +41 -0
- package/src/sources/general/yandex.ts +56 -0
- package/src/sources/images/bing_images.ts +68 -0
- package/src/sources/images/deviantart.ts +71 -0
- package/src/sources/images/flickr.ts +132 -0
- package/src/sources/images/google_images.ts +101 -0
- package/src/sources/images/imgur.ts +58 -0
- package/src/sources/images/openclipart.ts +52 -0
- package/src/sources/images/pixabay.ts +56 -0
- package/src/sources/images/unsplash.ts +38 -0
- package/src/sources/images/wallhaven.ts +50 -0
- package/src/sources/it/crates.ts +41 -0
- package/src/sources/it/dockerhub.ts +47 -0
- package/src/sources/it/github.ts +37 -0
- package/src/sources/it/gitlab.ts +55 -0
- package/src/sources/it/npm.ts +36 -0
- package/src/sources/it/packagist.ts +43 -0
- package/src/sources/it/pypi.ts +30 -0
- package/src/sources/it/rubygems.ts +43 -0
- package/src/sources/it/stackoverflow.ts +39 -0
- package/src/sources/maps/apple_maps.ts +105 -0
- package/src/sources/maps/openstreetmap.ts +34 -0
- package/src/sources/maps/photon.ts +77 -0
- package/src/sources/news/bing_news.ts +95 -0
- package/src/sources/news/google_news.ts +80 -0
- package/src/sources/news/hackernews.ts +94 -0
- package/src/sources/news/yahoo_news.ts +77 -0
- package/src/sources/shopping/ebay.ts +96 -0
- package/src/sources/social/mastodon.ts +46 -0
- package/src/sources/social/medium.ts +52 -0
- package/src/sources/social/reddit.ts +48 -0
- package/src/sources/social/soundcloud.ts +64 -0
- package/src/sources/social/twitter.ts +56 -0
- package/src/sources/specialized/annas_archive.ts +97 -0
- package/src/sources/specialized/archive.ts +48 -0
- package/src/sources/specialized/genius.ts +43 -0
- package/src/sources/specialized/goodreads.ts +62 -0
- package/src/sources/specialized/imdb.ts +55 -0
- package/src/sources/specialized/openlibrary.ts +59 -0
- package/src/sources/specialized/wikipedia.ts +37 -0
- package/src/sources/specialized/wttr.ts +98 -0
- package/src/sources/torrents/1337x.ts +43 -0
- package/src/sources/torrents/eztv.ts +47 -0
- package/src/sources/torrents/kickass.ts +63 -0
- package/src/sources/torrents/nyaa.ts +53 -0
- package/src/sources/torrents/solidtorrents.ts +68 -0
- package/src/sources/torrents/thepiratebay.ts +57 -0
- package/src/sources/torrents/yts.ts +54 -0
- package/src/sources/videos/bing_videos.ts +91 -0
- package/src/sources/videos/dailymotion.ts +101 -0
- package/src/sources/videos/invidious.ts +86 -0
- package/src/sources/videos/peertube.ts +76 -0
- package/src/sources/videos/vimeo.ts +67 -0
- package/src/sources/videos/youtube.ts +78 -0
- package/src/suggest-next-words/autocomplete-ai.ts +38 -0
- package/src/suggest-next-words/autocomplete-search-engines.ts +384 -0
- package/src/suggest-next-words/misspelled-typos-8k.json +1 -0
- package/src/types/search-engine-interface.ts +27 -0
- package/src/types/search-result-types.ts +405 -0
- package/test/api.test.ts +128 -0
- package/test/autocomplete-ai.test.ts +20 -0
- package/test/autocomplete-engines.test.ts +131 -0
- package/test/engine-health-suite.test.ts +350 -0
- package/test/search.test.ts +69 -0
- package/test/sources-unit.test.ts +1152 -0
- package/test/sources.test.ts +182 -0
- package/test/test-utils.ts +81 -0
- package/tsconfig.json +16 -0
- package/vitest.config.ts +20 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# Autocomplete API Documentation
|
|
2
|
+
|
|
3
|
+
The autocomplete module provides search query suggestions from multiple search engines, helping users quickly find what they're looking for.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **8 Search Engine Backends**: Google, DuckDuckGo, Brave, Wikipedia, Baidu, Qwant, Startpage, Yandex
|
|
8
|
+
- **Locale Support**: Most backends support different languages and regions
|
|
9
|
+
- **Multi-Backend Queries**: Combine suggestions from multiple engines
|
|
10
|
+
- **Fast Responses**: Optimized with 3-second timeout for quick results
|
|
11
|
+
|
|
12
|
+
## API Endpoints
|
|
13
|
+
|
|
14
|
+
### GET /autocomplete
|
|
15
|
+
|
|
16
|
+
Get autocomplete suggestions from a specific backend.
|
|
17
|
+
|
|
18
|
+
**Query Parameters:**
|
|
19
|
+
|
|
20
|
+
- `q` (required): Search query string
|
|
21
|
+
- `backend` (optional): Backend name (default: 'google')
|
|
22
|
+
- `locale` (optional): Language/locale code (default: 'en-US')
|
|
23
|
+
|
|
24
|
+
**Example:**
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
curl "http://localhost:3000/autocomplete?q=typescript&backend=google&locale=en-US"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Response:**
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"query": "typescript",
|
|
35
|
+
"backend": "google",
|
|
36
|
+
"locale": "en-US",
|
|
37
|
+
"suggestions": [
|
|
38
|
+
"typescript tutorial",
|
|
39
|
+
"typescript vs javascript",
|
|
40
|
+
"typescript generics",
|
|
41
|
+
"typescript interface",
|
|
42
|
+
"typescript types"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### GET /autocomplete/multi
|
|
48
|
+
|
|
49
|
+
Get autocomplete suggestions from multiple backends and merge them.
|
|
50
|
+
|
|
51
|
+
**Query Parameters:**
|
|
52
|
+
|
|
53
|
+
- `q` (required): Search query string
|
|
54
|
+
- `backends` (optional): Comma-separated backend names (default: 'google,duckduckgo')
|
|
55
|
+
- `locale` (optional): Language/locale code (default: 'en-US')
|
|
56
|
+
|
|
57
|
+
**Example:**
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
curl "http://localhost:3000/autocomplete/multi?q=python&backends=google,duckduckgo,wikipedia"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Response:**
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"query": "python",
|
|
68
|
+
"backends": ["google", "duckduckgo", "wikipedia"],
|
|
69
|
+
"locale": "en-US",
|
|
70
|
+
"count": 12,
|
|
71
|
+
"suggestions": [
|
|
72
|
+
"python tutorial",
|
|
73
|
+
"python download",
|
|
74
|
+
"python programming",
|
|
75
|
+
"python (programming language)",
|
|
76
|
+
"python snake",
|
|
77
|
+
...
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### GET /autocomplete/backends
|
|
83
|
+
|
|
84
|
+
List all available autocomplete backends.
|
|
85
|
+
|
|
86
|
+
**Example:**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
curl "http://localhost:3000/autocomplete/backends"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Response:**
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"backends": [
|
|
97
|
+
{
|
|
98
|
+
"name": "baidu",
|
|
99
|
+
"description": "Baidu (Chinese search engine)"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "brave",
|
|
103
|
+
"description": "Brave Search"
|
|
104
|
+
},
|
|
105
|
+
...
|
|
106
|
+
],
|
|
107
|
+
"count": 8
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Available Backends
|
|
112
|
+
|
|
113
|
+
| Backend | Description | Locale Support |
|
|
114
|
+
| -------------------- | ------------- | ---------------- |
|
|
115
|
+
| **google** | Google Search | Yes (subdomains) |
|
|
116
|
+
| **duckduckgo** | DuckDuckGo | Yes (regions) |
|
|
117
|
+
| **brave** | Brave Search | Limited |
|
|
118
|
+
| **wikipedia** | Wikipedia | Yes (languages) |
|
|
119
|
+
| **baidu** | Baidu | Chinese |
|
|
120
|
+
| **qwant** | Qwant | Yes (locales) |
|
|
121
|
+
| **startpage** | Startpage | Yes (languages) |
|
|
122
|
+
| **yandex** | Yandex | Russian |
|
|
123
|
+
|
|
124
|
+
## Programmatic Usage
|
|
125
|
+
|
|
126
|
+
### TypeScript/JavaScript
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { searchAutocomplete, searchAutocompleteMulti } from './app/lib/autocomplete';
|
|
130
|
+
|
|
131
|
+
// Single backend
|
|
132
|
+
const suggestions = await searchAutocomplete('google', 'typescript');
|
|
133
|
+
console.log(suggestions);
|
|
134
|
+
|
|
135
|
+
// Multiple backends
|
|
136
|
+
const merged = await searchAutocompleteMulti(
|
|
137
|
+
['google', 'duckduckgo', 'wikipedia'],
|
|
138
|
+
'javascript',
|
|
139
|
+
'en-US'
|
|
140
|
+
);
|
|
141
|
+
console.log(merged);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Individual Backend Functions
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { google, duckduckgo, wikipedia } from './app/lib/autocomplete';
|
|
148
|
+
|
|
149
|
+
// Google autocomplete
|
|
150
|
+
const googleSuggestions = await google('react', 'en-US');
|
|
151
|
+
|
|
152
|
+
// DuckDuckGo autocomplete
|
|
153
|
+
const ddgSuggestions = await duckduckgo('vue');
|
|
154
|
+
|
|
155
|
+
// Wikipedia autocomplete (German)
|
|
156
|
+
const wikiSuggestions = await wikipedia('quantum physics', 'de');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Locale Support
|
|
160
|
+
|
|
161
|
+
### Google
|
|
162
|
+
|
|
163
|
+
Google uses subdomains based on language:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// English (google.com)
|
|
167
|
+
await google('search query', 'en');
|
|
168
|
+
|
|
169
|
+
// German (google.de)
|
|
170
|
+
await google('Suchanfrage', 'de');
|
|
171
|
+
|
|
172
|
+
// French (google.fr)
|
|
173
|
+
await google('requête de recherche', 'fr');
|
|
174
|
+
|
|
175
|
+
// Japanese (google.co.jp)
|
|
176
|
+
await google('検索クエリ', 'ja');
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Wikipedia
|
|
180
|
+
|
|
181
|
+
Wikipedia uses language-specific domains:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// English Wikipedia
|
|
185
|
+
await wikipedia('physics', 'en');
|
|
186
|
+
|
|
187
|
+
// German Wikipedia
|
|
188
|
+
await wikipedia('Physik', 'de');
|
|
189
|
+
|
|
190
|
+
// French Wikipedia
|
|
191
|
+
await wikipedia('physique', 'fr');
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### DuckDuckGo
|
|
195
|
+
|
|
196
|
+
DuckDuckGo uses region codes:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
// US English
|
|
200
|
+
await duckduckgo('search', 'en-US');
|
|
201
|
+
|
|
202
|
+
// UK English
|
|
203
|
+
await duckduckgo('search', 'en-GB');
|
|
204
|
+
|
|
205
|
+
// German
|
|
206
|
+
await duckduckgo('Suche', 'de-DE');
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Implementation Details
|
|
210
|
+
|
|
211
|
+
### Response Timeout
|
|
212
|
+
|
|
213
|
+
All autocomplete requests have a 3-second timeout to ensure fast responses. If a backend doesn't respond within this time, an empty array is returned.
|
|
214
|
+
|
|
215
|
+
### Error Handling
|
|
216
|
+
|
|
217
|
+
Errors are caught and logged, but don't prevent the API from responding:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
try {
|
|
221
|
+
return await backend(query, locale);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error('Autocomplete error:', error);
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Deduplication
|
|
229
|
+
|
|
230
|
+
When using multi-backend queries, results are automatically deduplicated:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
const merged = new Set<string>();
|
|
234
|
+
for (const result of results) {
|
|
235
|
+
for (const suggestion of result) {
|
|
236
|
+
merged.add(suggestion);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return Array.from(merged);
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Examples
|
|
243
|
+
|
|
244
|
+
See `examples/autocomplete-example.ts` for comprehensive usage examples including:
|
|
245
|
+
|
|
246
|
+
1. Single backend autocomplete
|
|
247
|
+
2. Multi-backend queries
|
|
248
|
+
3. Locale-specific suggestions
|
|
249
|
+
4. Direct backend function calls
|
|
250
|
+
5. Comparing results across backends
|
|
251
|
+
6. Asian language autocomplete (Baidu, Yandex)
|
|
252
|
+
|
|
253
|
+
Run the examples:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
bun run examples/autocomplete-example.ts
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Performance Considerations
|
|
260
|
+
|
|
261
|
+
1. **Parallel Requests**: Multi-backend queries run in parallel using `Promise.all()`
|
|
262
|
+
2. **Fast Timeout**: 3-second timeout prevents slow backends from blocking
|
|
263
|
+
3. **Lightweight Parsing**: Minimal HTML parsing using linkedom for Google
|
|
264
|
+
4. **No Caching**: Suggestions are fresh on each request (can be added if needed)
|
|
265
|
+
|
|
266
|
+
## Future Enhancements
|
|
267
|
+
|
|
268
|
+
Potential improvements:
|
|
269
|
+
|
|
270
|
+
- [ ] Add caching layer for frequent queries
|
|
271
|
+
- [ ] Support for more backends (Bing, Yahoo, etc.)
|
|
272
|
+
- [ ] Ranked suggestions based on popularity
|
|
273
|
+
- [ ] User query history integration
|
|
274
|
+
- [ ] Personalized suggestions
|
|
275
|
+
- [ ] A/B testing different backends
|
|
276
|
+
|
|
277
|
+
## Troubleshooting
|
|
278
|
+
|
|
279
|
+
### No suggestions returned
|
|
280
|
+
|
|
281
|
+
1. Check if the backend is supported: `GET /autocomplete/backends`
|
|
282
|
+
2. Verify the query is not empty
|
|
283
|
+
3. Check network connectivity
|
|
284
|
+
4. Try a different backend
|
|
285
|
+
|
|
286
|
+
### Slow responses
|
|
287
|
+
|
|
288
|
+
1. Use single backend instead of multi-backend
|
|
289
|
+
2. Check backend-specific issues (rate limiting, etc.)
|
|
290
|
+
3. Consider implementing caching
|
|
291
|
+
|
|
292
|
+
### Locale not working
|
|
293
|
+
|
|
294
|
+
1. Verify locale format (e.g., 'en-US', 'de-DE')
|
|
295
|
+
2. Check if backend supports the locale
|
|
296
|
+
3. Refer to backend-specific locale documentation above
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# Category-Based Search with Weighted Ranking
|
|
2
|
+
|
|
3
|
+
This document explains how the TypeScript search API implements category-based search with weighted ranking, based on the Python SearXNG implementation.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The search API now supports:
|
|
8
|
+
|
|
9
|
+
- **Multi-category search**: Search across specific categories (general, news, academic, etc.)
|
|
10
|
+
- **Result combination**: Automatically combine and deduplicate results from multiple engines
|
|
11
|
+
- **Weighted ranking**: Score results based on engine quality, category importance, and position
|
|
12
|
+
- **Category grouping**: Results are grouped by category for better organization
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
### Key Components
|
|
17
|
+
|
|
18
|
+
1. **CategoryRegistry** (`app/lib/category-registry.ts`)
|
|
19
|
+
|
|
20
|
+
- Manages engines organized by category
|
|
21
|
+
- Supports 13 categories: general, images, videos, news, maps, music, it, academic, social, files, torrents, shopping, specialized
|
|
22
|
+
- Each category has configurable default weights
|
|
23
|
+
|
|
24
|
+
2. **ResultContainer** (`app/lib/result-container.ts`)
|
|
25
|
+
|
|
26
|
+
- Deduplicates results by URL hash
|
|
27
|
+
- Merges duplicate results from different engines
|
|
28
|
+
- Calculates weighted scores
|
|
29
|
+
- Groups results by category
|
|
30
|
+
|
|
31
|
+
3. **Search Class** (`app/lib/search.ts`)
|
|
32
|
+
- Main search interface
|
|
33
|
+
- Queries multiple engines in parallel
|
|
34
|
+
- Applies category and engine filters
|
|
35
|
+
- Returns combined, scored, and sorted results
|
|
36
|
+
|
|
37
|
+
## How Scoring Works
|
|
38
|
+
|
|
39
|
+
The scoring algorithm is based on SearXNG's Python implementation:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
score = Σ (weight / position) for each position
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Where:
|
|
46
|
+
|
|
47
|
+
- **weight** = `base_weight × engine_weight × category_weight × num_occurrences`
|
|
48
|
+
- **position**: The position of the result in the engine's results (1st, 2nd, 3rd, etc.)
|
|
49
|
+
- **num_occurrences**: How many engines found this result
|
|
50
|
+
|
|
51
|
+
### Engine Weights
|
|
52
|
+
|
|
53
|
+
Higher quality engines get higher weights:
|
|
54
|
+
|
|
55
|
+
- Google: 1.5
|
|
56
|
+
- Bing: 1.3
|
|
57
|
+
- DuckDuckGo: 1.2
|
|
58
|
+
- Google Scholar: 1.4
|
|
59
|
+
- Semantic Scholar: 1.3
|
|
60
|
+
- Default: 1.0
|
|
61
|
+
|
|
62
|
+
### Category Weights
|
|
63
|
+
|
|
64
|
+
Different categories can have different importance:
|
|
65
|
+
|
|
66
|
+
- Academic: 1.3 (higher credibility)
|
|
67
|
+
- IT: 1.2 (technical accuracy)
|
|
68
|
+
- News: 1.1
|
|
69
|
+
- Social: 0.9 (lower due to potential duplicates)
|
|
70
|
+
- Torrents: 0.8 (lower due to potential spam)
|
|
71
|
+
- Default: 1.0
|
|
72
|
+
|
|
73
|
+
### Example Score Calculation
|
|
74
|
+
|
|
75
|
+
If a result appears at:
|
|
76
|
+
|
|
77
|
+
- Position 1 in Google (weight 1.5)
|
|
78
|
+
- Position 3 in Bing (weight 1.3)
|
|
79
|
+
- Category: general (weight 1.0)
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
score = (1.5 × 1.0 × 2 / 1) + (1.3 × 1.0 × 2 / 3)
|
|
83
|
+
= 3.0 + 0.87
|
|
84
|
+
= 3.87
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The multiplier of 2 is because the result appeared in 2 engines.
|
|
88
|
+
|
|
89
|
+
## Usage Examples
|
|
90
|
+
|
|
91
|
+
### 1. Search a Single Category
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { Search } from "./app/lib/search.js";
|
|
95
|
+
|
|
96
|
+
const search = new Search();
|
|
97
|
+
|
|
98
|
+
// Search only general web engines
|
|
99
|
+
const results = await search.searchByCategories("typescript", ["general"]);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 2. Search Multiple Categories
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Search across general, IT, and academic categories
|
|
106
|
+
const results = await search.searchByCategories("machine learning", [
|
|
107
|
+
"general",
|
|
108
|
+
"it",
|
|
109
|
+
"academic",
|
|
110
|
+
]);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 3. Use the Standard Search with Category Filter
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// More explicit control
|
|
117
|
+
const results = await search.search(
|
|
118
|
+
"climate change",
|
|
119
|
+
1, // page number
|
|
120
|
+
undefined, // engine names
|
|
121
|
+
["news", "general"] // categories
|
|
122
|
+
);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 4. Search Specific Engines
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// Search only specific engines
|
|
129
|
+
const results = await search.search(
|
|
130
|
+
"nodejs",
|
|
131
|
+
1,
|
|
132
|
+
["google", "duckduckgo", "github"] // specific engines
|
|
133
|
+
);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Available Categories
|
|
137
|
+
|
|
138
|
+
| Category | Description | Default Weight | Example Engines |
|
|
139
|
+
| ----------- | ------------------- | -------------- | ---------------------------------- |
|
|
140
|
+
| general | General web search | 1.0 | Google, Bing, DuckDuckGo |
|
|
141
|
+
| images | Image search | 1.0 | Unsplash, Bing Images, Flickr |
|
|
142
|
+
| videos | Video search | 1.0 | YouTube, Vimeo, Dailymotion |
|
|
143
|
+
| news | News search | 1.1 | Google News, HackerNews, Bing News |
|
|
144
|
+
| maps | Maps and locations | 1.0 | OpenStreetMap, Photon |
|
|
145
|
+
| it | Programming/IT | 1.2 | GitHub, StackOverflow, NPM |
|
|
146
|
+
| academic | Scientific papers | 1.3 | Google Scholar, arXiv, PubMed |
|
|
147
|
+
| social | Social media | 0.9 | Reddit, Twitter, Mastodon |
|
|
148
|
+
| torrents | Torrent search | 0.8 | 1337x, ThePirateBay, YTS |
|
|
149
|
+
| shopping | Shopping | 1.0 | eBay |
|
|
150
|
+
| specialized | Specialized engines | 1.1 | Wikipedia, IMDB, Genius |
|
|
151
|
+
|
|
152
|
+
## Result Deduplication
|
|
153
|
+
|
|
154
|
+
Results with the same URL (normalized) are automatically merged:
|
|
155
|
+
|
|
156
|
+
1. **URL normalization**: Removes protocol, www, trailing slashes
|
|
157
|
+
2. **Title matching**: Includes partial title match for disambiguation
|
|
158
|
+
3. **Result merging**:
|
|
159
|
+
- Combines engine names
|
|
160
|
+
- Tracks all positions
|
|
161
|
+
- Uses longer content/title
|
|
162
|
+
- Prefers HTTPS URLs
|
|
163
|
+
- Accumulates scores from all engines
|
|
164
|
+
|
|
165
|
+
Example:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
Result from Google at position 1
|
|
169
|
+
+ Same URL from Bing at position 2
|
|
170
|
+
= Merged result with:
|
|
171
|
+
- engines: ['google', 'bing']
|
|
172
|
+
- positions: [1, 2]
|
|
173
|
+
- Higher combined score
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Category Grouping
|
|
177
|
+
|
|
178
|
+
Results are grouped by category in the final output:
|
|
179
|
+
|
|
180
|
+
1. **First pass**: Sort all results by score (descending)
|
|
181
|
+
2. **Second pass**: Group similar categories together
|
|
182
|
+
- Maximum 8 results per group
|
|
183
|
+
- Maximum distance of 20 positions to look back
|
|
184
|
+
- Groups by: category + template + has_image
|
|
185
|
+
|
|
186
|
+
This ensures related results appear together while maintaining score-based relevance.
|
|
187
|
+
|
|
188
|
+
## API Reference
|
|
189
|
+
|
|
190
|
+
### Search Class Methods
|
|
191
|
+
|
|
192
|
+
#### `search(query, pageno, engineNames?, categories?)`
|
|
193
|
+
|
|
194
|
+
Main search method with full control.
|
|
195
|
+
|
|
196
|
+
**Parameters:**
|
|
197
|
+
|
|
198
|
+
- `query`: Search query string
|
|
199
|
+
- `pageno`: Page number (default: 1)
|
|
200
|
+
- `engineNames`: Optional array of specific engine names
|
|
201
|
+
- `categories`: Optional array of category names
|
|
202
|
+
|
|
203
|
+
**Returns:** `Promise<MergedResult[]>`
|
|
204
|
+
|
|
205
|
+
#### `searchByCategories(query, categories, pageno?)`
|
|
206
|
+
|
|
207
|
+
Convenience method for multi-category search.
|
|
208
|
+
|
|
209
|
+
**Parameters:**
|
|
210
|
+
|
|
211
|
+
- `query`: Search query string
|
|
212
|
+
- `categories`: Array of category names
|
|
213
|
+
- `pageno`: Page number (default: 1)
|
|
214
|
+
|
|
215
|
+
**Returns:** `Promise<MergedResult[]>`
|
|
216
|
+
|
|
217
|
+
#### `getCategories()`
|
|
218
|
+
|
|
219
|
+
Get list of available categories.
|
|
220
|
+
|
|
221
|
+
**Returns:** `string[]`
|
|
222
|
+
|
|
223
|
+
#### `getEnginesByCategory(category)`
|
|
224
|
+
|
|
225
|
+
Get engines for a specific category.
|
|
226
|
+
|
|
227
|
+
**Parameters:**
|
|
228
|
+
|
|
229
|
+
- `category`: Category name
|
|
230
|
+
|
|
231
|
+
**Returns:** `Engine[]`
|
|
232
|
+
|
|
233
|
+
#### `getCategoryStats()`
|
|
234
|
+
|
|
235
|
+
Get statistics about engines and categories.
|
|
236
|
+
|
|
237
|
+
**Returns:** Object with category statistics
|
|
238
|
+
|
|
239
|
+
### MergedResult Interface
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
interface MergedResult {
|
|
243
|
+
url?: string;
|
|
244
|
+
title: string;
|
|
245
|
+
content: string;
|
|
246
|
+
engines: string[]; // List of engines that found this result
|
|
247
|
+
positions: number[]; // Positions in each engine's results
|
|
248
|
+
score: number; // Calculated weighted score
|
|
249
|
+
priority: "low" | "normal" | "high";
|
|
250
|
+
category?: string; // Primary category
|
|
251
|
+
template?: string; // Result template type
|
|
252
|
+
thumbnail?: string;
|
|
253
|
+
publishedDate?: string;
|
|
254
|
+
author?: string;
|
|
255
|
+
// ... other fields
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Performance Considerations
|
|
260
|
+
|
|
261
|
+
1. **Parallel execution**: All engines are queried in parallel using `Promise.all()`
|
|
262
|
+
2. **Health tracking**: Unhealthy engines are automatically skipped
|
|
263
|
+
3. **Timeout handling**: Individual engine timeouts don't block the overall search
|
|
264
|
+
4. **Deduplication**: Hash-based deduplication is O(1) using Map
|
|
265
|
+
5. **Sorting**: Results are sorted once using efficient native sort
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "search-web-api",
|
|
3
|
+
"description": "70+ search engines across 10 categories and Scrape Extract API",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "1.0.13",
|
|
6
|
+
"author": "vtempest",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/OpenSourceAGI/qwksearch-research-agent.git",
|
|
11
|
+
"directory": "packages/search-web-api"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"dev": "bun --watch demo/index.ts",
|
|
15
|
+
"start": "bun demo/index.ts",
|
|
16
|
+
"test": "vitest run"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@huggingface/transformers": "^3.8.1",
|
|
20
|
+
"@scalar/hono-api-reference": "^0.9.26",
|
|
21
|
+
"grab-url": "^1.0.8",
|
|
22
|
+
"hono": "^4.6.12",
|
|
23
|
+
"linkedom": "^0.18.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^25.9.3",
|
|
27
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
28
|
+
"tsx": "^4.7.1",
|
|
29
|
+
"typescript": "^5.9.3",
|
|
30
|
+
"vitest": "^4.0.18"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autocomplete AI Next-Word Predictor — Local, CPU-based next-word prediction
|
|
3
|
+
* using the Xenova/distilgpt2 model via the Hugging Face Transformers.js library.
|
|
4
|
+
* DistilGPT-2 is a distilled 82 M-parameter variant of GPT-2 (~80 MB) that
|
|
5
|
+
* runs efficiently on CPU with FP16 precision and is well-suited for lightweight
|
|
6
|
+
* inline query completion without any network calls.
|
|
7
|
+
*
|
|
8
|
+
* @see https://huggingface.co/Xenova/distilgpt2
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { pipeline, type TextGenerationSingle } from "@huggingface/transformers";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Predict the next words for a given text prompt using a small local language model.
|
|
15
|
+
*
|
|
16
|
+
* @param prompt - The input text to continue.
|
|
17
|
+
* @param options.maxTokens - Maximum number of new tokens to generate (default 16).
|
|
18
|
+
* @param options.model - Hugging Face model ID to use (default `"Xenova/distilgpt2"`).
|
|
19
|
+
* @param options.modelParams - Additional pipeline constructor options.
|
|
20
|
+
* @returns The generated continuation text with the original prompt removed.
|
|
21
|
+
*/
|
|
22
|
+
export async function predictNextWordsWithSmallLocalModel(
|
|
23
|
+
prompt: string,
|
|
24
|
+
{
|
|
25
|
+
model = "Xenova/distilgpt2",
|
|
26
|
+
maxTokens = 16,
|
|
27
|
+
modelParams = {},
|
|
28
|
+
}: {
|
|
29
|
+
model?: string;
|
|
30
|
+
maxTokens?: number;
|
|
31
|
+
modelParams?: Record<string, unknown>;
|
|
32
|
+
} = {},
|
|
33
|
+
): Promise<string> {
|
|
34
|
+
if (!prompt) throw new Error("Prompt is required");
|
|
35
|
+
|
|
36
|
+
const generator = await pipeline("text-generation", model, {
|
|
37
|
+
dtype: "fp16",
|
|
38
|
+
device: "cpu",
|
|
39
|
+
...modelParams,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return (await generator(prompt, { max_new_tokens: maxTokens }))
|
|
43
|
+
.map((res) => (res as TextGenerationSingle).generated_text)
|
|
44
|
+
.join(" ")
|
|
45
|
+
.replace(prompt, "")
|
|
46
|
+
.trim();
|
|
47
|
+
}
|