langchain 0.0.154 → 0.0.156

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 (78) hide show
  1. package/chat_models/bedrock.cjs +1 -0
  2. package/chat_models/bedrock.d.ts +1 -0
  3. package/chat_models/bedrock.js +1 -0
  4. package/dist/callbacks/base.d.ts +42 -28
  5. package/dist/callbacks/handlers/log_stream.cjs +283 -0
  6. package/dist/callbacks/handlers/log_stream.d.ts +99 -0
  7. package/dist/callbacks/handlers/log_stream.js +277 -0
  8. package/dist/callbacks/handlers/tracer.cjs +34 -18
  9. package/dist/callbacks/handlers/tracer.d.ts +18 -16
  10. package/dist/callbacks/handlers/tracer.js +34 -18
  11. package/dist/chat_models/bedrock.cjs +260 -0
  12. package/dist/chat_models/bedrock.d.ts +58 -0
  13. package/dist/chat_models/bedrock.js +254 -0
  14. package/dist/document_loaders/web/notionapi.cjs +8 -4
  15. package/dist/document_loaders/web/notionapi.js +8 -4
  16. package/dist/document_loaders/web/searchapi.cjs +134 -0
  17. package/dist/document_loaders/web/searchapi.d.ts +65 -0
  18. package/dist/document_loaders/web/searchapi.js +130 -0
  19. package/dist/embeddings/cloudflare_workersai.cjs +69 -0
  20. package/dist/embeddings/cloudflare_workersai.d.ts +28 -0
  21. package/dist/embeddings/cloudflare_workersai.js +65 -0
  22. package/dist/llms/bedrock.cjs +57 -67
  23. package/dist/llms/bedrock.d.ts +8 -35
  24. package/dist/llms/bedrock.js +57 -67
  25. package/dist/load/import_constants.cjs +4 -0
  26. package/dist/load/import_constants.js +4 -0
  27. package/dist/load/import_map.cjs +3 -2
  28. package/dist/load/import_map.d.ts +1 -0
  29. package/dist/load/import_map.js +1 -0
  30. package/dist/schema/runnable/base.cjs +64 -5
  31. package/dist/schema/runnable/base.d.ts +13 -0
  32. package/dist/schema/runnable/base.js +64 -5
  33. package/dist/tools/index.cjs +3 -1
  34. package/dist/tools/index.d.ts +1 -0
  35. package/dist/tools/index.js +1 -0
  36. package/dist/tools/searchapi.cjs +139 -0
  37. package/dist/tools/searchapi.d.ts +64 -0
  38. package/dist/tools/searchapi.js +135 -0
  39. package/dist/util/bedrock.cjs +54 -0
  40. package/dist/util/bedrock.d.ts +59 -0
  41. package/dist/util/bedrock.js +50 -0
  42. package/dist/util/fast-json-patch/index.cjs +48 -0
  43. package/dist/util/fast-json-patch/index.d.ts +21 -0
  44. package/dist/util/fast-json-patch/index.js +15 -0
  45. package/dist/util/fast-json-patch/src/core.cjs +469 -0
  46. package/dist/util/fast-json-patch/src/core.d.ts +111 -0
  47. package/dist/util/fast-json-patch/src/core.js +459 -0
  48. package/dist/util/fast-json-patch/src/helpers.cjs +194 -0
  49. package/dist/util/fast-json-patch/src/helpers.d.ts +36 -0
  50. package/dist/util/fast-json-patch/src/helpers.js +181 -0
  51. package/dist/util/googlevertexai-webauth.cjs +6 -2
  52. package/dist/util/googlevertexai-webauth.d.ts +1 -0
  53. package/dist/util/googlevertexai-webauth.js +6 -2
  54. package/dist/util/stream.cjs +2 -40
  55. package/dist/util/stream.d.ts +1 -2
  56. package/dist/util/stream.js +1 -38
  57. package/dist/vectorstores/cloudflare_vectorize.cjs +200 -0
  58. package/dist/vectorstores/cloudflare_vectorize.d.ts +90 -0
  59. package/dist/vectorstores/cloudflare_vectorize.js +173 -0
  60. package/dist/vectorstores/pgvector.cjs +1 -1
  61. package/dist/vectorstores/pgvector.js +1 -1
  62. package/dist/vectorstores/supabase.d.ts +1 -1
  63. package/dist/vectorstores/vercel_postgres.cjs +300 -0
  64. package/dist/vectorstores/vercel_postgres.d.ts +145 -0
  65. package/dist/vectorstores/vercel_postgres.js +296 -0
  66. package/document_loaders/web/searchapi.cjs +1 -0
  67. package/document_loaders/web/searchapi.d.ts +1 -0
  68. package/document_loaders/web/searchapi.js +1 -0
  69. package/embeddings/cloudflare_workersai.cjs +1 -0
  70. package/embeddings/cloudflare_workersai.d.ts +1 -0
  71. package/embeddings/cloudflare_workersai.js +1 -0
  72. package/package.json +60 -14
  73. package/vectorstores/cloudflare_vectorize.cjs +1 -0
  74. package/vectorstores/cloudflare_vectorize.d.ts +1 -0
  75. package/vectorstores/cloudflare_vectorize.js +1 -0
  76. package/vectorstores/vercel_postgres.cjs +1 -0
  77. package/vectorstores/vercel_postgres.d.ts +1 -0
  78. package/vectorstores/vercel_postgres.js +1 -0
