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.
Files changed (44) hide show
  1. package/README.md +438 -0
  2. package/dist/index.cjs +1841 -0
  3. package/dist/index.cjs.map +29 -0
  4. package/dist/index.js +1815 -0
  5. package/dist/index.js.map +29 -0
  6. package/package.json +63 -0
  7. package/src/api/api.test.ts +366 -0
  8. package/src/api/index.ts +179 -0
  9. package/src/api/schemas.ts +152 -0
  10. package/src/client.test.ts +685 -0
  11. package/src/client.ts +762 -0
  12. package/src/index.ts +4 -0
  13. package/src/scrape/types.ts +119 -0
  14. package/src/scrape/webPageData.test.ts +302 -0
  15. package/src/scrape/webPageData.ts +103 -0
  16. package/src/search/analyze.test.ts +396 -0
  17. package/src/search/analyze.ts +151 -0
  18. package/src/search/bulkSearch.ts +62 -0
  19. package/src/search/result.test.ts +423 -0
  20. package/src/search/result.ts +391 -0
  21. package/src/search/result.types.ts +32 -0
  22. package/src/search/resultFactory.ts +21 -0
  23. package/src/search/resultSet.io.test.ts +320 -0
  24. package/src/search/resultSet.test.ts +368 -0
  25. package/src/search/resultSet.ts +387 -0
  26. package/src/search/resultSet.types.ts +3 -0
  27. package/src/search/search.test.ts +299 -0
  28. package/src/search/search.ts +187 -0
  29. package/src/search/searchSet.io.test.ts +321 -0
  30. package/src/search/searchSet.ts +122 -0
  31. package/src/search/sqlFilter.test.ts +129 -0
  32. package/src/search/sqlFilter.ts +147 -0
  33. package/src/test-utils/mocks.ts +159 -0
  34. package/src/topicTrend/topicTrend.ts +53 -0
  35. package/src/utils/browser.test.ts +209 -0
  36. package/src/utils/browser.ts +21 -0
  37. package/src/utils/fernet.ts +47 -0
  38. package/src/utils/file.test.ts +81 -0
  39. package/src/utils/file.ts +195 -0
  40. package/src/utils/index.ts +7 -0
  41. package/src/utils/llm.test.ts +279 -0
  42. package/src/utils/llm.ts +244 -0
  43. package/src/utils/userPlan.test.ts +332 -0
  44. 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
+ }