nosible 0.1.5
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 +438 -0
- package/dist/index.cjs +1841 -0
- package/dist/index.cjs.map +29 -0
- package/dist/index.js +1815 -0
- package/dist/index.js.map +29 -0
- package/package.json +63 -0
- package/src/api/api.test.ts +366 -0
- package/src/api/index.ts +179 -0
- package/src/api/schemas.ts +152 -0
- package/src/client.test.ts +685 -0
- package/src/client.ts +762 -0
- package/src/index.ts +4 -0
- package/src/scrape/types.ts +119 -0
- package/src/scrape/webPageData.test.ts +302 -0
- package/src/scrape/webPageData.ts +103 -0
- package/src/search/analyze.test.ts +396 -0
- package/src/search/analyze.ts +151 -0
- package/src/search/bulkSearch.ts +62 -0
- package/src/search/result.test.ts +423 -0
- package/src/search/result.ts +391 -0
- package/src/search/result.types.ts +32 -0
- package/src/search/resultFactory.ts +21 -0
- package/src/search/resultSet.io.test.ts +320 -0
- package/src/search/resultSet.test.ts +368 -0
- package/src/search/resultSet.ts +387 -0
- package/src/search/resultSet.types.ts +3 -0
- package/src/search/search.test.ts +299 -0
- package/src/search/search.ts +187 -0
- package/src/search/searchSet.io.test.ts +321 -0
- package/src/search/searchSet.ts +122 -0
- package/src/search/sqlFilter.test.ts +129 -0
- package/src/search/sqlFilter.ts +147 -0
- package/src/test-utils/mocks.ts +159 -0
- package/src/topicTrend/topicTrend.ts +53 -0
- package/src/utils/browser.test.ts +209 -0
- package/src/utils/browser.ts +21 -0
- package/src/utils/fernet.ts +47 -0
- package/src/utils/file.test.ts +81 -0
- package/src/utils/file.ts +195 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/llm.test.ts +279 -0
- package/src/utils/llm.ts +244 -0
- package/src/utils/userPlan.test.ts +332 -0
- package/src/utils/userPlan.ts +211 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1841 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
19
|
+
var __toCommonJS = (from) => {
|
|
20
|
+
var entry = __moduleCache.get(from), desc;
|
|
21
|
+
if (entry)
|
|
22
|
+
return entry;
|
|
23
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
24
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
25
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
26
|
+
get: () => from[key],
|
|
27
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
28
|
+
}));
|
|
29
|
+
__moduleCache.set(from, entry);
|
|
30
|
+
return entry;
|
|
31
|
+
};
|
|
32
|
+
var __export = (target, all) => {
|
|
33
|
+
for (var name in all)
|
|
34
|
+
__defProp(target, name, {
|
|
35
|
+
get: all[name],
|
|
36
|
+
enumerable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
set: (newValue) => all[name] = () => newValue
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/index.ts
|
|
43
|
+
var exports_src = {};
|
|
44
|
+
__export(exports_src, {
|
|
45
|
+
Search: () => Search,
|
|
46
|
+
NosibleClient: () => NosibleClient
|
|
47
|
+
});
|
|
48
|
+
module.exports = __toCommonJS(exports_src);
|
|
49
|
+
|
|
50
|
+
// src/search/sqlFilter.ts
|
|
51
|
+
var import_zod = __toESM(require("zod"));
|
|
52
|
+
var sqlFilterSchema = import_zod.default.object({
|
|
53
|
+
publishStart: import_zod.default.date().optional(),
|
|
54
|
+
publishEnd: import_zod.default.date().optional(),
|
|
55
|
+
visitedStart: import_zod.default.date().optional(),
|
|
56
|
+
visitedEnd: import_zod.default.date().optional(),
|
|
57
|
+
certain: import_zod.default.boolean().optional(),
|
|
58
|
+
includeNetlocs: import_zod.default.array(import_zod.default.string()).max(50).optional(),
|
|
59
|
+
excludeNetlocs: import_zod.default.array(import_zod.default.string()).max(50).optional(),
|
|
60
|
+
includeCompanies: import_zod.default.array(import_zod.default.string()).max(50).optional(),
|
|
61
|
+
excludeCompanies: import_zod.default.array(import_zod.default.string()).max(50).optional(),
|
|
62
|
+
includeDocs: import_zod.default.array(import_zod.default.string()).max(50).optional(),
|
|
63
|
+
excludeDocs: import_zod.default.array(import_zod.default.string()).max(50).optional()
|
|
64
|
+
});
|
|
65
|
+
function generateSqlFilter(input) {
|
|
66
|
+
const validatedInput = sqlFilterSchema.parse(input);
|
|
67
|
+
const {
|
|
68
|
+
publishStart,
|
|
69
|
+
publishEnd,
|
|
70
|
+
visitedStart,
|
|
71
|
+
visitedEnd,
|
|
72
|
+
certain,
|
|
73
|
+
includeNetlocs,
|
|
74
|
+
excludeNetlocs,
|
|
75
|
+
includeCompanies,
|
|
76
|
+
excludeCompanies,
|
|
77
|
+
includeDocs,
|
|
78
|
+
excludeDocs
|
|
79
|
+
} = validatedInput;
|
|
80
|
+
const sql = ["SELECT loc FROM engine"];
|
|
81
|
+
const clauses = [];
|
|
82
|
+
if (publishStart || publishEnd) {
|
|
83
|
+
if (publishStart && publishEnd) {
|
|
84
|
+
clauses.push(`published >= '${publishStart.toISOString()}' AND published <= '${publishEnd.toISOString()}'`);
|
|
85
|
+
} else if (publishStart) {
|
|
86
|
+
clauses.push(`published >= '${publishStart.toISOString()}'`);
|
|
87
|
+
} else if (publishEnd) {
|
|
88
|
+
clauses.push(`published <= '${publishEnd.toISOString()}'`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (visitedStart || visitedEnd) {
|
|
92
|
+
if (visitedStart && visitedEnd) {
|
|
93
|
+
clauses.push(`visited >= '${visitedStart.toISOString()}' AND visited <= '${visitedEnd.toISOString()}'`);
|
|
94
|
+
} else if (visitedStart) {
|
|
95
|
+
clauses.push(`visited >= '${visitedStart.toISOString()}'`);
|
|
96
|
+
} else if (visitedEnd) {
|
|
97
|
+
clauses.push(`visited <= '${visitedEnd.toISOString()}'`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (certain === true) {
|
|
101
|
+
clauses.push("certain = TRUE");
|
|
102
|
+
} else if (certain === false) {
|
|
103
|
+
clauses.push("certain = FALSE");
|
|
104
|
+
}
|
|
105
|
+
if (includeNetlocs) {
|
|
106
|
+
const variants = new Set;
|
|
107
|
+
for (const n of includeNetlocs) {
|
|
108
|
+
variants.add(n);
|
|
109
|
+
if (n.startsWith("www.")) {
|
|
110
|
+
variants.add(n.slice(4));
|
|
111
|
+
} else {
|
|
112
|
+
variants.add("www." + n);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const inList = Array.from(variants).sort().map((v) => `'${v}'`).join(", ");
|
|
116
|
+
clauses.push(`netloc IN (${inList})`);
|
|
117
|
+
}
|
|
118
|
+
if (excludeNetlocs) {
|
|
119
|
+
const variants = new Set;
|
|
120
|
+
for (const n of excludeNetlocs) {
|
|
121
|
+
variants.add(n);
|
|
122
|
+
if (n.startsWith("www.")) {
|
|
123
|
+
variants.add(n.slice(4));
|
|
124
|
+
} else {
|
|
125
|
+
variants.add("www." + n);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const exList = Array.from(variants).sort().map((v) => `'${v}'`).join(", ");
|
|
129
|
+
clauses.push(`netloc NOT IN (${exList})`);
|
|
130
|
+
}
|
|
131
|
+
if (includeCompanies) {
|
|
132
|
+
const companyList = includeCompanies.map((c) => `ARRAY_CONTAINS(companies, '${c}')`).join(" OR ");
|
|
133
|
+
clauses.push(`(companies IS NOT NULL AND (${companyList}))`);
|
|
134
|
+
}
|
|
135
|
+
if (excludeCompanies) {
|
|
136
|
+
const companyList = excludeCompanies.map((c) => `ARRAY_CONTAINS(companies, '${c}')`).join(" OR ");
|
|
137
|
+
clauses.push(`(companies IS NULL OR NOT (${companyList}))`);
|
|
138
|
+
}
|
|
139
|
+
if (includeDocs) {
|
|
140
|
+
const docHashes = includeDocs.map((doc) => `'${doc}'`).join(", ");
|
|
141
|
+
clauses.push(`doc_hash IN (${docHashes})`);
|
|
142
|
+
}
|
|
143
|
+
if (excludeDocs) {
|
|
144
|
+
const docHashes = excludeDocs.map((doc) => `'${doc}'`).join(", ");
|
|
145
|
+
clauses.push(`doc_hash NOT IN (${docHashes})`);
|
|
146
|
+
}
|
|
147
|
+
if (clauses.length > 0) {
|
|
148
|
+
sql.push("WHERE " + clauses.join(" AND "));
|
|
149
|
+
}
|
|
150
|
+
if (sql.length === 1) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const sqlFilter = sql.join(" ");
|
|
154
|
+
return sqlFilter;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/search/search.ts
|
|
158
|
+
var import_zod5 = require("zod");
|
|
159
|
+
|
|
160
|
+
// src/api/schemas.ts
|
|
161
|
+
var import_zod3 = __toESM(require("zod"));
|
|
162
|
+
|
|
163
|
+
// src/scrape/types.ts
|
|
164
|
+
var import_zod2 = require("zod");
|
|
165
|
+
var snippetStatisticsSchema = import_zod2.z.object({
|
|
166
|
+
sentences: import_zod2.z.number(),
|
|
167
|
+
words: import_zod2.z.number(),
|
|
168
|
+
characters: import_zod2.z.number(),
|
|
169
|
+
links: import_zod2.z.number().optional(),
|
|
170
|
+
images: import_zod2.z.number().optional()
|
|
171
|
+
});
|
|
172
|
+
var snippetSchema = import_zod2.z.object({
|
|
173
|
+
url_hash: import_zod2.z.string(),
|
|
174
|
+
snippet_hash: import_zod2.z.string(),
|
|
175
|
+
prev_snippet_hash: import_zod2.z.string().nullable(),
|
|
176
|
+
next_snippet_hash: import_zod2.z.string().nullable(),
|
|
177
|
+
content: import_zod2.z.string(),
|
|
178
|
+
words: import_zod2.z.string().optional(),
|
|
179
|
+
language: import_zod2.z.string(),
|
|
180
|
+
statistics: snippetStatisticsSchema.optional(),
|
|
181
|
+
links: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional(),
|
|
182
|
+
images: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
183
|
+
});
|
|
184
|
+
var scrapeStatisticsSchema = import_zod2.z.object({
|
|
185
|
+
snippets: import_zod2.z.number(),
|
|
186
|
+
sentences: import_zod2.z.number(),
|
|
187
|
+
words: import_zod2.z.number(),
|
|
188
|
+
characters: import_zod2.z.number(),
|
|
189
|
+
images: import_zod2.z.number(),
|
|
190
|
+
videos: import_zod2.z.number(),
|
|
191
|
+
audio: import_zod2.z.number(),
|
|
192
|
+
tables: import_zod2.z.number(),
|
|
193
|
+
lists: import_zod2.z.number(),
|
|
194
|
+
blocks: import_zod2.z.number(),
|
|
195
|
+
links: import_zod2.z.number(),
|
|
196
|
+
files: import_zod2.z.number()
|
|
197
|
+
});
|
|
198
|
+
var scrapePageSchema = import_zod2.z.object({
|
|
199
|
+
title: import_zod2.z.string(),
|
|
200
|
+
description: import_zod2.z.string(),
|
|
201
|
+
author: import_zod2.z.string(),
|
|
202
|
+
published: import_zod2.z.coerce.date(),
|
|
203
|
+
visited: import_zod2.z.coerce.date(),
|
|
204
|
+
certain: import_zod2.z.boolean().optional()
|
|
205
|
+
});
|
|
206
|
+
var querySchema = import_zod2.z.object({});
|
|
207
|
+
var scrapeRequestSchema = import_zod2.z.object({
|
|
208
|
+
raw_url: import_zod2.z.string(),
|
|
209
|
+
url: import_zod2.z.string(),
|
|
210
|
+
hash: import_zod2.z.string(),
|
|
211
|
+
geo: import_zod2.z.string(),
|
|
212
|
+
proxy: import_zod2.z.string(),
|
|
213
|
+
scheme: import_zod2.z.string(),
|
|
214
|
+
netloc: import_zod2.z.string(),
|
|
215
|
+
prefix: import_zod2.z.string(),
|
|
216
|
+
domain: import_zod2.z.string(),
|
|
217
|
+
suffix: import_zod2.z.string(),
|
|
218
|
+
path: import_zod2.z.string(),
|
|
219
|
+
query: import_zod2.z.string(),
|
|
220
|
+
fragment: import_zod2.z.string(),
|
|
221
|
+
query_allowed: querySchema,
|
|
222
|
+
query_blocked: querySchema
|
|
223
|
+
});
|
|
224
|
+
var metadataSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.any());
|
|
225
|
+
var logoSchema = import_zod2.z.object({
|
|
226
|
+
"@type": import_zod2.z.string().optional(),
|
|
227
|
+
"@id": import_zod2.z.string().optional(),
|
|
228
|
+
caption: import_zod2.z.string().optional(),
|
|
229
|
+
inLanguage: import_zod2.z.string().optional(),
|
|
230
|
+
url: import_zod2.z.string(),
|
|
231
|
+
width: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number()]).optional(),
|
|
232
|
+
height: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number()]).optional()
|
|
233
|
+
});
|
|
234
|
+
var publisherSchema = import_zod2.z.object({
|
|
235
|
+
"@type": import_zod2.z.string(),
|
|
236
|
+
name: import_zod2.z.string().optional(),
|
|
237
|
+
url: import_zod2.z.string().optional(),
|
|
238
|
+
logo: import_zod2.z.union([logoSchema, import_zod2.z.string()]).optional(),
|
|
239
|
+
sameAs: import_zod2.z.union([import_zod2.z.array(import_zod2.z.string()), import_zod2.z.string()]).optional()
|
|
240
|
+
});
|
|
241
|
+
var structuredSchema = import_zod2.z.object({
|
|
242
|
+
"@context": import_zod2.z.string().optional(),
|
|
243
|
+
"@type": import_zod2.z.string().optional(),
|
|
244
|
+
headline: import_zod2.z.string().optional(),
|
|
245
|
+
publisher: publisherSchema.optional()
|
|
246
|
+
});
|
|
247
|
+
var urlTreeSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.any());
|
|
248
|
+
var scrapeResponseSchema = import_zod2.z.object({
|
|
249
|
+
request: scrapeRequestSchema,
|
|
250
|
+
page: scrapePageSchema,
|
|
251
|
+
statistics: scrapeStatisticsSchema,
|
|
252
|
+
languages: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.number()),
|
|
253
|
+
snippets: import_zod2.z.record(import_zod2.z.string(), snippetSchema),
|
|
254
|
+
full_text: import_zod2.z.string(),
|
|
255
|
+
metadata: metadataSchema,
|
|
256
|
+
structured: import_zod2.z.array(structuredSchema),
|
|
257
|
+
url_tree: urlTreeSchema
|
|
258
|
+
});
|
|
259
|
+
var scrapeFullResSchema = import_zod2.z.object({
|
|
260
|
+
message: import_zod2.z.string(),
|
|
261
|
+
added_to_batch: import_zod2.z.boolean(),
|
|
262
|
+
response: scrapeResponseSchema
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// src/api/schemas.ts
|
|
266
|
+
var queryTypeEnum = import_zod3.default.enum(["fast-search", "search", "bulk-search"]);
|
|
267
|
+
var algorithmEnum = import_zod3.default.enum([
|
|
268
|
+
"string",
|
|
269
|
+
"lexical",
|
|
270
|
+
"baseline",
|
|
271
|
+
"hamming",
|
|
272
|
+
"hybrid-1",
|
|
273
|
+
"hybrid-2",
|
|
274
|
+
"hybrid-3",
|
|
275
|
+
"company"
|
|
276
|
+
]);
|
|
277
|
+
var brandSafetyEnum = import_zod3.default.enum(["safe", "sensitive", "unsafe"]);
|
|
278
|
+
var continentEnum = import_zod3.default.enum([
|
|
279
|
+
"Africa",
|
|
280
|
+
"Asia",
|
|
281
|
+
"Europe",
|
|
282
|
+
"North America",
|
|
283
|
+
"Oceania",
|
|
284
|
+
"South America",
|
|
285
|
+
"Worldwide"
|
|
286
|
+
]);
|
|
287
|
+
var regionEnum = import_zod3.default.enum([
|
|
288
|
+
"Caribbean",
|
|
289
|
+
"Central Africa",
|
|
290
|
+
"Central America",
|
|
291
|
+
"Central Asia",
|
|
292
|
+
"Central Europe",
|
|
293
|
+
"East Africa",
|
|
294
|
+
"East Asia",
|
|
295
|
+
"Eastern Europe",
|
|
296
|
+
"Middle East",
|
|
297
|
+
"North Africa",
|
|
298
|
+
"North America",
|
|
299
|
+
"Northern Europe",
|
|
300
|
+
"Oceania",
|
|
301
|
+
"South America",
|
|
302
|
+
"South Asia",
|
|
303
|
+
"Southeast Asia",
|
|
304
|
+
"Southern Africa",
|
|
305
|
+
"Southern Europe",
|
|
306
|
+
"Sub-Saharan Africa",
|
|
307
|
+
"The Amazon Basin",
|
|
308
|
+
"The Andes",
|
|
309
|
+
"The Arctic Region",
|
|
310
|
+
"The Balkans",
|
|
311
|
+
"The Caucasus",
|
|
312
|
+
"The Horn of Africa",
|
|
313
|
+
"The Levant",
|
|
314
|
+
"The Middle East",
|
|
315
|
+
"The Sahel",
|
|
316
|
+
"West Africa",
|
|
317
|
+
"Western Europe",
|
|
318
|
+
"Worldwide"
|
|
319
|
+
]);
|
|
320
|
+
var searchQuerySchema = import_zod3.default.object({
|
|
321
|
+
instruction: import_zod3.default.string(),
|
|
322
|
+
question: import_zod3.default.string(),
|
|
323
|
+
expansions: import_zod3.default.array(import_zod3.default.string()),
|
|
324
|
+
brand_safety: import_zod3.default.null(),
|
|
325
|
+
language: import_zod3.default.string().nullable(),
|
|
326
|
+
continent: import_zod3.default.string().nullable(),
|
|
327
|
+
region: import_zod3.default.string().nullable(),
|
|
328
|
+
country: import_zod3.default.string().nullable(),
|
|
329
|
+
sector: import_zod3.default.string().nullable(),
|
|
330
|
+
industry_group: import_zod3.default.string().nullable(),
|
|
331
|
+
industry: import_zod3.default.string().nullable(),
|
|
332
|
+
sub_industry: import_zod3.default.string().nullable(),
|
|
333
|
+
iab_tier_1: import_zod3.default.string().nullable(),
|
|
334
|
+
iab_tier_2: import_zod3.default.string().nullable(),
|
|
335
|
+
iab_tier_3: import_zod3.default.string().nullable(),
|
|
336
|
+
iab_tier_4: import_zod3.default.string().nullable(),
|
|
337
|
+
algorithm: import_zod3.default.string(),
|
|
338
|
+
n_results: import_zod3.default.number(),
|
|
339
|
+
n_contextify: import_zod3.default.number(),
|
|
340
|
+
n_probes: import_zod3.default.number(),
|
|
341
|
+
min_similarity: import_zod3.default.number(),
|
|
342
|
+
pass_similarity: import_zod3.default.number(),
|
|
343
|
+
must_exclude: import_zod3.default.array(import_zod3.default.string()),
|
|
344
|
+
must_include: import_zod3.default.array(import_zod3.default.string()),
|
|
345
|
+
shard_selector: import_zod3.default.string(),
|
|
346
|
+
shard_reranker: import_zod3.default.string(),
|
|
347
|
+
search_lang: import_zod3.default.string(),
|
|
348
|
+
search_words: import_zod3.default.record(import_zod3.default.string(), import_zod3.default.number()),
|
|
349
|
+
search_intents: import_zod3.default.record(import_zod3.default.string(), import_zod3.default.any()),
|
|
350
|
+
companies: import_zod3.default.array(import_zod3.default.any())
|
|
351
|
+
});
|
|
352
|
+
var searchResultSemanticsSchema = import_zod3.default.object({
|
|
353
|
+
origin_shard: import_zod3.default.number(),
|
|
354
|
+
chunks_total: import_zod3.default.number(),
|
|
355
|
+
chunks_matched: import_zod3.default.number(),
|
|
356
|
+
chunks_kept: import_zod3.default.number(),
|
|
357
|
+
similarity: import_zod3.default.number(),
|
|
358
|
+
bitstring: import_zod3.default.string()
|
|
359
|
+
});
|
|
360
|
+
var searchResponseSchema = import_zod3.default.object({
|
|
361
|
+
url_hash: import_zod3.default.string(),
|
|
362
|
+
url: import_zod3.default.string(),
|
|
363
|
+
netloc: import_zod3.default.string(),
|
|
364
|
+
published: import_zod3.default.string(),
|
|
365
|
+
visited: import_zod3.default.string(),
|
|
366
|
+
language: import_zod3.default.string(),
|
|
367
|
+
author: import_zod3.default.string(),
|
|
368
|
+
title: import_zod3.default.string(),
|
|
369
|
+
description: import_zod3.default.string(),
|
|
370
|
+
content: import_zod3.default.string(),
|
|
371
|
+
best_chunk: import_zod3.default.string(),
|
|
372
|
+
semantics: searchResultSemanticsSchema
|
|
373
|
+
});
|
|
374
|
+
var bulkResSchema = import_zod3.default.object({
|
|
375
|
+
message: import_zod3.default.string(),
|
|
376
|
+
decrypt_using: import_zod3.default.string(),
|
|
377
|
+
download_from: import_zod3.default.string()
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// src/utils/llm.ts
|
|
381
|
+
var defaultModel = "google/gemini-2.0-flash-001";
|
|
382
|
+
var getSentiment = async ({
|
|
383
|
+
text,
|
|
384
|
+
model = defaultModel,
|
|
385
|
+
llmClient
|
|
386
|
+
}) => {
|
|
387
|
+
if (!llmClient) {
|
|
388
|
+
throw new Error("A OpenAI client instance must be provided as 'llmClient'.");
|
|
389
|
+
}
|
|
390
|
+
if (!text || text.trim() === "") {
|
|
391
|
+
throw new Error("Text must not be empty or whitespace.");
|
|
392
|
+
}
|
|
393
|
+
const prompt = `
|
|
394
|
+
# TASK DESCRIPTION
|
|
395
|
+
On a scale from -1.0 (very negative) to 1.0 (very positive),
|
|
396
|
+
please rate the sentiment of the following text and return _only_ the numeric score:
|
|
397
|
+
${text.trim()}
|
|
398
|
+
|
|
399
|
+
# RESPONSE FORMAT
|
|
400
|
+
|
|
401
|
+
The response must be a float in [-1.0, 1.0]. No other text must be returned.
|
|
402
|
+
`;
|
|
403
|
+
try {
|
|
404
|
+
const completion = await llmClient.chat.completions.create({
|
|
405
|
+
model,
|
|
406
|
+
messages: [{ role: "user", content: prompt.trim() }],
|
|
407
|
+
temperature: 0.7
|
|
408
|
+
});
|
|
409
|
+
const raw = completion.choices[0]?.message?.content;
|
|
410
|
+
const score = parseFloat(raw);
|
|
411
|
+
if (Number.isNaN(score)) {
|
|
412
|
+
throw new Error(`Sentiment response is not a float: ${JSON.stringify(raw)}`);
|
|
413
|
+
}
|
|
414
|
+
if (score < -1 || score > 1) {
|
|
415
|
+
throw new Error(`Sentiment ${score} outside valid range [-1.0, 1.0]`);
|
|
416
|
+
}
|
|
417
|
+
return score;
|
|
418
|
+
} catch (error) {
|
|
419
|
+
throw error;
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
var generateExpansions = async ({
|
|
423
|
+
question,
|
|
424
|
+
model = defaultModel,
|
|
425
|
+
llmClient
|
|
426
|
+
}) => {
|
|
427
|
+
if (!llmClient) {
|
|
428
|
+
throw new Error("A OpenAI client instance must be provided as 'llmClient'.");
|
|
429
|
+
}
|
|
430
|
+
if (!question || question.trim() === "") {
|
|
431
|
+
throw new Error("Question must not be empty or whitespace.");
|
|
432
|
+
}
|
|
433
|
+
const prompt = `
|
|
434
|
+
# TASK DESCRIPTION
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
Given a search question you must generate a list of 10 similar questions that have the same exact
|
|
438
|
+
semantic meaning but are contextually and lexically different to improve search recall.
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
## Question
|
|
442
|
+
|
|
443
|
+
Here is the question you must generate expansions for:
|
|
444
|
+
|
|
445
|
+
Question: ${question.trim()}
|
|
446
|
+
|
|
447
|
+
# RESPONSE FORMAT
|
|
448
|
+
|
|
449
|
+
Your response must be a JSON object structured as follows: a list of ten strings. Each string must
|
|
450
|
+
be a grammatically correct question that expands on the original question to improve recall.
|
|
451
|
+
|
|
452
|
+
[
|
|
453
|
+
string,
|
|
454
|
+
string,
|
|
455
|
+
string,
|
|
456
|
+
string,
|
|
457
|
+
string,
|
|
458
|
+
string,
|
|
459
|
+
string,
|
|
460
|
+
string,
|
|
461
|
+
string,
|
|
462
|
+
string
|
|
463
|
+
]
|
|
464
|
+
|
|
465
|
+
# EXPANSION GUIDELINES
|
|
466
|
+
|
|
467
|
+
1. **Use specific named entities** - To improve the quality of your search results you must mention
|
|
468
|
+
specific named entities (people, locations, organizations, products, places) in expansions.
|
|
469
|
+
2. **Expansions must be highly targeted** - To improve the quality of search results each expansion
|
|
470
|
+
must be semantically unambiguous. Questions must be use between ten and fifteen words.
|
|
471
|
+
3. **Expansions must improve recall** - When expanding the question leverage semantic and contextual
|
|
472
|
+
expansion to maximize the ability of the search engine to find semantically relevant documents:
|
|
473
|
+
- Semantic Example: Swap "climate change" with "global warming" or "environmental change".
|
|
474
|
+
- Contextual Example: Swap "diabetes treatment" with "insulin therapy" or "blood sugar management".
|
|
475
|
+
`;
|
|
476
|
+
try {
|
|
477
|
+
const completion = await llmClient.chat.completions.create({
|
|
478
|
+
model,
|
|
479
|
+
messages: [{ role: "user", content: prompt.trim() }],
|
|
480
|
+
temperature: 0.7
|
|
481
|
+
});
|
|
482
|
+
let raw = completion.choices[0]?.message?.content ?? "";
|
|
483
|
+
let toParse = raw.trim();
|
|
484
|
+
if (toParse.startsWith("```")) {
|
|
485
|
+
toParse = toParse.replace(/^```+/, "").trim();
|
|
486
|
+
if (toParse.toLowerCase().startsWith("json")) {
|
|
487
|
+
toParse = toParse.slice(4).trim();
|
|
488
|
+
}
|
|
489
|
+
toParse = toParse.replace(/```+$/, "").trim();
|
|
490
|
+
}
|
|
491
|
+
let expansions;
|
|
492
|
+
try {
|
|
493
|
+
expansions = JSON.parse(toParse);
|
|
494
|
+
} catch (decodeErr) {
|
|
495
|
+
throw new Error(`OpenRouter response was not valid JSON: '${toParse}'`);
|
|
496
|
+
}
|
|
497
|
+
if (!Array.isArray(expansions) || expansions.length !== 10 || !expansions.every((q) => typeof q === "string")) {
|
|
498
|
+
throw new Error("Invalid response: 'choices' missing or empty");
|
|
499
|
+
}
|
|
500
|
+
console.debug("Expansions: ", expansions);
|
|
501
|
+
return expansions;
|
|
502
|
+
} catch (error) {
|
|
503
|
+
throw error;
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
// src/api/index.ts
|
|
508
|
+
var import_zod4 = require("zod");
|
|
509
|
+
var fastNResults = import_zod4.z.number().min(10).max(100).optional().default(100);
|
|
510
|
+
var searchNResults = import_zod4.z.number().min(100).max(1000).optional().default(100);
|
|
511
|
+
var bulkNResults = import_zod4.z.number().min(1000).max(1e4).optional().default(1000);
|
|
512
|
+
var aiSearchParamsSchema = import_zod4.z.object({
|
|
513
|
+
prompt: import_zod4.z.string().min(25).max(2500),
|
|
514
|
+
agent: import_zod4.z.string().optional()
|
|
515
|
+
});
|
|
516
|
+
var stdSearchParams = import_zod4.z.object({
|
|
517
|
+
question: import_zod4.z.string(),
|
|
518
|
+
expansions: import_zod4.z.array(import_zod4.z.string()).optional(),
|
|
519
|
+
sql_filter: import_zod4.z.string().optional(),
|
|
520
|
+
algorithm: algorithmEnum.optional(),
|
|
521
|
+
n_results: import_zod4.z.number(),
|
|
522
|
+
n_probes: import_zod4.z.number().min(1).max(10).optional(),
|
|
523
|
+
n_contextify: import_zod4.z.number().min(64).max(1024).optional(),
|
|
524
|
+
min_similarity: import_zod4.z.number().min(0).max(1).optional(),
|
|
525
|
+
must_include: import_zod4.z.array(import_zod4.z.string()).max(100).optional(),
|
|
526
|
+
must_exclude: import_zod4.z.array(import_zod4.z.string()).max(100).optional(),
|
|
527
|
+
brand_safety: brandSafetyEnum.optional(),
|
|
528
|
+
language: import_zod4.z.string().min(2).max(2).optional(),
|
|
529
|
+
continent: continentEnum.optional(),
|
|
530
|
+
region: regionEnum.optional(),
|
|
531
|
+
country: import_zod4.z.string().optional(),
|
|
532
|
+
sector: import_zod4.z.string().optional(),
|
|
533
|
+
industry_group: import_zod4.z.string().optional(),
|
|
534
|
+
industry: import_zod4.z.string().optional(),
|
|
535
|
+
sub_industry: import_zod4.z.string().optional(),
|
|
536
|
+
iab_tier_1: import_zod4.z.string().optional(),
|
|
537
|
+
iab_tier_2: import_zod4.z.string().optional(),
|
|
538
|
+
iab_tier_3: import_zod4.z.string().optional(),
|
|
539
|
+
iab_tier_4: import_zod4.z.string().optional(),
|
|
540
|
+
companies: import_zod4.z.array(import_zod4.z.string()).max(30).optional()
|
|
541
|
+
});
|
|
542
|
+
var fastSearchParamsSchema = import_zod4.z.object({
|
|
543
|
+
...stdSearchParams.shape,
|
|
544
|
+
n_results: fastNResults
|
|
545
|
+
});
|
|
546
|
+
var bulkSearchParamsSchema = import_zod4.z.object({
|
|
547
|
+
...stdSearchParams.shape,
|
|
548
|
+
n_results: bulkNResults
|
|
549
|
+
});
|
|
550
|
+
var validateFastSearchParams = (params) => {
|
|
551
|
+
const validatedParams = fastSearchParamsSchema.parse(params);
|
|
552
|
+
return validatedParams;
|
|
553
|
+
};
|
|
554
|
+
var validateBulkSearchParams = (params) => {
|
|
555
|
+
const validatedParams = bulkSearchParamsSchema.parse(params);
|
|
556
|
+
return validatedParams;
|
|
557
|
+
};
|
|
558
|
+
var scapeUrlBody = import_zod4.z.object({
|
|
559
|
+
url: import_zod4.z.string()
|
|
560
|
+
});
|
|
561
|
+
var topicTrendBody = import_zod4.z.object({
|
|
562
|
+
query: import_zod4.z.string(),
|
|
563
|
+
sql_filter: import_zod4.z.string().optional()
|
|
564
|
+
});
|
|
565
|
+
var callNosibleApi = async ({
|
|
566
|
+
baseUrl = "https://www.nosible.ai/search/v2",
|
|
567
|
+
endpoint,
|
|
568
|
+
body,
|
|
569
|
+
apiKey
|
|
570
|
+
}) => {
|
|
571
|
+
const response = await fetch(`${baseUrl}/${endpoint}`, {
|
|
572
|
+
method: "POST",
|
|
573
|
+
headers: {
|
|
574
|
+
Accept: "application/json",
|
|
575
|
+
"Content-Type": "application/json",
|
|
576
|
+
"Api-Key": `${apiKey}`
|
|
577
|
+
},
|
|
578
|
+
body: JSON.stringify(body)
|
|
579
|
+
});
|
|
580
|
+
if (!response.ok) {
|
|
581
|
+
console.error("Status: " + response.status);
|
|
582
|
+
if (response.status === 401) {
|
|
583
|
+
throw new Error("Your API key is not valid.");
|
|
584
|
+
}
|
|
585
|
+
if (response.status === 422) {
|
|
586
|
+
const contentType = response.headers.get("Content-Type") || "";
|
|
587
|
+
if (contentType.startsWith("application/json")) {
|
|
588
|
+
const body2 = await response.json();
|
|
589
|
+
const errorBody = Array.isArray(body2) ? body2[0] : body2;
|
|
590
|
+
console.error(errorBody);
|
|
591
|
+
if (errorBody?.type === "string_too_short") {
|
|
592
|
+
throw new Error("Your API key is not valid: Too Short.");
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
throw new Error("You made a bad request.");
|
|
596
|
+
}
|
|
597
|
+
if (response.status === 429) {
|
|
598
|
+
throw new Error("You have hit your rate limit.");
|
|
599
|
+
}
|
|
600
|
+
if (response.status === 409) {
|
|
601
|
+
throw new Error("Too many concurrent searches.");
|
|
602
|
+
}
|
|
603
|
+
if (response.status === 500) {
|
|
604
|
+
throw new Error("An unexpected error occurred.");
|
|
605
|
+
}
|
|
606
|
+
if (response.status === 502) {
|
|
607
|
+
throw new Error("NOSIBLE is currently restarting.");
|
|
608
|
+
}
|
|
609
|
+
if (response.status === 504) {
|
|
610
|
+
throw new Error("NOSIBLE is currently overloaded.");
|
|
611
|
+
}
|
|
612
|
+
console.error(await response.text());
|
|
613
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
614
|
+
} else {
|
|
615
|
+
const data = await response.json();
|
|
616
|
+
return data;
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
// src/search/search.ts
|
|
621
|
+
var userSearchParamsSchema = sqlFilterSchema.extend({
|
|
622
|
+
question: import_zod5.z.string().optional(),
|
|
623
|
+
autoGenerateExpansions: import_zod5.z.boolean().optional(),
|
|
624
|
+
expansions: import_zod5.z.array(import_zod5.z.string()).optional(),
|
|
625
|
+
sqlFilter: import_zod5.z.string().optional(),
|
|
626
|
+
algorithm: algorithmEnum.optional(),
|
|
627
|
+
nResults: import_zod5.z.number().optional(),
|
|
628
|
+
nProbes: import_zod5.z.number().min(1).max(10).optional(),
|
|
629
|
+
nContextify: import_zod5.z.number().min(64).max(1024).optional(),
|
|
630
|
+
minSimilarity: import_zod5.z.number().min(0).max(1).optional(),
|
|
631
|
+
mustInclude: import_zod5.z.array(import_zod5.z.string()).max(100).optional(),
|
|
632
|
+
mustExclude: import_zod5.z.array(import_zod5.z.string()).max(100).optional(),
|
|
633
|
+
brandSafety: brandSafetyEnum.optional(),
|
|
634
|
+
language: import_zod5.z.string().min(2).max(2).optional(),
|
|
635
|
+
continent: continentEnum.optional(),
|
|
636
|
+
region: regionEnum.optional(),
|
|
637
|
+
country: import_zod5.z.string().optional(),
|
|
638
|
+
sector: import_zod5.z.string().optional(),
|
|
639
|
+
industryGroup: import_zod5.z.string().optional(),
|
|
640
|
+
industry: import_zod5.z.string().optional(),
|
|
641
|
+
subIndustry: import_zod5.z.string().optional(),
|
|
642
|
+
iabTier1: import_zod5.z.string().optional(),
|
|
643
|
+
iabTier2: import_zod5.z.string().optional(),
|
|
644
|
+
iabTier3: import_zod5.z.string().optional(),
|
|
645
|
+
iabTier4: import_zod5.z.string().optional(),
|
|
646
|
+
companies: import_zod5.z.array(import_zod5.z.string()).max(30).optional()
|
|
647
|
+
});
|
|
648
|
+
var clientDefaultSearchParamsSchema = userSearchParamsSchema.omit({
|
|
649
|
+
question: true
|
|
650
|
+
});
|
|
651
|
+
var similarUserSearchParams = userSearchParamsSchema.omit({
|
|
652
|
+
question: true
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
class Search {
|
|
656
|
+
question;
|
|
657
|
+
nResults;
|
|
658
|
+
expansions;
|
|
659
|
+
autoGenerateExpansions;
|
|
660
|
+
nProbes;
|
|
661
|
+
nContextify;
|
|
662
|
+
algorithm;
|
|
663
|
+
sqlFilter;
|
|
664
|
+
minSimilarity;
|
|
665
|
+
mustInclude;
|
|
666
|
+
mustExclude;
|
|
667
|
+
brandSafety;
|
|
668
|
+
language;
|
|
669
|
+
continent;
|
|
670
|
+
region;
|
|
671
|
+
country;
|
|
672
|
+
sector;
|
|
673
|
+
industryGroup;
|
|
674
|
+
industry;
|
|
675
|
+
subIndustry;
|
|
676
|
+
iabTier1;
|
|
677
|
+
iabTier2;
|
|
678
|
+
iabTier3;
|
|
679
|
+
iabTier4;
|
|
680
|
+
companies;
|
|
681
|
+
publishStart;
|
|
682
|
+
publishEnd;
|
|
683
|
+
visitedStart;
|
|
684
|
+
visitedEnd;
|
|
685
|
+
certain;
|
|
686
|
+
includeNetlocs;
|
|
687
|
+
excludeNetlocs;
|
|
688
|
+
includeCompanies;
|
|
689
|
+
excludeCompanies;
|
|
690
|
+
includeDocs;
|
|
691
|
+
excludeDocs;
|
|
692
|
+
constructor(params) {
|
|
693
|
+
Object.assign(this, params);
|
|
694
|
+
}
|
|
695
|
+
searchBody = async ({
|
|
696
|
+
client
|
|
697
|
+
}) => {
|
|
698
|
+
let expansions = this.expansions;
|
|
699
|
+
if (this.autoGenerateExpansions) {
|
|
700
|
+
expansions = await generateExpansions({
|
|
701
|
+
question: this.question,
|
|
702
|
+
model: client.expansionsModel,
|
|
703
|
+
llmClient: client.llmClient
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
let sqlFilter = generateSqlFilter({
|
|
707
|
+
publishStart: this.publishStart || undefined,
|
|
708
|
+
publishEnd: this.publishEnd || undefined,
|
|
709
|
+
visitedStart: this.visitedStart || undefined,
|
|
710
|
+
visitedEnd: this.visitedEnd || undefined,
|
|
711
|
+
certain: this.certain || undefined,
|
|
712
|
+
includeNetlocs: this.includeNetlocs || undefined,
|
|
713
|
+
excludeNetlocs: this.excludeNetlocs || undefined,
|
|
714
|
+
includeCompanies: this.includeCompanies || undefined,
|
|
715
|
+
excludeCompanies: this.excludeCompanies || undefined,
|
|
716
|
+
includeDocs: this.includeDocs || undefined,
|
|
717
|
+
excludeDocs: this.excludeDocs || undefined
|
|
718
|
+
});
|
|
719
|
+
const output = {
|
|
720
|
+
question: this.question,
|
|
721
|
+
expansions,
|
|
722
|
+
sql_filter: sqlFilter || undefined,
|
|
723
|
+
algorithm: this.algorithm,
|
|
724
|
+
n_probes: this.nProbes,
|
|
725
|
+
n_results: this.nResults,
|
|
726
|
+
n_contextify: this.nContextify,
|
|
727
|
+
min_similarity: this.minSimilarity,
|
|
728
|
+
must_include: this.mustInclude,
|
|
729
|
+
must_exclude: this.mustExclude,
|
|
730
|
+
brand_safety: this.brandSafety,
|
|
731
|
+
language: this.language,
|
|
732
|
+
continent: this.continent,
|
|
733
|
+
region: this.region,
|
|
734
|
+
country: this.country,
|
|
735
|
+
sector: this.sector,
|
|
736
|
+
industry_group: this.industryGroup,
|
|
737
|
+
industry: this.industry,
|
|
738
|
+
sub_industry: this.subIndustry,
|
|
739
|
+
iab_tier_1: this.iabTier1,
|
|
740
|
+
iab_tier_2: this.iabTier2,
|
|
741
|
+
iab_tier_3: this.iabTier3,
|
|
742
|
+
iab_tier_4: this.iabTier4,
|
|
743
|
+
companies: this.companies
|
|
744
|
+
};
|
|
745
|
+
const outputWithoutUndefined = Object.fromEntries(Object.entries(output).filter(([, value]) => value !== undefined));
|
|
746
|
+
return outputWithoutUndefined;
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// src/utils/index.ts
|
|
751
|
+
var isBrowser = () => {
|
|
752
|
+
return typeof window !== "undefined";
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
// src/utils/browser.ts
|
|
756
|
+
var downloadBlob = (data, mimeType, fileName) => {
|
|
757
|
+
const blob = new Blob([data], { type: mimeType });
|
|
758
|
+
const url = URL.createObjectURL(blob);
|
|
759
|
+
const a = document.createElement("a");
|
|
760
|
+
a.href = url;
|
|
761
|
+
a.download = fileName;
|
|
762
|
+
document.body.appendChild(a);
|
|
763
|
+
a.click();
|
|
764
|
+
document.body.removeChild(a);
|
|
765
|
+
URL.revokeObjectURL(url);
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
// src/utils/file.ts
|
|
769
|
+
var import_papaparse = __toESM(require("papaparse"));
|
|
770
|
+
var exportJson = async (data, outputPath) => {
|
|
771
|
+
try {
|
|
772
|
+
if (isBrowser()) {
|
|
773
|
+
const filename = outputPath.split("/").pop() || "export.json";
|
|
774
|
+
const jsonString = JSON.stringify(data);
|
|
775
|
+
const finalFilename = filename.endsWith(".json") ? filename : `${filename}.json`;
|
|
776
|
+
downloadBlob(jsonString, "application/json", finalFilename);
|
|
777
|
+
} else {
|
|
778
|
+
const { writeFile } = await import("node:fs/promises");
|
|
779
|
+
await writeFile(outputPath, JSON.stringify(data));
|
|
780
|
+
}
|
|
781
|
+
} catch (error) {
|
|
782
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
783
|
+
throw new Error(`Failed to write JSON: ${errorMessage}`);
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
var importJson = async (options) => {
|
|
787
|
+
try {
|
|
788
|
+
if ("file" in options) {
|
|
789
|
+
const text = await options.file.text();
|
|
790
|
+
return JSON.parse(text);
|
|
791
|
+
} else {
|
|
792
|
+
if (isBrowser()) {
|
|
793
|
+
throw new Error("File path import is not supported in browser. Use {file: File} instead.");
|
|
794
|
+
}
|
|
795
|
+
const { readFile } = await import("node:fs/promises");
|
|
796
|
+
const data = await readFile(options.filePath, "utf-8");
|
|
797
|
+
return JSON.parse(data);
|
|
798
|
+
}
|
|
799
|
+
} catch (error) {
|
|
800
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
801
|
+
throw new Error(`Failed to read JSON: ${errorMessage}`);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
var importCsv = async (options) => {
|
|
805
|
+
try {
|
|
806
|
+
let csvText;
|
|
807
|
+
if ("file" in options) {
|
|
808
|
+
csvText = await options.file.text();
|
|
809
|
+
} else {
|
|
810
|
+
if (isBrowser()) {
|
|
811
|
+
throw new Error("File path import is not supported in browser. Use {file: File} instead.");
|
|
812
|
+
}
|
|
813
|
+
const { readFile } = await import("node:fs/promises");
|
|
814
|
+
csvText = await readFile(options.filePath, "utf-8");
|
|
815
|
+
}
|
|
816
|
+
if (!csvText.trim()) {
|
|
817
|
+
return [];
|
|
818
|
+
}
|
|
819
|
+
const result = import_papaparse.default.parse(csvText, {
|
|
820
|
+
header: true,
|
|
821
|
+
skipEmptyLines: true,
|
|
822
|
+
dynamicTyping: true
|
|
823
|
+
});
|
|
824
|
+
const significantErrors = result.errors.filter((error) => !error.message.includes("Unable to auto-detect delimiting character"));
|
|
825
|
+
if (significantErrors.length > 0) {
|
|
826
|
+
const errorMessages = significantErrors.map((err) => err.message).join(", ");
|
|
827
|
+
throw new Error(`CSV parsing errors: ${errorMessages}`);
|
|
828
|
+
}
|
|
829
|
+
return result.data;
|
|
830
|
+
} catch (error) {
|
|
831
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
832
|
+
throw new Error(`Failed to read CSV: ${errorMessage}`);
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
var exportNdjson = async (data, outputPath) => {
|
|
836
|
+
try {
|
|
837
|
+
if (isBrowser()) {
|
|
838
|
+
const filename = outputPath.split("/").pop() || "export.ndjson";
|
|
839
|
+
const ndjsonString = data.map((item) => JSON.stringify(item)).join(`
|
|
840
|
+
`);
|
|
841
|
+
const finalFilename = filename.endsWith(".ndjson") ? filename : `${filename}.ndjson`;
|
|
842
|
+
downloadBlob(ndjsonString, "application/x-ndjson", finalFilename);
|
|
843
|
+
} else {
|
|
844
|
+
const pl = await import("nodejs-polars");
|
|
845
|
+
const df = pl.DataFrame(data);
|
|
846
|
+
await df.writeJSON(outputPath, { format: "lines" });
|
|
847
|
+
}
|
|
848
|
+
} catch (error) {
|
|
849
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
850
|
+
throw new Error(`Failed to write NDJSON: ${errorMessage}`);
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
var exportCsv = async (data, outputPath) => {
|
|
854
|
+
try {
|
|
855
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
856
|
+
throw new Error("Data must be a non-empty array");
|
|
857
|
+
}
|
|
858
|
+
if (!outputPath || typeof outputPath !== "string") {
|
|
859
|
+
throw new Error("Output path must be a non-empty string");
|
|
860
|
+
}
|
|
861
|
+
const csvString = import_papaparse.default.unparse(data, {
|
|
862
|
+
header: true,
|
|
863
|
+
newline: `
|
|
864
|
+
`
|
|
865
|
+
});
|
|
866
|
+
if (isBrowser()) {
|
|
867
|
+
const filename = outputPath.split("/").pop() || "export.csv";
|
|
868
|
+
const finalFilename = filename.endsWith(".csv") ? filename : `${filename}.csv`;
|
|
869
|
+
downloadBlob(csvString, "text/csv", finalFilename);
|
|
870
|
+
} else {
|
|
871
|
+
const { writeFile } = await import("node:fs/promises");
|
|
872
|
+
await writeFile(outputPath, csvString);
|
|
873
|
+
}
|
|
874
|
+
} catch (error) {
|
|
875
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
876
|
+
throw new Error(`Failed to write CSV: ${errorMessage}`);
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
|
|
880
|
+
// src/scrape/webPageData.ts
|
|
881
|
+
class WebPageData {
|
|
882
|
+
client;
|
|
883
|
+
data;
|
|
884
|
+
snippets;
|
|
885
|
+
page;
|
|
886
|
+
fullText;
|
|
887
|
+
metadata;
|
|
888
|
+
structured;
|
|
889
|
+
urlTree;
|
|
890
|
+
statistics;
|
|
891
|
+
constructor(client, res) {
|
|
892
|
+
this.client = client;
|
|
893
|
+
this.data = res;
|
|
894
|
+
this.snippets = mapSnippetToArray(res);
|
|
895
|
+
this.page = this.data.page;
|
|
896
|
+
this.fullText = this.data.full_text;
|
|
897
|
+
this.metadata = this.data.metadata;
|
|
898
|
+
this.structured = this.data.structured;
|
|
899
|
+
this.urlTree = this.data.url_tree;
|
|
900
|
+
this.statistics = this.data.statistics;
|
|
901
|
+
}
|
|
902
|
+
static async fromJson(client, inputPath) {
|
|
903
|
+
const data = await importJson({ filePath: inputPath });
|
|
904
|
+
const validData = scrapeResponseSchema.parse(data);
|
|
905
|
+
return new WebPageData(client, validData);
|
|
906
|
+
}
|
|
907
|
+
async writeJson(outputPath) {
|
|
908
|
+
return await exportJson(this.data, outputPath);
|
|
909
|
+
}
|
|
910
|
+
getSnippets() {
|
|
911
|
+
return this.snippets;
|
|
912
|
+
}
|
|
913
|
+
getSnippet(hashKey) {
|
|
914
|
+
return this.snippets.find((snippet) => snippet.url_hash === hashKey);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
var mapSnippetToArray = (data) => {
|
|
918
|
+
const snippets = [];
|
|
919
|
+
const snippetKeys = Object.keys(data.snippets);
|
|
920
|
+
if (snippetKeys.length === 0) {
|
|
921
|
+
return snippets;
|
|
922
|
+
}
|
|
923
|
+
const unsortedSnippets = [];
|
|
924
|
+
snippetKeys.forEach((key) => {
|
|
925
|
+
unsortedSnippets.push(data.snippets[key]);
|
|
926
|
+
});
|
|
927
|
+
const first = unsortedSnippets.find((snippet) => snippet.prev_snippet_hash === null);
|
|
928
|
+
if (!first) {
|
|
929
|
+
throw new Error("No first snippet found");
|
|
930
|
+
}
|
|
931
|
+
snippets.push(first);
|
|
932
|
+
let current = first;
|
|
933
|
+
while (current.next_snippet_hash) {
|
|
934
|
+
const next = unsortedSnippets.find((snippet) => snippet.snippet_hash === current.next_snippet_hash);
|
|
935
|
+
if (!next) {
|
|
936
|
+
throw new Error("No next snippet found");
|
|
937
|
+
}
|
|
938
|
+
snippets.push(next);
|
|
939
|
+
current = next;
|
|
940
|
+
}
|
|
941
|
+
return snippets;
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
// src/topicTrend/topicTrend.ts
|
|
945
|
+
class TopicTrend {
|
|
946
|
+
data;
|
|
947
|
+
constructor(data) {
|
|
948
|
+
this.data = data;
|
|
949
|
+
}
|
|
950
|
+
peakDate() {
|
|
951
|
+
const maxValue = Math.max(...Object.values(this.data.response));
|
|
952
|
+
const date = Object.keys(this.data.response).find((key) => this.data.response[key] === maxValue || undefined);
|
|
953
|
+
if (!date) {
|
|
954
|
+
throw new Error("No peak date found");
|
|
955
|
+
}
|
|
956
|
+
return new Date(date);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// src/utils/userPlan.ts
|
|
961
|
+
var import_bottleneck = __toESM(require("bottleneck"));
|
|
962
|
+
var planLimits = [
|
|
963
|
+
{
|
|
964
|
+
key: "test",
|
|
965
|
+
name: "Test",
|
|
966
|
+
rateLimits: {
|
|
967
|
+
scrapeUrl: { minute: 60, month: 300 },
|
|
968
|
+
bulk: { minute: 60, month: 300 },
|
|
969
|
+
fast: { minute: 60, month: 3000 }
|
|
970
|
+
}
|
|
971
|
+
},
|
|
972
|
+
{
|
|
973
|
+
key: "basic",
|
|
974
|
+
name: "Basic",
|
|
975
|
+
rateLimits: {
|
|
976
|
+
scrapeUrl: { minute: 60, month: 1400 },
|
|
977
|
+
bulk: { minute: 60, month: 1400 },
|
|
978
|
+
fast: { minute: 60, month: 14000 }
|
|
979
|
+
}
|
|
980
|
+
},
|
|
981
|
+
{
|
|
982
|
+
key: "pro",
|
|
983
|
+
name: "Pro",
|
|
984
|
+
rateLimits: {
|
|
985
|
+
scrapeUrl: { minute: 60, month: 6700 },
|
|
986
|
+
bulk: { minute: 60, month: 6700 },
|
|
987
|
+
fast: { minute: 60, month: 67000 }
|
|
988
|
+
}
|
|
989
|
+
},
|
|
990
|
+
{
|
|
991
|
+
key: "pro+",
|
|
992
|
+
name: "Pro+",
|
|
993
|
+
rateLimits: {
|
|
994
|
+
scrapeUrl: { minute: 60, month: 32000 },
|
|
995
|
+
bulk: { minute: 60, month: 32000 },
|
|
996
|
+
fast: { minute: 60, month: 320000 }
|
|
997
|
+
}
|
|
998
|
+
},
|
|
999
|
+
{
|
|
1000
|
+
key: "bus",
|
|
1001
|
+
name: "Business",
|
|
1002
|
+
rateLimits: {
|
|
1003
|
+
scrapeUrl: { minute: 60, month: 200000 },
|
|
1004
|
+
bulk: { minute: 60, month: 200000 },
|
|
1005
|
+
fast: { minute: 60, month: 2000000 }
|
|
1006
|
+
}
|
|
1007
|
+
},
|
|
1008
|
+
{
|
|
1009
|
+
key: "bus+",
|
|
1010
|
+
name: "Business+",
|
|
1011
|
+
rateLimits: {
|
|
1012
|
+
scrapeUrl: { minute: 60, month: 500000 },
|
|
1013
|
+
bulk: { minute: 60, month: 500000 },
|
|
1014
|
+
fast: { minute: 120, month: 5000000 }
|
|
1015
|
+
}
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
key: "ent",
|
|
1019
|
+
name: "Enterprise",
|
|
1020
|
+
rateLimits: {
|
|
1021
|
+
scrapeUrl: { minute: 60, month: 1500000 },
|
|
1022
|
+
bulk: { minute: 60, month: 1500000 },
|
|
1023
|
+
fast: { minute: 360, month: 15000000 }
|
|
1024
|
+
}
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
key: "prod",
|
|
1028
|
+
name: "Production",
|
|
1029
|
+
rateLimits: {
|
|
1030
|
+
scrapeUrl: { minute: 60, month: 1500000 },
|
|
1031
|
+
bulk: { minute: 60, month: 1500000 },
|
|
1032
|
+
fast: { minute: 360, month: 15000000 }
|
|
1033
|
+
}
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
key: "chat",
|
|
1037
|
+
name: "Chat",
|
|
1038
|
+
rateLimits: {
|
|
1039
|
+
scrapeUrl: { minute: 60, month: 1500000 },
|
|
1040
|
+
bulk: { minute: 60, month: 1500000 },
|
|
1041
|
+
fast: { minute: 360, month: 15000000 }
|
|
1042
|
+
}
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
key: "self",
|
|
1046
|
+
name: "Self",
|
|
1047
|
+
rateLimits: {
|
|
1048
|
+
scrapeUrl: { minute: 6000, month: 1500000 },
|
|
1049
|
+
bulk: { minute: 6000, month: 1500000 },
|
|
1050
|
+
fast: { minute: 36000, month: 15000000 }
|
|
1051
|
+
}
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
key: "cons",
|
|
1055
|
+
name: "Consumer",
|
|
1056
|
+
rateLimits: {
|
|
1057
|
+
scrapeUrl: { minute: 60, month: 3000 },
|
|
1058
|
+
bulk: { minute: 60, month: 3000 },
|
|
1059
|
+
fast: { minute: 120, month: 30000 }
|
|
1060
|
+
}
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
key: "stup",
|
|
1064
|
+
name: "Startup",
|
|
1065
|
+
rateLimits: {
|
|
1066
|
+
scrapeUrl: { minute: 60, month: 30000 },
|
|
1067
|
+
bulk: { minute: 60, month: 30000 },
|
|
1068
|
+
fast: { minute: 360, month: 300000 }
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
key: "busn",
|
|
1073
|
+
name: "Business Network",
|
|
1074
|
+
rateLimits: {
|
|
1075
|
+
scrapeUrl: { minute: 60, month: 300000 },
|
|
1076
|
+
bulk: { minute: 60, month: 300000 },
|
|
1077
|
+
fast: { minute: 360, month: 3000000 }
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
];
|
|
1081
|
+
var getUserPlan = (apiKey) => {
|
|
1082
|
+
const planKey = apiKey.split("|")[0];
|
|
1083
|
+
const plan = planLimits.find((p) => p.key === planKey);
|
|
1084
|
+
if (!plan) {
|
|
1085
|
+
throw new Error("Invalid API key");
|
|
1086
|
+
}
|
|
1087
|
+
return plan;
|
|
1088
|
+
};
|
|
1089
|
+
var minMs = 60 * 1000;
|
|
1090
|
+
var monthMs = 60 * 60 * 24 * 30 * 1000;
|
|
1091
|
+
var getLimiters = (planKey) => {
|
|
1092
|
+
const plan = getUserPlan(planKey);
|
|
1093
|
+
const scrapeUrlMinLimiter = new import_bottleneck.default({
|
|
1094
|
+
reservoir: plan.rateLimits.scrapeUrl.minute,
|
|
1095
|
+
reservoirRefreshAmount: plan.rateLimits.scrapeUrl.minute,
|
|
1096
|
+
reservoirRefreshInterval: minMs
|
|
1097
|
+
});
|
|
1098
|
+
const scrapeUrlMonthLimiter = new import_bottleneck.default({
|
|
1099
|
+
reservoir: plan.rateLimits.scrapeUrl.month,
|
|
1100
|
+
reservoirRefreshAmount: plan.rateLimits.scrapeUrl.month,
|
|
1101
|
+
reservoirRefreshInterval: monthMs
|
|
1102
|
+
});
|
|
1103
|
+
const scrapeUrlLimiter = scrapeUrlMinLimiter.chain(scrapeUrlMonthLimiter);
|
|
1104
|
+
const bulkMinLimiter = new import_bottleneck.default({
|
|
1105
|
+
reservoir: plan.rateLimits.bulk.minute,
|
|
1106
|
+
reservoirRefreshAmount: plan.rateLimits.bulk.minute,
|
|
1107
|
+
reservoirRefreshInterval: minMs
|
|
1108
|
+
});
|
|
1109
|
+
const bulkMonthLimiter = new import_bottleneck.default({
|
|
1110
|
+
reservoir: plan.rateLimits.bulk.month,
|
|
1111
|
+
reservoirRefreshAmount: plan.rateLimits.bulk.month,
|
|
1112
|
+
reservoirRefreshInterval: monthMs
|
|
1113
|
+
});
|
|
1114
|
+
const bulkLimiter = bulkMinLimiter.chain(bulkMonthLimiter);
|
|
1115
|
+
const fastMinLimiter = new import_bottleneck.default({
|
|
1116
|
+
reservoir: plan.rateLimits.fast.minute,
|
|
1117
|
+
reservoirRefreshAmount: plan.rateLimits.fast.minute,
|
|
1118
|
+
reservoirRefreshInterval: minMs
|
|
1119
|
+
});
|
|
1120
|
+
const fastMonthLimiter = new import_bottleneck.default({
|
|
1121
|
+
reservoir: plan.rateLimits.fast.month,
|
|
1122
|
+
reservoirRefreshAmount: plan.rateLimits.fast.month,
|
|
1123
|
+
reservoirRefreshInterval: monthMs
|
|
1124
|
+
});
|
|
1125
|
+
const fastLimiter = fastMinLimiter.chain(fastMonthLimiter);
|
|
1126
|
+
return {
|
|
1127
|
+
scrapeUrl: scrapeUrlLimiter,
|
|
1128
|
+
bulk: bulkLimiter,
|
|
1129
|
+
fast: fastLimiter
|
|
1130
|
+
};
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
// src/client.ts
|
|
1134
|
+
var import_openai = require("openai");
|
|
1135
|
+
var import_zod7 = __toESM(require("zod"));
|
|
1136
|
+
|
|
1137
|
+
// src/search/result.ts
|
|
1138
|
+
class Result {
|
|
1139
|
+
url_hash;
|
|
1140
|
+
url;
|
|
1141
|
+
netloc;
|
|
1142
|
+
published;
|
|
1143
|
+
visited;
|
|
1144
|
+
language;
|
|
1145
|
+
author;
|
|
1146
|
+
title;
|
|
1147
|
+
description;
|
|
1148
|
+
content;
|
|
1149
|
+
best_chunk;
|
|
1150
|
+
semantics;
|
|
1151
|
+
brand_safety;
|
|
1152
|
+
continent;
|
|
1153
|
+
region;
|
|
1154
|
+
country;
|
|
1155
|
+
sector;
|
|
1156
|
+
industry_group;
|
|
1157
|
+
industry;
|
|
1158
|
+
sub_industry;
|
|
1159
|
+
iab_tier_1;
|
|
1160
|
+
iab_tier_2;
|
|
1161
|
+
iab_tier_3;
|
|
1162
|
+
iab_tier_4;
|
|
1163
|
+
client;
|
|
1164
|
+
constructor(params) {
|
|
1165
|
+
this.client = params.client;
|
|
1166
|
+
Object.assign(this, params.result);
|
|
1167
|
+
}
|
|
1168
|
+
static fromFlatten = (client, flatten) => {
|
|
1169
|
+
const unflattened = {
|
|
1170
|
+
...flatten,
|
|
1171
|
+
semantics: {
|
|
1172
|
+
origin_shard: flatten.origin_shard,
|
|
1173
|
+
chunks_total: flatten.chunks_total,
|
|
1174
|
+
chunks_matched: flatten.chunks_matched,
|
|
1175
|
+
chunks_kept: flatten.chunks_kept,
|
|
1176
|
+
similarity: flatten.similarity
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
return new Result({
|
|
1180
|
+
client,
|
|
1181
|
+
result: unflattened
|
|
1182
|
+
});
|
|
1183
|
+
};
|
|
1184
|
+
getSentiment = async (model) => {
|
|
1185
|
+
if (!this.client.llmClient) {
|
|
1186
|
+
throw new Error("A Nosible client instance must be provided with a OpenRouter API key.");
|
|
1187
|
+
}
|
|
1188
|
+
return getSentiment({
|
|
1189
|
+
text: this.content,
|
|
1190
|
+
model,
|
|
1191
|
+
llmClient: this.client.llmClient
|
|
1192
|
+
});
|
|
1193
|
+
};
|
|
1194
|
+
getSimilar = async (params) => {
|
|
1195
|
+
return this.client.fastSearch({
|
|
1196
|
+
question: this.title,
|
|
1197
|
+
excludeDocs: [this.url_hash],
|
|
1198
|
+
...params
|
|
1199
|
+
});
|
|
1200
|
+
};
|
|
1201
|
+
scrapeUrl = async () => {
|
|
1202
|
+
return this.client.scrapeUrl(this.url);
|
|
1203
|
+
};
|
|
1204
|
+
flatten = () => {
|
|
1205
|
+
return {
|
|
1206
|
+
url_hash: this.url_hash,
|
|
1207
|
+
url: this.url,
|
|
1208
|
+
netloc: this.netloc,
|
|
1209
|
+
published: this.published,
|
|
1210
|
+
visited: this.visited,
|
|
1211
|
+
language: this.language,
|
|
1212
|
+
author: this.author,
|
|
1213
|
+
title: this.title,
|
|
1214
|
+
description: this.description,
|
|
1215
|
+
content: this.content,
|
|
1216
|
+
best_chunk: this.best_chunk,
|
|
1217
|
+
origin_shard: this.semantics.origin_shard,
|
|
1218
|
+
chunks_total: this.semantics.chunks_total,
|
|
1219
|
+
chunks_matched: this.semantics.chunks_matched,
|
|
1220
|
+
chunks_kept: this.semantics.chunks_kept,
|
|
1221
|
+
similarity: this.semantics.similarity,
|
|
1222
|
+
brand_safety: this.brand_safety,
|
|
1223
|
+
continent: this.continent,
|
|
1224
|
+
region: this.region,
|
|
1225
|
+
country: this.country,
|
|
1226
|
+
sector: this.sector,
|
|
1227
|
+
industry_group: this.industry_group,
|
|
1228
|
+
industry: this.industry,
|
|
1229
|
+
sub_industry: this.sub_industry,
|
|
1230
|
+
iab_tier_1: this.iab_tier_1,
|
|
1231
|
+
iab_tier_2: this.iab_tier_2,
|
|
1232
|
+
iab_tier_3: this.iab_tier_3,
|
|
1233
|
+
iab_tier_4: this.iab_tier_4
|
|
1234
|
+
};
|
|
1235
|
+
};
|
|
1236
|
+
data = () => {
|
|
1237
|
+
return {
|
|
1238
|
+
url_hash: this.url_hash,
|
|
1239
|
+
url: this.url,
|
|
1240
|
+
netloc: this.netloc,
|
|
1241
|
+
published: this.published,
|
|
1242
|
+
visited: this.visited,
|
|
1243
|
+
language: this.language,
|
|
1244
|
+
author: this.author,
|
|
1245
|
+
title: this.title,
|
|
1246
|
+
description: this.description,
|
|
1247
|
+
content: this.content,
|
|
1248
|
+
best_chunk: this.best_chunk,
|
|
1249
|
+
brand_safety: this.brand_safety,
|
|
1250
|
+
continent: this.continent,
|
|
1251
|
+
region: this.region,
|
|
1252
|
+
country: this.country,
|
|
1253
|
+
sector: this.sector,
|
|
1254
|
+
industry_group: this.industry_group,
|
|
1255
|
+
industry: this.industry,
|
|
1256
|
+
sub_industry: this.sub_industry,
|
|
1257
|
+
iab_tier_1: this.iab_tier_1,
|
|
1258
|
+
iab_tier_2: this.iab_tier_2,
|
|
1259
|
+
iab_tier_3: this.iab_tier_3,
|
|
1260
|
+
iab_tier_4: this.iab_tier_4,
|
|
1261
|
+
semantics: this.semantics
|
|
1262
|
+
};
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
// src/search/resultSet.ts
|
|
1267
|
+
var import_lunr = __toESM(require("lunr"));
|
|
1268
|
+
|
|
1269
|
+
// src/search/analyze.ts
|
|
1270
|
+
var import_simple_statistics = require("simple-statistics");
|
|
1271
|
+
var analyzeResults = (results, by) => {
|
|
1272
|
+
switch (by) {
|
|
1273
|
+
case 0 /* netloc */:
|
|
1274
|
+
const netlocValues = results.map((r) => r.netloc);
|
|
1275
|
+
const netlocStats = analyzeCategorical(netlocValues);
|
|
1276
|
+
return netlocStats;
|
|
1277
|
+
case 1 /* published */:
|
|
1278
|
+
const publishedValues = results.map((r) => new Date(r.published));
|
|
1279
|
+
const publishedStats = analyzeDateByMonth(publishedValues);
|
|
1280
|
+
return publishedStats;
|
|
1281
|
+
case 2 /* visited */:
|
|
1282
|
+
const visitedValues = results.map((r) => new Date(r.visited));
|
|
1283
|
+
const visitedStats = analyzeDateByMonth(visitedValues);
|
|
1284
|
+
return visitedStats;
|
|
1285
|
+
case 3 /* author */:
|
|
1286
|
+
const authorValues = results.map((r) => {
|
|
1287
|
+
if (r.author) {
|
|
1288
|
+
return r.author;
|
|
1289
|
+
} else {
|
|
1290
|
+
return "Unknown Author";
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
const authorStats = analyzeCategorical(authorValues);
|
|
1294
|
+
return authorStats;
|
|
1295
|
+
case 4 /* language */:
|
|
1296
|
+
const languageValues = results.map((r) => r.language);
|
|
1297
|
+
const languageStats = analyzeCategorical(languageValues);
|
|
1298
|
+
return languageStats;
|
|
1299
|
+
case 5 /* similarity */:
|
|
1300
|
+
const simValues = results.map((r) => r.semantics.similarity);
|
|
1301
|
+
const simStats = analyzeNumeric(simValues);
|
|
1302
|
+
return simStats;
|
|
1303
|
+
default:
|
|
1304
|
+
return {};
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
var analyzeCategorical = (arr) => {
|
|
1308
|
+
const result = {};
|
|
1309
|
+
for (const v of arr) {
|
|
1310
|
+
if (result[v]) {
|
|
1311
|
+
result[v] += 1;
|
|
1312
|
+
} else {
|
|
1313
|
+
result[v] = 1;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
return result;
|
|
1317
|
+
};
|
|
1318
|
+
var analyzeNumeric = (arr) => {
|
|
1319
|
+
const meanValue = import_simple_statistics.mean(arr);
|
|
1320
|
+
const stdValue = import_simple_statistics.standardDeviation(arr);
|
|
1321
|
+
const minValue = import_simple_statistics.min(arr);
|
|
1322
|
+
const maxValue = import_simple_statistics.max(arr);
|
|
1323
|
+
const q25 = import_simple_statistics.quantile(arr, 0.25);
|
|
1324
|
+
const q50 = import_simple_statistics.quantile(arr, 0.5);
|
|
1325
|
+
const q75 = import_simple_statistics.quantile(arr, 0.75);
|
|
1326
|
+
return {
|
|
1327
|
+
count: arr.length,
|
|
1328
|
+
null_count: arr.filter((v) => v === null).length,
|
|
1329
|
+
mean: meanValue,
|
|
1330
|
+
std: stdValue,
|
|
1331
|
+
min: minValue,
|
|
1332
|
+
q25,
|
|
1333
|
+
q50,
|
|
1334
|
+
q75,
|
|
1335
|
+
max: maxValue
|
|
1336
|
+
};
|
|
1337
|
+
};
|
|
1338
|
+
var analyzeDateByMonth = (arr) => {
|
|
1339
|
+
if (!arr || arr.length === 0)
|
|
1340
|
+
return {};
|
|
1341
|
+
let minDate = null;
|
|
1342
|
+
let maxDate = null;
|
|
1343
|
+
const counts = {};
|
|
1344
|
+
for (const d of arr) {
|
|
1345
|
+
if (!(d instanceof Date))
|
|
1346
|
+
continue;
|
|
1347
|
+
const time = d.getTime();
|
|
1348
|
+
if (Number.isNaN(time))
|
|
1349
|
+
continue;
|
|
1350
|
+
if (!minDate || d < minDate)
|
|
1351
|
+
minDate = d;
|
|
1352
|
+
if (!maxDate || d > maxDate)
|
|
1353
|
+
maxDate = d;
|
|
1354
|
+
const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
|
|
1355
|
+
counts[key] = (counts[key] ?? 0) + 1;
|
|
1356
|
+
}
|
|
1357
|
+
if (!minDate || !maxDate)
|
|
1358
|
+
return {};
|
|
1359
|
+
const result = {};
|
|
1360
|
+
let y = minDate.getFullYear();
|
|
1361
|
+
let m = minDate.getMonth() + 1;
|
|
1362
|
+
const endY = maxDate.getFullYear();
|
|
1363
|
+
const endM = maxDate.getMonth() + 1;
|
|
1364
|
+
while (y < endY || y === endY && m <= endM) {
|
|
1365
|
+
const key = `${y}-${String(m).padStart(2, "0")}`;
|
|
1366
|
+
result[key] = counts[key] ?? 0;
|
|
1367
|
+
m += 1;
|
|
1368
|
+
if (m > 12) {
|
|
1369
|
+
m = 1;
|
|
1370
|
+
y += 1;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return result;
|
|
1374
|
+
};
|
|
1375
|
+
|
|
1376
|
+
// src/search/resultSet.ts
|
|
1377
|
+
class ResultSet {
|
|
1378
|
+
results;
|
|
1379
|
+
constructor(results) {
|
|
1380
|
+
this.results = results;
|
|
1381
|
+
}
|
|
1382
|
+
static async fromFilePath(filePath, client) {
|
|
1383
|
+
if (filePath.endsWith(".json")) {
|
|
1384
|
+
const json = await importJson({ filePath });
|
|
1385
|
+
const results = json.map((result) => {
|
|
1386
|
+
return new Result({ client, result });
|
|
1387
|
+
});
|
|
1388
|
+
return new ResultSet(results);
|
|
1389
|
+
} else if (filePath.endsWith(".csv")) {
|
|
1390
|
+
const csv = await importCsv({ filePath });
|
|
1391
|
+
const results = csv.map((result) => {
|
|
1392
|
+
return Result.fromFlatten(client, result);
|
|
1393
|
+
});
|
|
1394
|
+
return new ResultSet(results);
|
|
1395
|
+
} else {
|
|
1396
|
+
throw new Error("Unsupported file type");
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
static async fromFile(file, client) {
|
|
1400
|
+
if (file.name.endsWith(".json")) {
|
|
1401
|
+
const json = await importJson({ file });
|
|
1402
|
+
const results = json.map((result) => {
|
|
1403
|
+
return new Result({ client, result });
|
|
1404
|
+
});
|
|
1405
|
+
return new ResultSet(results);
|
|
1406
|
+
} else if (file.name.endsWith(".csv")) {
|
|
1407
|
+
const csv = await importCsv({ file });
|
|
1408
|
+
const results = csv.map((result) => {
|
|
1409
|
+
return new Result({ client, result });
|
|
1410
|
+
});
|
|
1411
|
+
return new ResultSet(results);
|
|
1412
|
+
} else {
|
|
1413
|
+
throw new Error("Unsupported file type");
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
static fromResults(results, searchQuery, client) {
|
|
1417
|
+
const processedResults = results.map((result) => {
|
|
1418
|
+
if (result instanceof Result) {
|
|
1419
|
+
return result;
|
|
1420
|
+
} else {
|
|
1421
|
+
const fullResult = { ...searchQuery, ...result };
|
|
1422
|
+
return new Result({ client, result: fullResult });
|
|
1423
|
+
}
|
|
1424
|
+
});
|
|
1425
|
+
return new ResultSet(processedResults);
|
|
1426
|
+
}
|
|
1427
|
+
static join(resultSets) {
|
|
1428
|
+
const newSet = [];
|
|
1429
|
+
resultSets.forEach((resultSet) => newSet.push(...resultSet.results));
|
|
1430
|
+
return new ResultSet(newSet);
|
|
1431
|
+
}
|
|
1432
|
+
getResults = () => {
|
|
1433
|
+
return this.results.map((result) => result.data());
|
|
1434
|
+
};
|
|
1435
|
+
getFlattenResults = () => {
|
|
1436
|
+
return this.results.map((result) => result.flatten());
|
|
1437
|
+
};
|
|
1438
|
+
findInResults = (query) => {
|
|
1439
|
+
const results = this.results;
|
|
1440
|
+
const index = import_lunr.default(function() {
|
|
1441
|
+
this.ref("index");
|
|
1442
|
+
this.field("content");
|
|
1443
|
+
results.forEach((result, i) => {
|
|
1444
|
+
this.add({
|
|
1445
|
+
index: i,
|
|
1446
|
+
content: result.content
|
|
1447
|
+
});
|
|
1448
|
+
});
|
|
1449
|
+
});
|
|
1450
|
+
const hits = index.search(query);
|
|
1451
|
+
console.log("Number of results: " + this.results.length);
|
|
1452
|
+
const matchedResults = [];
|
|
1453
|
+
hits.forEach((hit) => {
|
|
1454
|
+
let index2 = Number(hit.ref);
|
|
1455
|
+
const found = this.results[index2];
|
|
1456
|
+
if (found) {
|
|
1457
|
+
matchedResults.push(found);
|
|
1458
|
+
} else {
|
|
1459
|
+
console.warn(`findInSearchResults: Hit not found (index ${index2})`);
|
|
1460
|
+
}
|
|
1461
|
+
});
|
|
1462
|
+
console.log("Number of hits: " + hits.length);
|
|
1463
|
+
console.log("Number of matchedResults: " + matchedResults.length);
|
|
1464
|
+
console.log("matchedResults: ", typeof matchedResults);
|
|
1465
|
+
return matchedResults;
|
|
1466
|
+
};
|
|
1467
|
+
analyze = (by) => {
|
|
1468
|
+
return analyzeResults(this.results, by);
|
|
1469
|
+
};
|
|
1470
|
+
toPolars = async () => {
|
|
1471
|
+
if (isBrowser()) {
|
|
1472
|
+
throw new Error("toPolars is not supported in the browser");
|
|
1473
|
+
} else {
|
|
1474
|
+
const pl = await import("nodejs-polars");
|
|
1475
|
+
const flattenedData = this.getFlattenResults();
|
|
1476
|
+
const df = pl.DataFrame(flattenedData);
|
|
1477
|
+
return df;
|
|
1478
|
+
}
|
|
1479
|
+
};
|
|
1480
|
+
writeToCsv = async (fileName) => {
|
|
1481
|
+
const flattenedData = this.getFlattenResults();
|
|
1482
|
+
await exportCsv(flattenedData, fileName);
|
|
1483
|
+
};
|
|
1484
|
+
writeToParquet = async (fileName) => {
|
|
1485
|
+
if (isBrowser()) {
|
|
1486
|
+
throw new Error("writeToParquet is not supported in the browser");
|
|
1487
|
+
} else {
|
|
1488
|
+
const pl = await import("nodejs-polars");
|
|
1489
|
+
const flattenedData = this.getFlattenResults();
|
|
1490
|
+
const df = pl.DataFrame(flattenedData);
|
|
1491
|
+
await df.writeParquet(fileName);
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
writeToIpc = async (fileName) => {
|
|
1495
|
+
if (isBrowser()) {
|
|
1496
|
+
throw new Error("writeToIpc is not supported in the browser");
|
|
1497
|
+
} else {
|
|
1498
|
+
const pl = await import("nodejs-polars");
|
|
1499
|
+
const flattenedData = this.getFlattenResults();
|
|
1500
|
+
const df = pl.DataFrame(flattenedData);
|
|
1501
|
+
await df.writeIPC(fileName);
|
|
1502
|
+
}
|
|
1503
|
+
};
|
|
1504
|
+
writeToJson = async (fileName) => {
|
|
1505
|
+
await exportJson(this.getResults(), fileName);
|
|
1506
|
+
};
|
|
1507
|
+
writeToNdjson = async (fileName) => {
|
|
1508
|
+
const flattenedData = this.getFlattenResults();
|
|
1509
|
+
await exportNdjson(flattenedData, fileName);
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
// src/search/resultFactory.ts
|
|
1514
|
+
function createResult(client, result) {
|
|
1515
|
+
return new Result({ client, result });
|
|
1516
|
+
}
|
|
1517
|
+
function createResultSet(client, rawResults) {
|
|
1518
|
+
const resultInstances = rawResults.map((result) => createResult(client, result));
|
|
1519
|
+
return new ResultSet(resultInstances);
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
// src/search/bulkSearch.ts
|
|
1523
|
+
var import_zlib = require("zlib");
|
|
1524
|
+
|
|
1525
|
+
// src/utils/fernet.ts
|
|
1526
|
+
var import_crypto = require("crypto");
|
|
1527
|
+
var fernetDecrypt = (token, key) => {
|
|
1528
|
+
try {
|
|
1529
|
+
const keyBuffer = Buffer.from(key, "base64");
|
|
1530
|
+
const signingKey = keyBuffer.subarray(0, 16);
|
|
1531
|
+
const encryptionKey = keyBuffer.subarray(16, 32);
|
|
1532
|
+
const hmac = token.subarray(token.length - 32);
|
|
1533
|
+
const payload = token.subarray(0, token.length - 32);
|
|
1534
|
+
const expectedHmac = import_crypto.createHmac("sha256", signingKey).update(payload).digest();
|
|
1535
|
+
if (!import_crypto.timingSafeEqual(hmac, expectedHmac)) {
|
|
1536
|
+
throw new Error("HMAC verification failed");
|
|
1537
|
+
}
|
|
1538
|
+
const version = payload[0];
|
|
1539
|
+
if (version !== 128) {
|
|
1540
|
+
throw new Error(`Unsupported Fernet version: ${version}`);
|
|
1541
|
+
}
|
|
1542
|
+
const iv = payload.subarray(9, 25);
|
|
1543
|
+
const ciphertext = payload.subarray(25);
|
|
1544
|
+
const decipher = import_crypto.createDecipheriv("aes-128-cbc", encryptionKey, iv);
|
|
1545
|
+
const decrypted = Buffer.concat([
|
|
1546
|
+
decipher.update(ciphertext),
|
|
1547
|
+
decipher.final()
|
|
1548
|
+
]);
|
|
1549
|
+
return decrypted;
|
|
1550
|
+
} catch (error) {
|
|
1551
|
+
console.error("Error decrypting data:", error);
|
|
1552
|
+
throw error;
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1555
|
+
|
|
1556
|
+
// src/search/bulkSearch.ts
|
|
1557
|
+
async function bulkSearchDownload({
|
|
1558
|
+
downloadFrom,
|
|
1559
|
+
decryptUsing
|
|
1560
|
+
}) {
|
|
1561
|
+
if (downloadFrom.includes(".zstd.")) {
|
|
1562
|
+
downloadFrom = downloadFrom.replace(".zstd.", ".gzip.");
|
|
1563
|
+
} else {
|
|
1564
|
+
throw new Error("Results were not retrieved from Nosible");
|
|
1565
|
+
}
|
|
1566
|
+
try {
|
|
1567
|
+
for (let attempt = 0;attempt < 100; attempt++) {
|
|
1568
|
+
const response = await fetch(downloadFrom);
|
|
1569
|
+
if (response.status === 200) {
|
|
1570
|
+
try {
|
|
1571
|
+
const responseData = await response.arrayBuffer();
|
|
1572
|
+
const encryptedData = Buffer.from(responseData);
|
|
1573
|
+
const tokenBuffer = Buffer.from(encryptedData.toString("utf-8"), "base64");
|
|
1574
|
+
const decrypted = fernetDecrypt(tokenBuffer, decryptUsing);
|
|
1575
|
+
const decompressed = import_zlib.gunzipSync(decrypted);
|
|
1576
|
+
const apiResp = JSON.parse(decompressed.toString("utf-8"));
|
|
1577
|
+
return apiResp;
|
|
1578
|
+
} catch (error) {
|
|
1579
|
+
console.error("Error decrypting data:", error);
|
|
1580
|
+
break;
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
await new Promise((resolve) => setTimeout(resolve, 1e4));
|
|
1584
|
+
}
|
|
1585
|
+
} catch (error) {
|
|
1586
|
+
console.error("Error downloading data:", error);
|
|
1587
|
+
throw error;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
// src/search/searchSet.ts
|
|
1592
|
+
var import_zod6 = require("zod");
|
|
1593
|
+
var searchSetParams = import_zod6.z.union([
|
|
1594
|
+
import_zod6.z.object({
|
|
1595
|
+
searches: import_zod6.z.array(import_zod6.z.instanceof(Search))
|
|
1596
|
+
}),
|
|
1597
|
+
import_zod6.z.array(import_zod6.z.instanceof(Search))
|
|
1598
|
+
]);
|
|
1599
|
+
|
|
1600
|
+
class SearchSet {
|
|
1601
|
+
searches = [];
|
|
1602
|
+
index;
|
|
1603
|
+
constructor(params) {
|
|
1604
|
+
if (Array.isArray(params)) {
|
|
1605
|
+
this.searches = params;
|
|
1606
|
+
} else {
|
|
1607
|
+
this.searches = params.searches;
|
|
1608
|
+
}
|
|
1609
|
+
this.index = 0;
|
|
1610
|
+
}
|
|
1611
|
+
static async fromFilePath(filePath) {
|
|
1612
|
+
if (filePath.endsWith(".json")) {
|
|
1613
|
+
const searches = await importJson({ filePath });
|
|
1614
|
+
return new SearchSet(searches.map((search) => new Search(search)));
|
|
1615
|
+
} else if (filePath.endsWith(".csv")) {
|
|
1616
|
+
const searches = await importCsv({ filePath });
|
|
1617
|
+
return new SearchSet(searches.map((search) => new Search(search)));
|
|
1618
|
+
} else
|
|
1619
|
+
throw new Error("Unsupported file type");
|
|
1620
|
+
}
|
|
1621
|
+
static async fromFile(file) {
|
|
1622
|
+
if (file.name.endsWith(".json")) {
|
|
1623
|
+
const searches = await importJson({ file });
|
|
1624
|
+
return new SearchSet(searches.map((search) => new Search(search)));
|
|
1625
|
+
} else if (file.name.endsWith(".csv")) {
|
|
1626
|
+
const searches = await importCsv({ file });
|
|
1627
|
+
return new SearchSet(searches.map((search) => new Search(search)));
|
|
1628
|
+
} else
|
|
1629
|
+
throw new Error("Unsupported file type");
|
|
1630
|
+
}
|
|
1631
|
+
next = () => {
|
|
1632
|
+
this.index++;
|
|
1633
|
+
const search = this.searches[this.index];
|
|
1634
|
+
if (!search) {
|
|
1635
|
+
return null;
|
|
1636
|
+
}
|
|
1637
|
+
return search;
|
|
1638
|
+
};
|
|
1639
|
+
add = (search) => {
|
|
1640
|
+
this.searches.push(search);
|
|
1641
|
+
};
|
|
1642
|
+
remove = (index) => {
|
|
1643
|
+
this.searches.splice(index, 1);
|
|
1644
|
+
};
|
|
1645
|
+
toPolars = async () => {
|
|
1646
|
+
if (isBrowser()) {
|
|
1647
|
+
throw new Error("toPolars is not supported in the browser");
|
|
1648
|
+
} else {
|
|
1649
|
+
const pl = await import("nodejs-polars");
|
|
1650
|
+
const df = pl.DataFrame(this.searches);
|
|
1651
|
+
return df;
|
|
1652
|
+
}
|
|
1653
|
+
};
|
|
1654
|
+
writeToCsv = async (fileName) => {
|
|
1655
|
+
await exportCsv(this.searches, fileName);
|
|
1656
|
+
};
|
|
1657
|
+
writeToJson = async (fileName) => {
|
|
1658
|
+
await exportJson(this.searches, fileName);
|
|
1659
|
+
};
|
|
1660
|
+
writeToNdjson = async (fileName) => {
|
|
1661
|
+
await exportNdjson(this.searches, fileName);
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
// src/client.ts
|
|
1666
|
+
var fastSearchesParamsSchema = import_zod7.default.union([
|
|
1667
|
+
userSearchParamsSchema.omit({ question: true }).extend({
|
|
1668
|
+
questions: import_zod7.default.array(import_zod7.default.string())
|
|
1669
|
+
}),
|
|
1670
|
+
import_zod7.default.instanceof(SearchSet)
|
|
1671
|
+
]);
|
|
1672
|
+
var nosibleClientParams = import_zod7.default.union([
|
|
1673
|
+
import_zod7.default.string(),
|
|
1674
|
+
import_zod7.default.object({
|
|
1675
|
+
apiKey: import_zod7.default.string(),
|
|
1676
|
+
llmApiKey: import_zod7.default.string().optional(),
|
|
1677
|
+
openAiBaseURL: import_zod7.default.string().optional(),
|
|
1678
|
+
sentimentModel: import_zod7.default.string().optional(),
|
|
1679
|
+
expansionsModel: import_zod7.default.string().optional(),
|
|
1680
|
+
searchDefaults: clientDefaultSearchParamsSchema.optional()
|
|
1681
|
+
})
|
|
1682
|
+
]);
|
|
1683
|
+
|
|
1684
|
+
class NosibleClient {
|
|
1685
|
+
baseUrl = "https://www.nosible.ai/search/v2";
|
|
1686
|
+
apiKey;
|
|
1687
|
+
llmClient;
|
|
1688
|
+
expansionsModel = "openai/gpt-4o";
|
|
1689
|
+
searchDefaults;
|
|
1690
|
+
plan;
|
|
1691
|
+
limiters;
|
|
1692
|
+
constructor(params) {
|
|
1693
|
+
let apiKeyToUse;
|
|
1694
|
+
let llmApiKeyToUse;
|
|
1695
|
+
let openAiBaseURL;
|
|
1696
|
+
let searchDefaultsToUse;
|
|
1697
|
+
if (typeof params === "string") {
|
|
1698
|
+
apiKeyToUse = params;
|
|
1699
|
+
} else if (params) {
|
|
1700
|
+
apiKeyToUse = params.apiKey;
|
|
1701
|
+
llmApiKeyToUse = params.llmApiKey;
|
|
1702
|
+
openAiBaseURL = params.openAiBaseURL;
|
|
1703
|
+
searchDefaultsToUse = params.searchDefaults;
|
|
1704
|
+
} else {
|
|
1705
|
+
apiKeyToUse = process.env.NOSIBLE_API_KEY;
|
|
1706
|
+
llmApiKeyToUse = process.env.LLM_API_KEY;
|
|
1707
|
+
}
|
|
1708
|
+
if (!apiKeyToUse) {
|
|
1709
|
+
throw new Error("API key is required");
|
|
1710
|
+
} else {
|
|
1711
|
+
this.verifyAndSetApiKey(apiKeyToUse);
|
|
1712
|
+
}
|
|
1713
|
+
if (llmApiKeyToUse) {
|
|
1714
|
+
this.llmClient = new import_openai.OpenAI({
|
|
1715
|
+
apiKey: llmApiKeyToUse,
|
|
1716
|
+
baseURL: openAiBaseURL
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
this.apiKey = apiKeyToUse;
|
|
1720
|
+
this.searchDefaults = searchDefaultsToUse;
|
|
1721
|
+
this.plan = getUserPlan(this.apiKey);
|
|
1722
|
+
this.limiters = getLimiters(this.apiKey);
|
|
1723
|
+
}
|
|
1724
|
+
mergeWithDefaultSearch(params) {
|
|
1725
|
+
if (!this.searchDefaults) {
|
|
1726
|
+
return params;
|
|
1727
|
+
}
|
|
1728
|
+
return {
|
|
1729
|
+
...this.searchDefaults,
|
|
1730
|
+
...params
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
verifyAndSetApiKey(apiKey) {
|
|
1734
|
+
if (!apiKey) {
|
|
1735
|
+
throw new Error("API key is required");
|
|
1736
|
+
}
|
|
1737
|
+
const splits = apiKey.split("|");
|
|
1738
|
+
if (splits.length !== 2) {
|
|
1739
|
+
throw new Error("API key is invalid - expected format 'key_id|secret_key'");
|
|
1740
|
+
}
|
|
1741
|
+
this.apiKey = apiKey;
|
|
1742
|
+
}
|
|
1743
|
+
async _request(endpoint, body) {
|
|
1744
|
+
return callNosibleApi({
|
|
1745
|
+
endpoint,
|
|
1746
|
+
body,
|
|
1747
|
+
apiKey: this.apiKey
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
async fastSearch(params) {
|
|
1751
|
+
let search;
|
|
1752
|
+
const hasSearchInstance = (params2) => {
|
|
1753
|
+
return "search" in params2;
|
|
1754
|
+
};
|
|
1755
|
+
if (hasSearchInstance(params)) {
|
|
1756
|
+
if (params.search instanceof Search) {
|
|
1757
|
+
search = params.search;
|
|
1758
|
+
} else {
|
|
1759
|
+
throw new Error("Invalid search parameter provided.");
|
|
1760
|
+
}
|
|
1761
|
+
} else {
|
|
1762
|
+
const mergedParams = this.mergeWithDefaultSearch(params);
|
|
1763
|
+
search = new Search(mergedParams);
|
|
1764
|
+
}
|
|
1765
|
+
const body = await search.searchBody({ client: this });
|
|
1766
|
+
const validatedBody = validateFastSearchParams(body);
|
|
1767
|
+
const { message, query, response } = await this._request("fast-search", validatedBody);
|
|
1768
|
+
const results = response.map((result) => {
|
|
1769
|
+
const fullResult = { ...query, ...result };
|
|
1770
|
+
return fullResult;
|
|
1771
|
+
});
|
|
1772
|
+
const resultSet = createResultSet(this, results);
|
|
1773
|
+
return resultSet;
|
|
1774
|
+
}
|
|
1775
|
+
async fastSearches(params) {
|
|
1776
|
+
let searchSet;
|
|
1777
|
+
if (params instanceof SearchSet) {
|
|
1778
|
+
searchSet = params;
|
|
1779
|
+
} else {
|
|
1780
|
+
const { questions, ...sharedParams } = params;
|
|
1781
|
+
const mergedSharedParams = this.mergeWithDefaultSearch(sharedParams);
|
|
1782
|
+
const searches = questions.map((question) => new Search({ question, ...mergedSharedParams }));
|
|
1783
|
+
searchSet = new SearchSet(searches);
|
|
1784
|
+
}
|
|
1785
|
+
const results = await Promise.all(searchSet.searches.map((search) => this.fastSearch({ search })));
|
|
1786
|
+
return results;
|
|
1787
|
+
}
|
|
1788
|
+
async aiSearch(params) {
|
|
1789
|
+
const json = await this._request("search", params);
|
|
1790
|
+
const results = json.response.map((result) => {
|
|
1791
|
+
const fullResult = { ...json.query, ...result };
|
|
1792
|
+
return fullResult;
|
|
1793
|
+
});
|
|
1794
|
+
const resultSet = createResultSet(this, results);
|
|
1795
|
+
return resultSet;
|
|
1796
|
+
}
|
|
1797
|
+
async bulkSearch(params) {
|
|
1798
|
+
let search;
|
|
1799
|
+
const hasSearchInstance = (params2) => {
|
|
1800
|
+
return "search" in params2;
|
|
1801
|
+
};
|
|
1802
|
+
if (hasSearchInstance(params)) {
|
|
1803
|
+
if (params.search instanceof Search) {
|
|
1804
|
+
search = params.search;
|
|
1805
|
+
} else {
|
|
1806
|
+
throw new Error("Invalid search parameter provided.");
|
|
1807
|
+
}
|
|
1808
|
+
} else {
|
|
1809
|
+
const mergedParams = this.mergeWithDefaultSearch(params);
|
|
1810
|
+
search = new Search(mergedParams);
|
|
1811
|
+
}
|
|
1812
|
+
const body = await search.searchBody({ client: this });
|
|
1813
|
+
const validatedBody = validateBulkSearchParams(body);
|
|
1814
|
+
const fileLocation = await this._request("bulk-search", validatedBody);
|
|
1815
|
+
const json = await bulkSearchDownload({
|
|
1816
|
+
downloadFrom: fileLocation.download_from,
|
|
1817
|
+
decryptUsing: fileLocation.decrypt_using
|
|
1818
|
+
});
|
|
1819
|
+
const results = json.response.map((result) => {
|
|
1820
|
+
const fullResult = { ...json.query, ...result };
|
|
1821
|
+
return fullResult;
|
|
1822
|
+
});
|
|
1823
|
+
const resultSet = createResultSet(this, results);
|
|
1824
|
+
return resultSet;
|
|
1825
|
+
}
|
|
1826
|
+
async scrapeUrl(url) {
|
|
1827
|
+
return this.limiters.scrapeUrl.schedule(async () => {
|
|
1828
|
+
const json = await this._request("scrape-url", { url });
|
|
1829
|
+
const webPage = new WebPageData(this, json.response);
|
|
1830
|
+
return webPage;
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
async topicTrend(query, sqlFilter) {
|
|
1834
|
+
const body = { query, sql_filter: sqlFilter };
|
|
1835
|
+
const json = await this._request("topic-trend", body);
|
|
1836
|
+
const topicTrend = new TopicTrend(json);
|
|
1837
|
+
return topicTrend;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
//# debugId=E7A50C56345E2B0F64756E2164756E21
|