@@ -0,0 +1,254 @@
1
+ import { SignatureV4 } from "@smithy/signature-v4";
2
+ import { defaultProvider } from "@aws-sdk/credential-provider-node";
3
+ import { HttpRequest } from "@smithy/protocol-http";
4
+ import { EventStreamCodec } from "@smithy/eventstream-codec";
5
+ import { fromUtf8, toUtf8 } from "@smithy/util-utf8";
6
+ import { Sha256 } from "@aws-crypto/sha256-js";
7
+ import { BedrockLLMInputOutputAdapter, } from "../util/bedrock.js";
8
+ import { getEnvironmentVariable } from "../util/env.js";
9
+ import { SimpleChatModel } from "./base.js";
10
+ import { AIMessageChunk, AIMessage, ChatGenerationChunk, ChatMessage, } from "../schema/index.js";
11
+ function convertOneMessageToText(message, humanPrompt, aiPrompt) {
12
+ if (message._getType() === "human") {
13
+ return `${humanPrompt} ${message.content}`;
14
+ }
15
+ else if (message._getType() === "ai") {
16
+ return `${aiPrompt} ${message.content}`;
17
+ }
18
+ else if (message._getType() === "system") {
19
+ return `${humanPrompt} <admin>${message.content}</admin>`;
20
+ }
21
+ else if (ChatMessage.isInstance(message)) {
22
+ return `\n\n${message.role[0].toUpperCase() + message.role.slice(1)}: {message.content}`;
23
+ }
24
+ throw new Error(`Unknown role: ${message._getType()}`);
25
+ }
26
+ export function convertMessagesToPromptAnthropic(messages, humanPrompt = "\n\nHuman:", aiPrompt = "\n\nAssistant:") {
27
+ const messagesCopy = [...messages];
28
+ if (messagesCopy.length === 0 ||
29
+ messagesCopy[messagesCopy.length - 1]._getType() !== "ai") {
30
+ messagesCopy.push(new AIMessage({ content: "" }));
31
+ }
32
+ return messagesCopy
33
+ .map((message) => convertOneMessageToText(message, humanPrompt, aiPrompt))
34
+ .join("");
35
+ }
36
+ /**
37
+ * Function that converts an array of messages into a single string prompt
38
+ * that can be used as input for a chat model. It delegates the conversion
39
+ * logic to the appropriate provider-specific function.
40
+ * @param messages Array of messages to be converted.
41
+ * @param options Options to be used during the conversion.
42
+ * @returns A string prompt that can be used as input for a chat model.
43
+ */
44
+ export function convertMessagesToPrompt(messages, provider) {
45
+ if (provider === "anthropic") {
46
+ return convertMessagesToPromptAnthropic(messages);
47
+ }
48
+ throw new Error(`Provider ${provider} does not support chat.`);
49
+ }
50
+ /**
51
+ * A type of Large Language Model (LLM) that interacts with the Bedrock
52
+ * service. It extends the base `LLM` class and implements the
53
+ * `BaseBedrockInput` interface. The class is designed to authenticate and
54
+ * interact with the Bedrock service, which is a part of Amazon Web
55
+ * Services (AWS). It uses AWS credentials for authentication and can be
56
+ * configured with various parameters such as the model to use, the AWS
57
+ * region, and the maximum number of tokens to generate.
58
+ */
59
+ export class ChatBedrock extends SimpleChatModel {
60
+ get lc_secrets() {
61
+ return {};
62
+ }
63
+ _llmType() {
64
+ return "bedrock";
65
+ }
66
+ static lc_name() {
67
+ return "ChatBedrock";
68
+ }
69
+ constructor(fields) {
70
+ super(fields ?? {});
71
+ Object.defineProperty(this, "model", {
72
+ enumerable: true,
73
+ configurable: true,
74
+ writable: true,
75
+ value: "amazon.titan-tg1-large"
76
+ });
77
+ Object.defineProperty(this, "region", {
78
+ enumerable: true,
79
+ configurable: true,
80
+ writable: true,
81
+ value: void 0
82
+ });
83
+ Object.defineProperty(this, "credentials", {
84
+ enumerable: true,
85
+ configurable: true,
86
+ writable: true,
87
+ value: void 0
88
+ });
89
+ Object.defineProperty(this, "temperature", {
90
+ enumerable: true,
91
+ configurable: true,
92
+ writable: true,
93
+ value: undefined
94
+ });
95
+ Object.defineProperty(this, "maxTokens", {
96
+ enumerable: true,
97
+ configurable: true,
98
+ writable: true,
99
+ value: undefined
100
+ });
101
+ Object.defineProperty(this, "fetchFn", {
102
+ enumerable: true,
103
+ configurable: true,
104
+ writable: true,
105
+ value: void 0
106
+ });
107
+ Object.defineProperty(this, "endpointHost", {
108
+ enumerable: true,
109
+ configurable: true,
110
+ writable: true,
111
+ value: void 0
112
+ });
113
+ Object.defineProperty(this, "stopSequences", {
114
+ enumerable: true,
115
+ configurable: true,
116
+ writable: true,
117
+ value: void 0
118
+ });
119
+ Object.defineProperty(this, "modelKwargs", {
120
+ enumerable: true,
121
+ configurable: true,
122
+ writable: true,
123
+ value: void 0
124
+ });
125
+ Object.defineProperty(this, "codec", {
126
+ enumerable: true,
127
+ configurable: true,
128
+ writable: true,
129
+ value: new EventStreamCodec(toUtf8, fromUtf8)
130
+ });
131
+ this.model = fields?.model ?? this.model;
132
+ const allowedModels = ["ai21", "anthropic", "amazon"];
133
+ if (!allowedModels.includes(this.model.split(".")[0])) {
134
+ throw new Error(`Unknown model: '${this.model}', only these are supported: ${allowedModels}`);
135
+ }
136
+ const region = fields?.region ?? getEnvironmentVariable("AWS_DEFAULT_REGION");
137
+ if (!region) {
138
+ throw new Error("Please set the AWS_DEFAULT_REGION environment variable or pass it to the constructor as the region field.");
139
+ }
140
+ this.region = region;
141
+ this.credentials = fields?.credentials ?? defaultProvider();
142
+ this.temperature = fields?.temperature ?? this.temperature;
143
+ this.maxTokens = fields?.maxTokens ?? this.maxTokens;
144
+ this.fetchFn = fields?.fetchFn ?? fetch;
145
+ this.endpointHost = fields?.endpointHost ?? fields?.endpointUrl;
146
+ this.stopSequences = fields?.stopSequences;
147
+ this.modelKwargs = fields?.modelKwargs;
148
+ }
149
+ /** Call out to Bedrock service model.
150
+ Arguments:
151
+ prompt: The prompt to pass into the model.
152
+
153
+ Returns:
154
+ The string generated by the model.
155
+
156
+ Example:
157
+ response = model.call("Tell me a joke.")
158
+ */
159
+ async _call(messages, options, runManager) {
160
+ const chunks = [];
161
+ for await (const chunk of this._streamResponseChunks(messages, options, runManager)) {
162
+ chunks.push(chunk);
163
+ }
164
+ return chunks.map((chunk) => chunk.text).join("");
165
+ }
166
+ async *_streamResponseChunks(messages, options, runManager) {
167
+ const provider = this.model.split(".")[0];
168
+ const service = "bedrock-runtime";
169
+ const inputBody = BedrockLLMInputOutputAdapter.prepareInput(provider, convertMessagesToPromptAnthropic(messages), this.maxTokens, this.temperature, this.stopSequences, this.modelKwargs);
170
+ const endpointHost = this.endpointHost ?? `${service}.${this.region}.amazonaws.com`;
171
+ const amazonMethod = provider === "anthropic" ? "invoke-with-response-stream" : "invoke";
172
+ const url = new URL(`https://${endpointHost}/model/${this.model}/${amazonMethod}`);
173
+ const request = new HttpRequest({
174
+ hostname: url.hostname,
175
+ path: url.pathname,
176
+ protocol: url.protocol,
177
+ method: "POST",
178
+ body: JSON.stringify(inputBody),
179
+ query: Object.fromEntries(url.searchParams.entries()),
180
+ headers: {
181
+ // host is required by AWS Signature V4: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
182
+ host: url.host,
183
+ accept: "application/json",
184
+ "content-type": "application/json",
185
+ },
186
+ });
187
+ const signer = new SignatureV4({
188
+ credentials: this.credentials,
189
+ service: "bedrock",
190
+ region: this.region,
191
+ sha256: Sha256,
192
+ });
193
+ const signedRequest = await signer.sign(request);
194
+ // Send request to AWS using the low-level fetch API
195
+ const response = await this.caller.callWithOptions({ signal: options.signal }, async () => this.fetchFn(url, {
196
+ headers: signedRequest.headers,
197
+ body: signedRequest.body,
198
+ method: signedRequest.method,
199
+ }));
200
+ if (response.status < 200 || response.status >= 300) {
201
+ throw Error(`Failed to access underlying url '${url}': got ${response.status} ${response.statusText}: ${await response.text()}`);
202
+ }
203
+ if (provider === "anthropic") {
204
+ const reader = response.body?.getReader();
205
+ const decoder = new TextDecoder();
206
+ for await (const chunk of this._readChunks(reader)) {
207
+ const event = this.codec.decode(chunk);
208
+ if ((event.headers[":event-type"] !== undefined &&
209
+ event.headers[":event-type"].value !== "chunk") ||
210
+ event.headers[":content-type"].value !== "application/json") {
211
+ throw Error(`Failed to get event chunk: got ${chunk}`);
212
+ }
213
+ // console.log(decoder.decode(event.body));
214
+ const body = JSON.parse(decoder.decode(event.body));
215
+ if (body.message) {
216
+ throw new Error(body.message);
217
+ }
218
+ if (body.bytes !== undefined) {
219
+ const chunkResult = JSON.parse(Buffer.from(body.bytes, "base64").toString());
220
+ const text = BedrockLLMInputOutputAdapter.prepareOutput(provider, chunkResult);
221
+ yield new ChatGenerationChunk({
222
+ text,
223
+ message: new AIMessageChunk({ content: text }),
224
+ });
225
+ await runManager?.handleLLMNewToken(text);
226
+ }
227
+ }
228
+ }
229
+ else {
230
+ const json = await response.json();
231
+ const text = BedrockLLMInputOutputAdapter.prepareOutput(provider, json);
232
+ yield new ChatGenerationChunk({
233
+ text,
234
+ message: new AIMessageChunk({ content: text }),
235
+ });
236
+ await runManager?.handleLLMNewToken(text);
237
+ }
238
+ }
239
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
240
+ _readChunks(reader) {
241
+ return {
242
+ async *[Symbol.asyncIterator]() {
243
+ let readResult = await reader.read();
244
+ while (!readResult.done) {
245
+ yield readResult.value;
246
+ readResult = await reader.read();
247
+ }
248
+ },
249
+ };
250
+ }
251
+ _combineLLMOutput() {
252
+ return {};
253
+ }
254
+ }
@@ -119,11 +119,15 @@ class NotionAPILoader extends base_js_1.BaseDocumentLoader {
119
119
  * @returns The string of the title.
120
120
  */
121
121
  getTitle(obj) {
122
- if ((0, exports.isPage)(obj) && obj.properties.title.type === "title") {
123
- return obj.properties.title.title[0]?.plain_text;
122
+ if ((0, exports.isPage)(obj)) {
123
+ const titleProp = Object.values(obj.properties).find((prop) => prop.type === "title");
124
+ if (titleProp)
125
+ return this.getPropValue(titleProp);
124
126
  }
125
127
  if ((0, exports.isDatabase)(obj))
126
- return obj.title[0]?.plain_text;
128
+ return obj.title
129
+ .map((v) => this.n2mClient.annotatePlainText(v.plain_text, v.annotations))
130
+ .join("");
127
131
  return null;
128
132
  }
129
133
  /**
@@ -284,7 +288,7 @@ class NotionAPILoader extends base_js_1.BaseDocumentLoader {
284
288
  });
285
289
  this.documents.push(pageDocument);
286
290
  this.pageCompleted.push(pageId);
287
- this.onDocumentLoaded(this.documents.length, this.pageQueueTotal, pageDocument.metadata.properties.title, this.rootTitle);
291
+ this.onDocumentLoaded(this.documents.length, this.pageQueueTotal, this.getTitle(pageDetails) || undefined, this.rootTitle);
288
292
  }
289
293
  /**
290
294
  * Loads a Notion database and adds it's pages to the queue.
@@ -111,11 +111,15 @@ export class NotionAPILoader extends BaseDocumentLoader {
111
111
  * @returns The string of the title.
112
112
  */
113
113
  getTitle(obj) {
114
- if (isPage(obj) && obj.properties.title.type === "title") {
115
- return obj.properties.title.title[0]?.plain_text;
114
+ if (isPage(obj)) {
115
+ const titleProp = Object.values(obj.properties).find((prop) => prop.type === "title");
116
+ if (titleProp)
117
+ return this.getPropValue(titleProp);
116
118
  }
117
119
  if (isDatabase(obj))
118
- return obj.title[0]?.plain_text;
120
+ return obj.title
121
+ .map((v) => this.n2mClient.annotatePlainText(v.plain_text, v.annotations))
122
+ .join("");
119
123
  return null;
120
124
  }
121
125
  /**
@@ -276,7 +280,7 @@ export class NotionAPILoader extends BaseDocumentLoader {
276
280
  });
277
281
  this.documents.push(pageDocument);
278
282
  this.pageCompleted.push(pageId);
279
- this.onDocumentLoaded(this.documents.length, this.pageQueueTotal, pageDocument.metadata.properties.title, this.rootTitle);
283
+ this.onDocumentLoaded(this.documents.length, this.pageQueueTotal, this.getTitle(pageDetails) || undefined, this.rootTitle);
280
284
  }
281
285
  /**
282
286
  * Loads a Notion database and adds it's pages to the queue.
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SearchApiLoader = void 0;
4
+ const env_js_1 = require("../../util/env.cjs");
5
+ const document_js_1 = require("../../document.cjs");
6
+ const base_js_1 = require("../base.cjs");
7
+ /**
8
+ * Class representing a document loader for loading search results from
9
+ * the SearchApi. It extends the BaseDocumentLoader class.
10
+ */
11
+ class SearchApiLoader extends base_js_1.BaseDocumentLoader {
12
+ constructor(params) {
13
+ super();
14
+ Object.defineProperty(this, "apiKey", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: void 0
19
+ });
20
+ Object.defineProperty(this, "parameters", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: void 0
25
+ });
26
+ const { apiKey = (0, env_js_1.getEnvironmentVariable)("SEARCHAPI_API_KEY") } = params;
27
+ if (typeof apiKey !== "string") {
28
+ throw new Error("Invalid type for apiKey. Expected string.");
29
+ }
30
+ if (!apiKey) {
31
+ throw new Error("SearchApi API key not set. You can set it as SEARCHAPI_API_KEY in your .env file, or pass it to SearchApi.");
32
+ }
33
+ this.apiKey = apiKey;
34
+ this.parameters = { ...params };
35
+ }
36
+ /**
37
+ * Builds the URL for the SearchApi search request.
38
+ * @returns The URL for the search request.
39
+ */
40
+ buildUrl() {
41
+ this.parameters = {
42
+ engine: "google",
43
+ api_key: this.apiKey,
44
+ ...this.parameters,
45
+ };
46
+ const preparedParams = Object.entries(this.parameters)
47
+ .filter(([key, value]) => value !== undefined && value !== null && key !== "apiKey")
48
+ .map(([key, value]) => [key, `${value}`]);
49
+ const searchParams = new URLSearchParams(preparedParams);
50
+ return `https://www.searchapi.io/api/v1/search?${searchParams}`;
51
+ }
52
+ /**
53
+ * Extracts documents from the provided output.
54
+ * @param output - The output to extract documents from.
55
+ * @param responseType - The type of the response to extract documents from.
56
+ * @returns An array of Documents.
57
+ */
58
+ extractDocuments(output, responseType) {
59
+ const documents = [];
60
+ const results = Array.isArray(output) ? output : [output];
61
+ if (responseType === "transcripts") {
62
+ const pageContent = results.map((result) => result.text).join("\n");
63
+ const metadata = {
64
+ source: "SearchApi",
65
+ responseType,
66
+ };
67
+ documents.push(new document_js_1.Document({ pageContent, metadata }));
68
+ }
69
+ else {
70
+ for (const result of results) {
71
+ const pageContent = JSON.stringify(result);
72
+ const metadata = {
73
+ source: "SearchApi",
74
+ responseType,
75
+ };
76
+ documents.push(new document_js_1.Document({ pageContent, metadata }));
77
+ }
78
+ }
79
+ return documents;
80
+ }
81
+ /**
82
+ * Processes the response data from the SearchApi search request and converts it into an array of Documents.
83
+ * @param data - The response data from the SearchApi search request.
84
+ * @returns An array of Documents.
85
+ */
86
+ processResponseData(data) {
87
+ const documents = [];
88
+ const responseTypes = [
89
+ "answer_box",
90
+ "shopping_results",
91
+ "knowledge_graph",
92
+ "organic_results",
93
+ "transcripts",
94
+ ];
95
+ for (const responseType of responseTypes) {
96
+ if (responseType in data) {
97
+ documents.push(...this.extractDocuments(data[responseType], responseType));
98
+ }
99
+ }
100
+ return documents;
101
+ }
102
+ /**
103
+ * Fetches the data from the provided URL and returns it as a JSON object.
104
+ * If an error occurs during the fetch operation, an exception is thrown with the error message.
105
+ * @param url - The URL to fetch data from.
106
+ * @returns A promise that resolves to the fetched data as a JSON object.
107
+ * @throws An error if the fetch operation fails.
108
+ */
109
+ async fetchData(url) {
110
+ const response = await fetch(url);
111
+ const data = await response.json();
112
+ if (data.error) {
113
+ throw new Error(`Failed to load search results from SearchApi due to: ${data.error}`);
114
+ }
115
+ return data;
116
+ }
117
+ /**
118
+ * Loads the search results from the SearchApi.
119
+ * @returns An array of Documents representing the search results.
120
+ * @throws An error if the search results could not be loaded.
121
+ */
122
+ async load() {
123
+ const url = this.buildUrl();
124
+ const data = await this.fetchData(url);
125
+ try {
126
+ return this.processResponseData(data);
127
+ }
128
+ catch (error) {
129
+ console.error(error);
130
+ throw new Error(`Failed to process search results from SearchApi: ${error}`);
131
+ }
132
+ }
133
+ }
134
+ exports.SearchApiLoader = SearchApiLoader;
@@ -0,0 +1,65 @@
1
+ import { Document } from "../../document.js";
2
+ import { BaseDocumentLoader } from "../base.js";
3
+ type JSONPrimitive = string | number | boolean | null;
4
+ type JSONValue = JSONPrimitive | JSONObject | JSONArray;
5
+ interface JSONObject {
6
+ [key: string]: JSONValue;
7
+ }
8
+ interface JSONArray extends Array<JSONValue> {
9
+ }
10
+ /**
11
+ * SearchApiParameters Type Definition.
12
+ *
13
+ * For more parameters and supported search engines, refer specific engine documentation:
14
+ * Google - https://www.searchapi.io/docs/google
15
+ * Google News - https://www.searchapi.io/docs/google-news
16
+ * Google Scholar - https://www.searchapi.io/docs/google-scholar
17
+ * YouTube Transcripts - https://www.searchapi.io/docs/youtube-transcripts
18
+ * and others.
19
+ *
20
+ */
21
+ type SearchApiParameters = {
22
+ [key: string]: JSONValue;
23
+ };
24
+ /**
25
+ * Class representing a document loader for loading search results from
26
+ * the SearchApi. It extends the BaseDocumentLoader class.
27
+ */
28
+ export declare class SearchApiLoader extends BaseDocumentLoader {
29
+ private apiKey;
30
+ private parameters;
31
+ constructor(params: SearchApiParameters);
32
+ /**
33
+ * Builds the URL for the SearchApi search request.
34
+ * @returns The URL for the search request.
35
+ */
36
+ buildUrl(): string;
37
+ /**
38
+ * Extracts documents from the provided output.
39
+ * @param output - The output to extract documents from.
40
+ * @param responseType - The type of the response to extract documents from.
41
+ * @returns An array of Documents.
42
+ */
43
+ private extractDocuments;
44
+ /**
45
+ * Processes the response data from the SearchApi search request and converts it into an array of Documents.
46
+ * @param data - The response data from the SearchApi search request.
47
+ * @returns An array of Documents.
48
+ */
49
+ processResponseData(data: Record<string, unknown>): Document[];
50
+ /**
51
+ * Fetches the data from the provided URL and returns it as a JSON object.
52
+ * If an error occurs during the fetch operation, an exception is thrown with the error message.
53
+ * @param url - The URL to fetch data from.
54
+ * @returns A promise that resolves to the fetched data as a JSON object.
55
+ * @throws An error if the fetch operation fails.
56
+ */
57
+ private fetchData;
58
+ /**
59
+ * Loads the search results from the SearchApi.
60
+ * @returns An array of Documents representing the search results.
61
+ * @throws An error if the search results could not be loaded.
62
+ */
63
+ load(): Promise<Document[]>;
64
+ }
65
+ export {};
@@ -0,0 +1,130 @@
1
+ import { getEnvironmentVariable } from "../../util/env.js";
2
+ import { Document } from "../../document.js";
3
+ import { BaseDocumentLoader } from "../base.js";
4
+ /**
5
+ * Class representing a document loader for loading search results from
6
+ * the SearchApi. It extends the BaseDocumentLoader class.
7
+ */
8
+ export class SearchApiLoader extends BaseDocumentLoader {
9
+ constructor(params) {
10
+ super();
11
+ Object.defineProperty(this, "apiKey", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ Object.defineProperty(this, "parameters", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ const { apiKey = getEnvironmentVariable("SEARCHAPI_API_KEY") } = params;
24
+ if (typeof apiKey !== "string") {
25
+ throw new Error("Invalid type for apiKey. Expected string.");
26
+ }
27
+ if (!apiKey) {
28
+ throw new Error("SearchApi API key not set. You can set it as SEARCHAPI_API_KEY in your .env file, or pass it to SearchApi.");
29
+ }
30
+ this.apiKey = apiKey;
31
+ this.parameters = { ...params };
32
+ }
33
+ /**
34
+ * Builds the URL for the SearchApi search request.
35
+ * @returns The URL for the search request.
36
+ */
37
+ buildUrl() {
38
+ this.parameters = {
39
+ engine: "google",
40
+ api_key: this.apiKey,
41
+ ...this.parameters,
42
+ };
43
+ const preparedParams = Object.entries(this.parameters)
44
+ .filter(([key, value]) => value !== undefined && value !== null && key !== "apiKey")
45
+ .map(([key, value]) => [key, `${value}`]);
46
+ const searchParams = new URLSearchParams(preparedParams);
47
+ return `https://www.searchapi.io/api/v1/search?${searchParams}`;
48
+ }
49
+ /**
50
+ * Extracts documents from the provided output.
51
+ * @param output - The output to extract documents from.
52
+ * @param responseType - The type of the response to extract documents from.
53
+ * @returns An array of Documents.
54
+ */
55
+ extractDocuments(output, responseType) {
56
+ const documents = [];
57
+ const results = Array.isArray(output) ? output : [output];
58
+ if (responseType === "transcripts") {
59
+ const pageContent = results.map((result) => result.text).join("\n");
60
+ const metadata = {
61
+ source: "SearchApi",
62
+ responseType,
63
+ };
64
+ documents.push(new Document({ pageContent, metadata }));
65
+ }
66
+ else {
67
+ for (const result of results) {
68
+ const pageContent = JSON.stringify(result);
69
+ const metadata = {
70
+ source: "SearchApi",
71
+ responseType,
72
+ };
73
+ documents.push(new Document({ pageContent, metadata }));
74
+ }
75
+ }
76
+ return documents;
77
+ }
78
+ /**
79
+ * Processes the response data from the SearchApi search request and converts it into an array of Documents.
80
+ * @param data - The response data from the SearchApi search request.
81
+ * @returns An array of Documents.
82
+ */
83
+ processResponseData(data) {
84
+ const documents = [];
85
+ const responseTypes = [
86
+ "answer_box",
87
+ "shopping_results",
88
+ "knowledge_graph",
89
+ "organic_results",
90
+ "transcripts",
91
+ ];
92
+ for (const responseType of responseTypes) {
93
+ if (responseType in data) {
94
+ documents.push(...this.extractDocuments(data[responseType], responseType));
95
+ }
96
+ }
97
+ return documents;
98
+ }
99
+ /**
100
+ * Fetches the data from the provided URL and returns it as a JSON object.
101
+ * If an error occurs during the fetch operation, an exception is thrown with the error message.
102
+ * @param url - The URL to fetch data from.
103
+ * @returns A promise that resolves to the fetched data as a JSON object.
104
+ * @throws An error if the fetch operation fails.
105
+ */
106
+ async fetchData(url) {
107
+ const response = await fetch(url);
108
+ const data = await response.json();
109
+ if (data.error) {
110
+ throw new Error(`Failed to load search results from SearchApi due to: ${data.error}`);
111
+ }
112
+ return data;
113
+ }
114
+ /**
115
+ * Loads the search results from the SearchApi.
116
+ * @returns An array of Documents representing the search results.
117
+ * @throws An error if the search results could not be loaded.
118
+ */
119
+ async load() {
120
+ const url = this.buildUrl();
121
+ const data = await this.fetchData(url);
122
+ try {
123
+ return this.processResponseData(data);
124
+ }
125
+ catch (error) {
126
+ console.error(error);
127
+ throw new Error(`Failed to process search results from SearchApi: ${error}`);
128
+ }
129
+ }
130
+ }