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,391 @@
|
|
|
1
|
+
import {type SearchResultSemantics} from "../api/schemas";
|
|
2
|
+
import {NosibleClient} from "../client";
|
|
3
|
+
import {getSentiment} from "../utils/llm";
|
|
4
|
+
import {type SimilarUserSearchParamsType} from "./search";
|
|
5
|
+
import type {WebPageData} from "../scrape/webPageData";
|
|
6
|
+
import type {IResultSet} from "./resultSet.types";
|
|
7
|
+
import type {FlattenResult} from "./result.types";
|
|
8
|
+
import type {ResultSet} from "./resultSet";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parameters for creating a Result instance
|
|
12
|
+
*/
|
|
13
|
+
type ResultParams = {
|
|
14
|
+
/** The Nosible client instance */
|
|
15
|
+
client: NosibleClient;
|
|
16
|
+
/** The raw search result data from the API */
|
|
17
|
+
result: any;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Represents a single search result from the Nosible search API.
|
|
22
|
+
*
|
|
23
|
+
* This class encapsulates all the data and functionality associated with a search result,
|
|
24
|
+
* including metadata, content, semantic information, and methods for further operations
|
|
25
|
+
* like sentiment analysis, finding similar results, and URL scraping.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const result = new Result({
|
|
30
|
+
* client: nosibleClient,
|
|
31
|
+
* result: apiResponseData
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* // Get sentiment analysis
|
|
35
|
+
* const sentiment = await result.getSentiment();
|
|
36
|
+
*
|
|
37
|
+
* // Find similar results
|
|
38
|
+
* const similarResults = await result.getSimilar({ limit: 5 });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export class Result {
|
|
42
|
+
// === Core Result Properties ===
|
|
43
|
+
/**
|
|
44
|
+
* Unique hash identifier for the URL
|
|
45
|
+
*/
|
|
46
|
+
public url_hash!: string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The full URL of the web page
|
|
50
|
+
*/
|
|
51
|
+
public url!: string;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Network location (domain) of the URL
|
|
55
|
+
*/
|
|
56
|
+
public netloc!: string;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Publication date of the content (ISO 8601 format)
|
|
60
|
+
*/
|
|
61
|
+
public published!: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Date when the page was last visited/crawled (ISO 8601 format)
|
|
65
|
+
*/
|
|
66
|
+
public visited!: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Language code of the content (e.g., 'en', 'es', 'fr')
|
|
70
|
+
*/
|
|
71
|
+
public language!: string;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Author of the content, if available
|
|
75
|
+
*/
|
|
76
|
+
public author!: string;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Title of the web page
|
|
80
|
+
*/
|
|
81
|
+
public title!: string;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Meta description or summary of the content
|
|
85
|
+
*/
|
|
86
|
+
public description!: string;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Full text content of the web page
|
|
90
|
+
*/
|
|
91
|
+
public content!: string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The most relevant content chunk for the search query
|
|
95
|
+
*/
|
|
96
|
+
public best_chunk!: string;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Semantic search metadata including similarity scores and chunk information
|
|
100
|
+
*/
|
|
101
|
+
public semantics!: SearchResultSemantics;
|
|
102
|
+
|
|
103
|
+
// === Geographic and Industry Classification ===
|
|
104
|
+
/**
|
|
105
|
+
* Brand safety classification
|
|
106
|
+
*/
|
|
107
|
+
public brand_safety!: string | null;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Continent classification
|
|
111
|
+
*/
|
|
112
|
+
public continent!: string | null;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Geographic region classification
|
|
116
|
+
*/
|
|
117
|
+
public region!: string | null;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Country classification (ISO 3166-1 alpha-2 code)
|
|
121
|
+
*/
|
|
122
|
+
public country!: string | null;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Economic sector classification
|
|
126
|
+
*/
|
|
127
|
+
public sector!: string | null;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Industry group classification
|
|
131
|
+
*/
|
|
132
|
+
public industry_group!: string | null;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Industry classification
|
|
136
|
+
*/
|
|
137
|
+
public industry!: string | null;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Sub-industry classification
|
|
141
|
+
*/
|
|
142
|
+
public sub_industry!: string | null;
|
|
143
|
+
|
|
144
|
+
// === IAB Content Categories ===
|
|
145
|
+
/**
|
|
146
|
+
* IAB Tier 1 content category
|
|
147
|
+
*/
|
|
148
|
+
public iab_tier_1!: string | null;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* IAB Tier 2 content category
|
|
152
|
+
*/
|
|
153
|
+
public iab_tier_2!: string | null;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* IAB Tier 3 content category
|
|
157
|
+
*/
|
|
158
|
+
public iab_tier_3!: string | null;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* IAB Tier 4 content category
|
|
162
|
+
*/
|
|
163
|
+
public iab_tier_4!: string | null;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The Nosible client instance used for API operations
|
|
167
|
+
*/
|
|
168
|
+
public client: NosibleClient;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Creates a new Result instance from raw API response data
|
|
172
|
+
*
|
|
173
|
+
* @param params - The result parameters containing client and raw data
|
|
174
|
+
*/
|
|
175
|
+
constructor(params: ResultParams) {
|
|
176
|
+
this.client = params.client;
|
|
177
|
+
|
|
178
|
+
Object.assign(this, params.result);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Creates a Result instance from a flattened result structure
|
|
183
|
+
*
|
|
184
|
+
* This method reconstructs the nested semantics object from flattened properties
|
|
185
|
+
* and creates a new Result instance.
|
|
186
|
+
*
|
|
187
|
+
* @param client - The Nosible client instance
|
|
188
|
+
* @param flatten - The flattened result data
|
|
189
|
+
* @returns A new Result instance
|
|
190
|
+
*/
|
|
191
|
+
static fromFlatten = (
|
|
192
|
+
client: NosibleClient,
|
|
193
|
+
flatten: FlattenResult
|
|
194
|
+
): Result => {
|
|
195
|
+
const unflattened = {
|
|
196
|
+
...flatten,
|
|
197
|
+
semantics: {
|
|
198
|
+
origin_shard: flatten.origin_shard,
|
|
199
|
+
chunks_total: flatten.chunks_total,
|
|
200
|
+
chunks_matched: flatten.chunks_matched,
|
|
201
|
+
chunks_kept: flatten.chunks_kept,
|
|
202
|
+
similarity: flatten.similarity,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
return new Result({
|
|
207
|
+
client: client,
|
|
208
|
+
result: unflattened,
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Analyzes the sentiment of the result content using an LLM
|
|
214
|
+
*
|
|
215
|
+
* This method requires the Nosible client to be configured with an OpenRouter API key.
|
|
216
|
+
* The sentiment analysis returns a numerical score (typically ranging from -1 to 1)
|
|
217
|
+
* where negative values indicate negative sentiment and positive values indicate positive sentiment.
|
|
218
|
+
*
|
|
219
|
+
* @param model - Optional model name for sentiment analysis (uses default if not specified)
|
|
220
|
+
* @returns A promise that resolves to the sentiment score
|
|
221
|
+
* @throws Error if the client is not configured with an OpenRouter API key
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* const sentiment = await result.getSentiment('gpt-4');
|
|
226
|
+
* console.log(`Sentiment score: ${sentiment}`);
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
public getSentiment = async (model?: string): Promise<number> => {
|
|
230
|
+
if (!this.client.llmClient) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
"A Nosible client instance must be provided with a OpenRouter API key."
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
return getSentiment({
|
|
236
|
+
text: this.content,
|
|
237
|
+
model: model,
|
|
238
|
+
llmClient: this.client.llmClient,
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Finds search results similar to this one based on content and metadata
|
|
244
|
+
*
|
|
245
|
+
* This method performs a new search using the title of this result as the query,
|
|
246
|
+
* excluding the current result from the returned results. It's useful for discovering
|
|
247
|
+
* related content or alternative sources on the same topic.
|
|
248
|
+
*
|
|
249
|
+
* @param params - Search parameters for finding similar results
|
|
250
|
+
* @returns A promise that resolves to a ResultSet containing similar results
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```typescript
|
|
254
|
+
* // Find 5 similar results
|
|
255
|
+
* const similar = await result.getSimilar({ limit: 5 });
|
|
256
|
+
*
|
|
257
|
+
* // Find similar results with specific filters
|
|
258
|
+
* const filteredSimilar = await result.getSimilar({
|
|
259
|
+
* limit: 10,
|
|
260
|
+
* country: 'US',
|
|
261
|
+
* language: 'en'
|
|
262
|
+
* });
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
public getSimilar = async (
|
|
266
|
+
params: SimilarUserSearchParamsType
|
|
267
|
+
): Promise<ResultSet> => {
|
|
268
|
+
return this.client.fastSearch({
|
|
269
|
+
question: this.title,
|
|
270
|
+
excludeDocs: [this.url_hash],
|
|
271
|
+
...params,
|
|
272
|
+
});
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Scrapes the full web page content from the result's URL
|
|
277
|
+
*
|
|
278
|
+
* This method uses the client's scraping functionality to retrieve the complete
|
|
279
|
+
* web page content, which may include additional information not present in the
|
|
280
|
+
* search result snippet.
|
|
281
|
+
*
|
|
282
|
+
* @returns A promise that resolves to WebPageData containing the scraped content
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* ```typescript
|
|
286
|
+
* const pageData = await result.scrapeUrl();
|
|
287
|
+
* console.log('Full page title:', pageData.title);
|
|
288
|
+
* console.log('Full page content:', pageData.text);
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
public scrapeUrl = async (): Promise<WebPageData> => {
|
|
292
|
+
return this.client.scrapeUrl(this.url);
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Converts the Result to a flattened structure
|
|
297
|
+
*
|
|
298
|
+
* This method transforms the nested Result object into a flat structure where
|
|
299
|
+
* semantic properties are top-level fields. This is useful for serialization,
|
|
300
|
+
* storage, or when working with systems that prefer flat data structures.
|
|
301
|
+
*
|
|
302
|
+
* @returns A FlattenResult object with all properties flattened to top level
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```typescript
|
|
306
|
+
* const flattened = result.flatten();
|
|
307
|
+
* console.log('Similarity score:', flattened.similarity);
|
|
308
|
+
* console.log('Chunks matched:', flattened.chunks_matched);
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
public flatten = (): FlattenResult => {
|
|
312
|
+
return {
|
|
313
|
+
url_hash: this.url_hash,
|
|
314
|
+
url: this.url,
|
|
315
|
+
netloc: this.netloc,
|
|
316
|
+
published: this.published,
|
|
317
|
+
visited: this.visited,
|
|
318
|
+
language: this.language,
|
|
319
|
+
author: this.author,
|
|
320
|
+
title: this.title,
|
|
321
|
+
description: this.description,
|
|
322
|
+
content: this.content,
|
|
323
|
+
best_chunk: this.best_chunk,
|
|
324
|
+
origin_shard: this.semantics.origin_shard,
|
|
325
|
+
chunks_total: this.semantics.chunks_total,
|
|
326
|
+
chunks_matched: this.semantics.chunks_matched,
|
|
327
|
+
chunks_kept: this.semantics.chunks_kept,
|
|
328
|
+
similarity: this.semantics.similarity,
|
|
329
|
+
brand_safety: this.brand_safety,
|
|
330
|
+
continent: this.continent,
|
|
331
|
+
region: this.region,
|
|
332
|
+
country: this.country,
|
|
333
|
+
sector: this.sector,
|
|
334
|
+
industry_group: this.industry_group,
|
|
335
|
+
industry: this.industry,
|
|
336
|
+
sub_industry: this.sub_industry,
|
|
337
|
+
iab_tier_1: this.iab_tier_1,
|
|
338
|
+
iab_tier_2: this.iab_tier_2,
|
|
339
|
+
iab_tier_3: this.iab_tier_3,
|
|
340
|
+
iab_tier_4: this.iab_tier_4,
|
|
341
|
+
};
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Returns a plain object representation of the Result data
|
|
346
|
+
*
|
|
347
|
+
* This method provides a clean object with all the result properties,
|
|
348
|
+
* maintaining the nested structure for semantic data. It's useful for
|
|
349
|
+
* serialization, logging, or when you need to work with the raw data
|
|
350
|
+
* without the class methods.
|
|
351
|
+
*
|
|
352
|
+
* @returns A plain object containing all result properties
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```typescript
|
|
356
|
+
* const rawData = result.data();
|
|
357
|
+
* console.log('Result metadata:', rawData.semantics);
|
|
358
|
+
*
|
|
359
|
+
* // Serialize to JSON
|
|
360
|
+
* const json = JSON.stringify(rawData, null, 2);
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
public data = () => {
|
|
364
|
+
return {
|
|
365
|
+
url_hash: this.url_hash,
|
|
366
|
+
url: this.url,
|
|
367
|
+
netloc: this.netloc,
|
|
368
|
+
published: this.published,
|
|
369
|
+
visited: this.visited,
|
|
370
|
+
language: this.language,
|
|
371
|
+
author: this.author,
|
|
372
|
+
title: this.title,
|
|
373
|
+
description: this.description,
|
|
374
|
+
content: this.content,
|
|
375
|
+
best_chunk: this.best_chunk,
|
|
376
|
+
brand_safety: this.brand_safety,
|
|
377
|
+
continent: this.continent,
|
|
378
|
+
region: this.region,
|
|
379
|
+
country: this.country,
|
|
380
|
+
sector: this.sector,
|
|
381
|
+
industry_group: this.industry_group,
|
|
382
|
+
industry: this.industry,
|
|
383
|
+
sub_industry: this.sub_industry,
|
|
384
|
+
iab_tier_1: this.iab_tier_1,
|
|
385
|
+
iab_tier_2: this.iab_tier_2,
|
|
386
|
+
iab_tier_3: this.iab_tier_3,
|
|
387
|
+
iab_tier_4: this.iab_tier_4,
|
|
388
|
+
semantics: this.semantics,
|
|
389
|
+
};
|
|
390
|
+
};
|
|
391
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type {SearchResultSemantics} from "../api/schemas";
|
|
2
|
+
|
|
3
|
+
export interface FlattenResult {
|
|
4
|
+
url_hash: string;
|
|
5
|
+
url: string;
|
|
6
|
+
netloc: string;
|
|
7
|
+
published: string;
|
|
8
|
+
visited: string;
|
|
9
|
+
language: string;
|
|
10
|
+
author: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
content: string;
|
|
14
|
+
best_chunk: string;
|
|
15
|
+
origin_shard: number;
|
|
16
|
+
chunks_total: number;
|
|
17
|
+
chunks_matched: number;
|
|
18
|
+
chunks_kept: number;
|
|
19
|
+
similarity: number;
|
|
20
|
+
brand_safety: string | null;
|
|
21
|
+
continent: string | null;
|
|
22
|
+
region: string | null;
|
|
23
|
+
country: string | null;
|
|
24
|
+
sector: string | null;
|
|
25
|
+
industry_group: string | null;
|
|
26
|
+
industry: string | null;
|
|
27
|
+
sub_industry: string | null;
|
|
28
|
+
iab_tier_1: string | null;
|
|
29
|
+
iab_tier_2: string | null;
|
|
30
|
+
iab_tier_3: string | null;
|
|
31
|
+
iab_tier_4: string | null;
|
|
32
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {NosibleClient} from "../client";
|
|
2
|
+
import {Result} from "./result";
|
|
3
|
+
import {ResultSet} from "./resultSet";
|
|
4
|
+
import type {SearchResponse, SearchQuery} from "../api/schemas";
|
|
5
|
+
|
|
6
|
+
export function createResult(
|
|
7
|
+
client: NosibleClient,
|
|
8
|
+
result: SearchResponse & SearchQuery
|
|
9
|
+
): Result {
|
|
10
|
+
return new Result({client, result});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createResultSet(
|
|
14
|
+
client: NosibleClient,
|
|
15
|
+
rawResults: (SearchResponse & SearchQuery)[]
|
|
16
|
+
): ResultSet {
|
|
17
|
+
const resultInstances = rawResults.map((result) =>
|
|
18
|
+
createResult(client, result)
|
|
19
|
+
);
|
|
20
|
+
return new ResultSet(resultInstances);
|
|
21
|
+
}
|