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
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
import {describe, it, expect, beforeEach} from "bun:test";
|
|
2
|
+
import {NosibleClient, type FastSearchesParamsType} from "./client";
|
|
3
|
+
import {Result} from "./search/result";
|
|
4
|
+
import {Search} from "./search/search";
|
|
5
|
+
import {SearchSet} from "./search/searchSet";
|
|
6
|
+
import {type ContinentEnum} from "./api/schemas";
|
|
7
|
+
|
|
8
|
+
describe("NosibleClient", () => {
|
|
9
|
+
let client: NosibleClient;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
// Create genuine client - will use environment variable NOSIBLE_API_KEY
|
|
13
|
+
client = new NosibleClient();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("fastSearch", () => {
|
|
17
|
+
it("should return search results", async () => {
|
|
18
|
+
const searchResultSet = await client.fastSearch({
|
|
19
|
+
question: "artificial intelligence machine learning",
|
|
20
|
+
nResults: 10,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(searchResultSet).toBeDefined();
|
|
24
|
+
expect(searchResultSet.results).toBeDefined();
|
|
25
|
+
expect(searchResultSet.results.length).toBeGreaterThan(0);
|
|
26
|
+
|
|
27
|
+
// Get first result with proper type guard
|
|
28
|
+
const firstResult = searchResultSet.results[0];
|
|
29
|
+
if (!firstResult) {
|
|
30
|
+
throw new Error("Expected first result to be defined");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
expect(firstResult).toBeInstanceOf(Result);
|
|
34
|
+
expect(firstResult.url_hash).toBeDefined();
|
|
35
|
+
expect(firstResult.url).toBeDefined();
|
|
36
|
+
expect(firstResult.title).toBeDefined();
|
|
37
|
+
expect(firstResult.content).toBeDefined();
|
|
38
|
+
|
|
39
|
+
console.log(
|
|
40
|
+
`Found ${searchResultSet.results.length} results via fastSearch`
|
|
41
|
+
);
|
|
42
|
+
console.log(`First result: ${firstResult.title}`);
|
|
43
|
+
}, 10000);
|
|
44
|
+
|
|
45
|
+
it("should handle different search parameters", async () => {
|
|
46
|
+
const searchResultSet = await client.fastSearch({
|
|
47
|
+
question: "blockchain cryptocurrency",
|
|
48
|
+
nResults: 10,
|
|
49
|
+
minSimilarity: 0.7,
|
|
50
|
+
algorithm: "hybrid-2",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(searchResultSet).toBeDefined();
|
|
54
|
+
expect(searchResultSet.results).toBeDefined();
|
|
55
|
+
expect(searchResultSet.results.length).toBeGreaterThan(0);
|
|
56
|
+
|
|
57
|
+
console.log(
|
|
58
|
+
`Search with filters returned ${searchResultSet.results.length} results`
|
|
59
|
+
);
|
|
60
|
+
}, 10000);
|
|
61
|
+
|
|
62
|
+
it("should handle language filters", async () => {
|
|
63
|
+
const searchResultSet = await client.fastSearch({
|
|
64
|
+
question: "intelligence artificielle",
|
|
65
|
+
nResults: 10,
|
|
66
|
+
language: "fr",
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(searchResultSet).toBeDefined();
|
|
70
|
+
expect(searchResultSet.results).toBeDefined();
|
|
71
|
+
|
|
72
|
+
console.log(
|
|
73
|
+
`French search returned ${searchResultSet.results.length} results`
|
|
74
|
+
);
|
|
75
|
+
}, 10000);
|
|
76
|
+
|
|
77
|
+
it("should work with a Search instance", async () => {
|
|
78
|
+
const search = new Search({
|
|
79
|
+
question: "quantum computing technology",
|
|
80
|
+
nResults: 15,
|
|
81
|
+
algorithm: "hybrid-2",
|
|
82
|
+
minSimilarity: 0.7,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const searchResultSet = await client.fastSearch({search});
|
|
86
|
+
|
|
87
|
+
expect(searchResultSet).toBeDefined();
|
|
88
|
+
expect(searchResultSet.results).toBeDefined();
|
|
89
|
+
expect(searchResultSet.results.length).toBeGreaterThan(0);
|
|
90
|
+
|
|
91
|
+
const firstResult = searchResultSet.results[0];
|
|
92
|
+
if (!firstResult) {
|
|
93
|
+
throw new Error("Expected first result to be defined");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
expect(firstResult).toBeInstanceOf(Result);
|
|
97
|
+
expect(firstResult.url_hash).toBeDefined();
|
|
98
|
+
expect(firstResult.url).toBeDefined();
|
|
99
|
+
expect(firstResult.title).toBeDefined();
|
|
100
|
+
expect(firstResult.content).toBeDefined();
|
|
101
|
+
|
|
102
|
+
console.log(
|
|
103
|
+
`Found ${searchResultSet.results.length} results via fastSearch with Search instance`
|
|
104
|
+
);
|
|
105
|
+
console.log(`First result: ${firstResult.title}`);
|
|
106
|
+
}, 10000);
|
|
107
|
+
|
|
108
|
+
it("should work with a Search instance and complex filters", async () => {
|
|
109
|
+
const search = new Search({
|
|
110
|
+
question: "renewable energy solutions",
|
|
111
|
+
nResults: 20,
|
|
112
|
+
algorithm: "hybrid-3",
|
|
113
|
+
minSimilarity: 0.6,
|
|
114
|
+
mustInclude: ["solar", "wind"],
|
|
115
|
+
mustExclude: ["nuclear"],
|
|
116
|
+
continent: "Europe",
|
|
117
|
+
language: "en",
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const searchResultSet = await client.fastSearch({search});
|
|
121
|
+
|
|
122
|
+
expect(searchResultSet).toBeDefined();
|
|
123
|
+
expect(searchResultSet.results).toBeDefined();
|
|
124
|
+
|
|
125
|
+
console.log(
|
|
126
|
+
`Search instance with complex filters returned ${searchResultSet.results.length} results`
|
|
127
|
+
);
|
|
128
|
+
}, 10000);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe("fastSearches", () => {
|
|
132
|
+
it("should handle questions array with shared parameters and return multiple result sets", async () => {
|
|
133
|
+
const params = {
|
|
134
|
+
questions: [
|
|
135
|
+
"artificial intelligence",
|
|
136
|
+
"machine learning",
|
|
137
|
+
"neural networks",
|
|
138
|
+
],
|
|
139
|
+
nResults: 10,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const results = await client.fastSearches(params);
|
|
143
|
+
|
|
144
|
+
expect(results).toBeDefined();
|
|
145
|
+
expect(results).toBeInstanceOf(Array);
|
|
146
|
+
expect(results.length).toBe(3);
|
|
147
|
+
|
|
148
|
+
// Check each result set
|
|
149
|
+
results.forEach((resultSet, index) => {
|
|
150
|
+
expect(resultSet).toBeDefined();
|
|
151
|
+
expect(resultSet.results).toBeDefined();
|
|
152
|
+
expect(resultSet.results.length).toBeGreaterThan(0);
|
|
153
|
+
|
|
154
|
+
const firstResult = resultSet.results[0];
|
|
155
|
+
if (!firstResult) {
|
|
156
|
+
throw new Error(
|
|
157
|
+
`Expected first result to be defined for question ${index}`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
expect(firstResult).toBeInstanceOf(Result);
|
|
162
|
+
expect(firstResult.url_hash).toBeDefined();
|
|
163
|
+
expect(firstResult.url).toBeDefined();
|
|
164
|
+
expect(firstResult.title).toBeDefined();
|
|
165
|
+
expect(firstResult.content).toBeDefined();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
console.log(
|
|
169
|
+
`fastSearches with questions returned ${results.length} result sets`
|
|
170
|
+
);
|
|
171
|
+
results.forEach((resultSet, index) => {
|
|
172
|
+
console.log(
|
|
173
|
+
`Question ${index + 1}: ${resultSet.results.length} results`
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
}, 10000);
|
|
177
|
+
|
|
178
|
+
it("should handle SearchSet input and return multiple result sets", async () => {
|
|
179
|
+
const searches = [
|
|
180
|
+
new Search({question: "blockchain technology", nResults: 10}),
|
|
181
|
+
new Search({question: "cryptocurrency", nResults: 10}),
|
|
182
|
+
new Search({question: "decentralized finance", nResults: 10}),
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
const searchSet = new SearchSet(searches);
|
|
186
|
+
const results = await client.fastSearches(searchSet);
|
|
187
|
+
|
|
188
|
+
expect(results).toBeDefined();
|
|
189
|
+
expect(results).toBeInstanceOf(Array);
|
|
190
|
+
expect(results.length).toBe(3);
|
|
191
|
+
|
|
192
|
+
// Check each result set
|
|
193
|
+
results.forEach((resultSet, index) => {
|
|
194
|
+
expect(resultSet).toBeDefined();
|
|
195
|
+
expect(resultSet.results).toBeDefined();
|
|
196
|
+
expect(resultSet.results.length).toBeGreaterThan(0);
|
|
197
|
+
|
|
198
|
+
const firstResult = resultSet.results[0];
|
|
199
|
+
if (!firstResult) {
|
|
200
|
+
throw new Error(
|
|
201
|
+
`Expected first result to be defined for search ${index}`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
expect(firstResult).toBeInstanceOf(Result);
|
|
206
|
+
expect(firstResult.url_hash).toBeDefined();
|
|
207
|
+
expect(firstResult.url).toBeDefined();
|
|
208
|
+
expect(firstResult.title).toBeDefined();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
console.log(
|
|
212
|
+
`fastSearches with SearchSet returned ${results.length} result sets`
|
|
213
|
+
);
|
|
214
|
+
results.forEach((resultSet, index) => {
|
|
215
|
+
console.log(`Search ${index + 1}: ${resultSet.results.length} results`);
|
|
216
|
+
});
|
|
217
|
+
}, 10000);
|
|
218
|
+
|
|
219
|
+
it("should handle questions array with complex shared parameters", async () => {
|
|
220
|
+
const params = {
|
|
221
|
+
questions: ["renewable energy", "electric vehicles"],
|
|
222
|
+
nResults: 10,
|
|
223
|
+
algorithm: "hybrid-2",
|
|
224
|
+
minSimilarity: 0.7,
|
|
225
|
+
continent: "Europe",
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const results = await client.fastSearches(
|
|
229
|
+
params as FastSearchesParamsType
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
expect(results).toBeDefined();
|
|
233
|
+
expect(results.length).toBe(2);
|
|
234
|
+
|
|
235
|
+
results.forEach((resultSet, index) => {
|
|
236
|
+
expect(resultSet).toBeDefined();
|
|
237
|
+
expect(resultSet.results).toBeDefined();
|
|
238
|
+
expect(resultSet.results.length).toBeGreaterThan(0);
|
|
239
|
+
|
|
240
|
+
const firstResult = resultSet.results[0];
|
|
241
|
+
if (!firstResult) {
|
|
242
|
+
throw new Error(
|
|
243
|
+
`Expected first result to be defined for question ${index}`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
expect(firstResult).toBeInstanceOf(Result);
|
|
248
|
+
expect(firstResult.url_hash).toBeDefined();
|
|
249
|
+
expect(firstResult.url).toBeDefined();
|
|
250
|
+
expect(firstResult.title).toBeDefined();
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
console.log(
|
|
254
|
+
`fastSearches with complex shared parameters returned ${results.length} result sets`
|
|
255
|
+
);
|
|
256
|
+
results.forEach((resultSet, index) => {
|
|
257
|
+
console.log(
|
|
258
|
+
`Question ${index + 1}: ${resultSet.results.length} results`
|
|
259
|
+
);
|
|
260
|
+
});
|
|
261
|
+
}, 10000);
|
|
262
|
+
|
|
263
|
+
it("should handle single question in array", async () => {
|
|
264
|
+
const params = {
|
|
265
|
+
questions: ["quantum computing"],
|
|
266
|
+
nResults: 10,
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const results = await client.fastSearches(params);
|
|
270
|
+
|
|
271
|
+
expect(results).toBeDefined();
|
|
272
|
+
expect(results.length).toBe(1);
|
|
273
|
+
|
|
274
|
+
const firstResultSet = results[0];
|
|
275
|
+
if (!firstResultSet) {
|
|
276
|
+
throw new Error("Expected first result set to be defined");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
expect(firstResultSet.results.length).toBeGreaterThan(0);
|
|
280
|
+
|
|
281
|
+
const firstResult = firstResultSet.results[0];
|
|
282
|
+
if (!firstResult) {
|
|
283
|
+
throw new Error("Expected first result to be defined");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
expect(firstResult).toBeInstanceOf(Result);
|
|
287
|
+
expect(firstResult.url_hash).toBeDefined();
|
|
288
|
+
expect(firstResult.title).toBeDefined();
|
|
289
|
+
|
|
290
|
+
console.log(
|
|
291
|
+
`fastSearches with single question returned ${firstResultSet.results.length} results`
|
|
292
|
+
);
|
|
293
|
+
}, 10000);
|
|
294
|
+
|
|
295
|
+
it("should handle empty questions array", async () => {
|
|
296
|
+
const params = {
|
|
297
|
+
questions: [] as string[],
|
|
298
|
+
nResults: 10,
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const results = await client.fastSearches(params);
|
|
302
|
+
|
|
303
|
+
expect(results).toBeDefined();
|
|
304
|
+
expect(results).toBeInstanceOf(Array);
|
|
305
|
+
expect(results.length).toBe(0);
|
|
306
|
+
|
|
307
|
+
console.log(
|
|
308
|
+
"fastSearches with empty questions array returned empty array"
|
|
309
|
+
);
|
|
310
|
+
}, 10000);
|
|
311
|
+
|
|
312
|
+
it("should execute searches in parallel and return results in correct order", async () => {
|
|
313
|
+
const params = {
|
|
314
|
+
questions: [
|
|
315
|
+
"first search query",
|
|
316
|
+
"second search query",
|
|
317
|
+
"third search query",
|
|
318
|
+
],
|
|
319
|
+
nResults: 10,
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const startTime = Date.now();
|
|
323
|
+
const results = await client.fastSearches(params);
|
|
324
|
+
const endTime = Date.now();
|
|
325
|
+
|
|
326
|
+
expect(results).toBeDefined();
|
|
327
|
+
expect(results.length).toBe(3);
|
|
328
|
+
|
|
329
|
+
// Verify results are in the same order as questions
|
|
330
|
+
results.forEach((resultSet, index) => {
|
|
331
|
+
expect(resultSet).toBeDefined();
|
|
332
|
+
expect(resultSet.results).toBeDefined();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
console.log(
|
|
336
|
+
`Parallel fastSearches completed in ${endTime - startTime}ms`
|
|
337
|
+
);
|
|
338
|
+
console.log(`Returned ${results.length} result sets in correct order`);
|
|
339
|
+
}, 10000);
|
|
340
|
+
|
|
341
|
+
it("should work with SearchSet containing complex Search instances", async () => {
|
|
342
|
+
const searches = [
|
|
343
|
+
new Search({
|
|
344
|
+
question: "climate change solutions",
|
|
345
|
+
nResults: 10,
|
|
346
|
+
algorithm: "hybrid-2" as const,
|
|
347
|
+
minSimilarity: 0.65,
|
|
348
|
+
mustInclude: ["carbon", "renewable"],
|
|
349
|
+
mustExclude: ["politics"],
|
|
350
|
+
language: "en",
|
|
351
|
+
}),
|
|
352
|
+
new Search({
|
|
353
|
+
question: "sustainable technology",
|
|
354
|
+
nResults: 10,
|
|
355
|
+
algorithm: "hybrid-3" as const,
|
|
356
|
+
minSimilarity: 0.6,
|
|
357
|
+
continent: "Europe" as ContinentEnum,
|
|
358
|
+
sector: "Energy",
|
|
359
|
+
}),
|
|
360
|
+
];
|
|
361
|
+
|
|
362
|
+
const searchSet = new SearchSet(searches);
|
|
363
|
+
const results = await client.fastSearches(searchSet);
|
|
364
|
+
|
|
365
|
+
expect(results).toBeDefined();
|
|
366
|
+
expect(results.length).toBe(2);
|
|
367
|
+
|
|
368
|
+
results.forEach((resultSet, index) => {
|
|
369
|
+
expect(resultSet).toBeDefined();
|
|
370
|
+
expect(resultSet.results).toBeDefined();
|
|
371
|
+
expect(resultSet.results.length).toBeGreaterThan(0);
|
|
372
|
+
|
|
373
|
+
const firstResult = resultSet.results[0];
|
|
374
|
+
if (!firstResult) {
|
|
375
|
+
throw new Error(
|
|
376
|
+
`Expected first result to be defined for complex search ${index}`
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
expect(firstResult).toBeInstanceOf(Result);
|
|
381
|
+
expect(firstResult.url_hash).toBeDefined();
|
|
382
|
+
expect(firstResult.title).toBeDefined();
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
console.log(
|
|
386
|
+
`fastSearches with complex SearchSet returned ${results.length} result sets`
|
|
387
|
+
);
|
|
388
|
+
results.forEach((resultSet, index) => {
|
|
389
|
+
console.log(
|
|
390
|
+
`Complex search ${index + 1}: ${resultSet.results.length} results`
|
|
391
|
+
);
|
|
392
|
+
});
|
|
393
|
+
}, 10000);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
describe("aiSearch", () => {
|
|
397
|
+
it("should return AI-powered search results", async () => {
|
|
398
|
+
const searchResultSet = await client.aiSearch({
|
|
399
|
+
prompt: "What are the latest developments in quantum computing?",
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
expect(searchResultSet).toBeDefined();
|
|
403
|
+
expect(searchResultSet.results).toBeDefined();
|
|
404
|
+
expect(searchResultSet.results.length).toBeGreaterThan(0);
|
|
405
|
+
|
|
406
|
+
// Get first result with proper type guard
|
|
407
|
+
const firstResult = searchResultSet.results[0];
|
|
408
|
+
if (!firstResult) {
|
|
409
|
+
throw new Error("Expected first result to be defined");
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
expect(firstResult).toBeInstanceOf(Result);
|
|
413
|
+
expect(firstResult.url_hash).toBeDefined();
|
|
414
|
+
expect(firstResult.url).toBeDefined();
|
|
415
|
+
expect(firstResult.title).toBeDefined();
|
|
416
|
+
|
|
417
|
+
console.log(
|
|
418
|
+
`Found ${searchResultSet.results.length} results via aiSearch`
|
|
419
|
+
);
|
|
420
|
+
console.log(`First result: ${firstResult.title}`);
|
|
421
|
+
}, 30000);
|
|
422
|
+
|
|
423
|
+
it("should handle complex AI search instructions", async () => {
|
|
424
|
+
const searchResultSet = await client.aiSearch({
|
|
425
|
+
prompt: "Compare renewable energy sources",
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
expect(searchResultSet).toBeDefined();
|
|
429
|
+
expect(searchResultSet.results).toBeDefined();
|
|
430
|
+
|
|
431
|
+
console.log(
|
|
432
|
+
`Complex AI search returned ${searchResultSet.results.length} results`
|
|
433
|
+
);
|
|
434
|
+
}, 30000);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
describe("bulkSearch", () => {
|
|
438
|
+
it("should return bulk search results", async () => {
|
|
439
|
+
// Note: This test may take longer due to bulk processing
|
|
440
|
+
const searchResultSet = await client.bulkSearch({
|
|
441
|
+
question: "climate change renewable energy",
|
|
442
|
+
nResults: 1000,
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
expect(searchResultSet).toBeDefined();
|
|
446
|
+
expect(searchResultSet.results).toBeDefined();
|
|
447
|
+
expect(searchResultSet.results.length).toBeGreaterThan(0);
|
|
448
|
+
|
|
449
|
+
console.log(
|
|
450
|
+
`Bulk search returned ${searchResultSet.results.length} results`
|
|
451
|
+
);
|
|
452
|
+
}, 20000);
|
|
453
|
+
|
|
454
|
+
it("should handle bulk search with filters", async () => {
|
|
455
|
+
const searchResultSet = await client.bulkSearch({
|
|
456
|
+
question: "technology startups funding",
|
|
457
|
+
nResults: 5000,
|
|
458
|
+
continent: "North America" as ContinentEnum,
|
|
459
|
+
minSimilarity: 0.6,
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
expect(searchResultSet).toBeDefined();
|
|
463
|
+
expect(searchResultSet.results).toBeDefined();
|
|
464
|
+
|
|
465
|
+
console.log(
|
|
466
|
+
`Filtered bulk search returned ${searchResultSet.results.length} results`
|
|
467
|
+
);
|
|
468
|
+
}, 20000); // Longer timeout for bulk search
|
|
469
|
+
|
|
470
|
+
it("should work with a Search instance", async () => {
|
|
471
|
+
const search = new Search({
|
|
472
|
+
question: "artificial intelligence research papers",
|
|
473
|
+
nResults: 2000,
|
|
474
|
+
algorithm: "hybrid-2",
|
|
475
|
+
minSimilarity: 0.65,
|
|
476
|
+
language: "en",
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
const searchResultSet = await client.bulkSearch({search});
|
|
480
|
+
|
|
481
|
+
expect(searchResultSet).toBeDefined();
|
|
482
|
+
expect(searchResultSet.results).toBeDefined();
|
|
483
|
+
expect(searchResultSet.results.length).toBeGreaterThan(0);
|
|
484
|
+
|
|
485
|
+
const firstResult = searchResultSet.results[0];
|
|
486
|
+
if (!firstResult) {
|
|
487
|
+
throw new Error("Expected first result to be defined");
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
expect(firstResult).toBeInstanceOf(Result);
|
|
491
|
+
expect(firstResult.url_hash).toBeDefined();
|
|
492
|
+
expect(firstResult.url).toBeDefined();
|
|
493
|
+
expect(firstResult.title).toBeDefined();
|
|
494
|
+
expect(firstResult.content).toBeDefined();
|
|
495
|
+
|
|
496
|
+
console.log(
|
|
497
|
+
`Found ${searchResultSet.results.length} results via bulkSearch with Search instance`
|
|
498
|
+
);
|
|
499
|
+
console.log(`First result: ${firstResult.title}`);
|
|
500
|
+
}, 25000);
|
|
501
|
+
|
|
502
|
+
it("should work with a Search instance and comprehensive filters", async () => {
|
|
503
|
+
const search = new Search({
|
|
504
|
+
question: "electric vehicle market analysis",
|
|
505
|
+
nResults: 3000,
|
|
506
|
+
algorithm: "hybrid-3",
|
|
507
|
+
minSimilarity: 0.6,
|
|
508
|
+
mustInclude: ["Tesla", "market share", "sales"],
|
|
509
|
+
mustExclude: ["toy review"],
|
|
510
|
+
continent: "North America",
|
|
511
|
+
country: "United States",
|
|
512
|
+
sector: "Consumer Discretionary",
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
const searchResultSet = await client.bulkSearch({search});
|
|
516
|
+
|
|
517
|
+
expect(searchResultSet).toBeDefined();
|
|
518
|
+
expect(searchResultSet.results).toBeDefined();
|
|
519
|
+
|
|
520
|
+
console.log(
|
|
521
|
+
`Bulk search instance with comprehensive filters returned ${searchResultSet.results.length} results`
|
|
522
|
+
);
|
|
523
|
+
}, 30000);
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
describe("scrapeUrl", () => {
|
|
527
|
+
it("should scrape content from a URL", async () => {
|
|
528
|
+
// First get a URL from search results
|
|
529
|
+
const searchResultSet = await client.fastSearch({
|
|
530
|
+
question: "technology news",
|
|
531
|
+
nResults: 10,
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
if (searchResultSet.results.length > 0) {
|
|
535
|
+
const firstResult = searchResultSet.results[0];
|
|
536
|
+
if (!firstResult) {
|
|
537
|
+
throw new Error("Expected first result to be defined");
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const urlToScrape = firstResult.url;
|
|
541
|
+
|
|
542
|
+
const webPage = await client.scrapeUrl(urlToScrape);
|
|
543
|
+
|
|
544
|
+
expect(webPage).toBeDefined();
|
|
545
|
+
|
|
546
|
+
expect(webPage.data.request.url).toBe(urlToScrape);
|
|
547
|
+
expect(webPage.data.page.title).toBeDefined();
|
|
548
|
+
expect(webPage.data.full_text).toBeDefined();
|
|
549
|
+
expect(webPage.data.snippets).toBeDefined();
|
|
550
|
+
|
|
551
|
+
console.log(`Successfully scraped: ${webPage.data.page.title}`);
|
|
552
|
+
console.log(
|
|
553
|
+
`Content length: ${webPage.data.full_text.length} characters`
|
|
554
|
+
);
|
|
555
|
+
} else {
|
|
556
|
+
console.log("No URLs found to scrape");
|
|
557
|
+
}
|
|
558
|
+
}, 10000);
|
|
559
|
+
|
|
560
|
+
it("should handle invalid URLs gracefully", async () => {
|
|
561
|
+
await expect(
|
|
562
|
+
client.scrapeUrl("https://invalid-url-12345.com")
|
|
563
|
+
).rejects.toThrow();
|
|
564
|
+
}, 10000);
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
describe("topicTrend", () => {
|
|
568
|
+
it("should return trend analysis for a topic", async () => {
|
|
569
|
+
const topicTrend = await client.topicTrend("artificial intelligence");
|
|
570
|
+
|
|
571
|
+
expect(topicTrend).toBeDefined();
|
|
572
|
+
expect(topicTrend.data).toBeDefined();
|
|
573
|
+
expect(typeof topicTrend.data.response).toBe("object");
|
|
574
|
+
|
|
575
|
+
const responseData = topicTrend.data.response;
|
|
576
|
+
const dataPoints = Object.keys(responseData);
|
|
577
|
+
|
|
578
|
+
console.log(
|
|
579
|
+
`Topic trend for "${topicTrend.data.query.query}" returned ${dataPoints.length} data points`
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
if (dataPoints.length > 0) {
|
|
583
|
+
const firstDate = dataPoints[0];
|
|
584
|
+
if (!firstDate) {
|
|
585
|
+
throw new Error("Expected first date to be defined");
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const firstPopularity = responseData[firstDate];
|
|
589
|
+
expect(firstDate).toBeDefined();
|
|
590
|
+
expect(firstPopularity).toBeDefined();
|
|
591
|
+
console.log(
|
|
592
|
+
`First data point: ${firstDate} - popularity: ${firstPopularity}`
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
}, 10000);
|
|
596
|
+
|
|
597
|
+
it("should handle trend analysis with SQL filter", async () => {
|
|
598
|
+
const topicTrend = await client.topicTrend("machine learning");
|
|
599
|
+
|
|
600
|
+
expect(topicTrend).toBeDefined();
|
|
601
|
+
expect(topicTrend.data).toBeDefined();
|
|
602
|
+
|
|
603
|
+
const responseData = topicTrend.data.response;
|
|
604
|
+
const dataPoints = Object.keys(responseData);
|
|
605
|
+
|
|
606
|
+
console.log(
|
|
607
|
+
`Filtered trend analysis returned ${dataPoints.length} data points`
|
|
608
|
+
);
|
|
609
|
+
}, 10000);
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
describe("defaultSearch", () => {
|
|
613
|
+
it("should apply default search parameters when provided", async () => {
|
|
614
|
+
const clientWithDefaults = new NosibleClient({
|
|
615
|
+
apiKey: process.env.NOSIBLE_API_KEY || "test-key",
|
|
616
|
+
searchDefaults: {
|
|
617
|
+
nResults: 15,
|
|
618
|
+
algorithm: "hybrid-2",
|
|
619
|
+
continent: "North America",
|
|
620
|
+
},
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
// This should use the default parameters
|
|
624
|
+
const searchResultSet = await clientWithDefaults.fastSearch({
|
|
625
|
+
question: "artificial intelligence",
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
expect(searchResultSet).toBeDefined();
|
|
629
|
+
expect(searchResultSet.results).toBeDefined();
|
|
630
|
+
expect(searchResultSet.results.length).toBeGreaterThan(0);
|
|
631
|
+
|
|
632
|
+
console.log(
|
|
633
|
+
`Default search returned ${searchResultSet.results.length} results`
|
|
634
|
+
);
|
|
635
|
+
}, 10000);
|
|
636
|
+
|
|
637
|
+
it("should override default parameters with provided parameters", async () => {
|
|
638
|
+
const clientWithDefaults = new NosibleClient({
|
|
639
|
+
apiKey: process.env.NOSIBLE_API_KEY || "test-key",
|
|
640
|
+
searchDefaults: {
|
|
641
|
+
nResults: 15,
|
|
642
|
+
algorithm: "hybrid-2",
|
|
643
|
+
continent: "North America",
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
// This should override the default nResults
|
|
648
|
+
const searchResultSet = await clientWithDefaults.fastSearch({
|
|
649
|
+
question: "machine learning",
|
|
650
|
+
nResults: 20, // This should override the default of 15
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
expect(searchResultSet).toBeDefined();
|
|
654
|
+
expect(searchResultSet.results).toBeDefined();
|
|
655
|
+
expect(searchResultSet.results.length).toBeGreaterThan(0);
|
|
656
|
+
|
|
657
|
+
console.log(
|
|
658
|
+
`Override search returned ${searchResultSet.results.length} results`
|
|
659
|
+
);
|
|
660
|
+
}, 10000);
|
|
661
|
+
|
|
662
|
+
it("should work with fastSearches using default parameters", async () => {
|
|
663
|
+
const clientWithDefaults = new NosibleClient({
|
|
664
|
+
apiKey: process.env.NOSIBLE_API_KEY || "test-key",
|
|
665
|
+
searchDefaults: {
|
|
666
|
+
nResults: 10,
|
|
667
|
+
algorithm: "hybrid-2",
|
|
668
|
+
},
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
const searchResultSet = await clientWithDefaults.fastSearches({
|
|
672
|
+
questions: ["AI", "machine learning"],
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
expect(searchResultSet).toBeDefined();
|
|
676
|
+
expect(searchResultSet).toHaveLength(2);
|
|
677
|
+
expect(searchResultSet[0]?.results).toBeDefined();
|
|
678
|
+
expect(searchResultSet[1]?.results).toBeDefined();
|
|
679
|
+
|
|
680
|
+
console.log(
|
|
681
|
+
`Default fastSearches returned ${searchResultSet.length} result sets`
|
|
682
|
+
);
|
|
683
|
+
}, 10000);
|
|
684
|
+
});
|
|
685
|
+
});
|