agsamantha/node_modules/@langchain/community/dist/vectorstores/turbopuffer.cjs
2024-10-02 15:15:21 -05:00

211 lines
8.2 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TurbopufferVectorStore = void 0;
const uuid_1 = require("uuid");
const documents_1 = require("@langchain/core/documents");
const async_caller_1 = require("@langchain/core/utils/async_caller");
const chunk_array_1 = require("@langchain/core/utils/chunk_array");
const env_1 = require("@langchain/core/utils/env");
const vectorstores_1 = require("@langchain/core/vectorstores");
class TurbopufferVectorStore extends vectorstores_1.VectorStore {
get lc_secrets() {
return {
apiKey: "TURBOPUFFER_API_KEY",
};
}
get lc_aliases() {
return {
apiKey: "TURBOPUFFER_API_KEY",
};
}
// Handle minification for tracing
static lc_name() {
return "TurbopufferVectorStore";
}
_vectorstoreType() {
return "turbopuffer";
}
constructor(embeddings, args) {
super(embeddings, args);
Object.defineProperty(this, "distanceMetric", {
enumerable: true,
configurable: true,
writable: true,
value: "cosine_distance"
});
Object.defineProperty(this, "apiKey", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "namespace", {
enumerable: true,
configurable: true,
writable: true,
value: "default"
});
Object.defineProperty(this, "apiUrl", {
enumerable: true,
configurable: true,
writable: true,
value: "https://api.turbopuffer.com/v1"
});
Object.defineProperty(this, "caller", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "batchSize", {
enumerable: true,
configurable: true,
writable: true,
value: 3000
});
const { apiKey: argsApiKey, namespace, distanceMetric, apiUrl, batchSize, ...asyncCallerArgs } = args;
const apiKey = argsApiKey ?? (0, env_1.getEnvironmentVariable)("TURBOPUFFER_API_KEY");
if (!apiKey) {
throw new Error(`Turbopuffer API key not found.\nPlease pass it in as "apiKey" or set it as an environment variable called "TURBOPUFFER_API_KEY"`);
}
this.apiKey = apiKey;
this.namespace = namespace ?? this.namespace;
this.distanceMetric = distanceMetric ?? this.distanceMetric;
this.apiUrl = apiUrl ?? this.apiUrl;
this.batchSize = batchSize ?? this.batchSize;
this.caller = new async_caller_1.AsyncCaller({
maxConcurrency: 6,
maxRetries: 0,
...asyncCallerArgs,
});
}
defaultHeaders() {
return {
Authorization: `Bearer ${this.apiKey}`,
"Content-Type": "application/json",
};
}
async callWithRetry(fetchUrl, stringifiedBody, method = "POST") {
const json = await this.caller.call(async () => {
const headers = {
Authorization: `Bearer ${this.apiKey}`,
};
if (stringifiedBody !== undefined) {
headers["Content-Type"] = "application/json";
}
const response = await fetch(fetchUrl, {
method,
headers,
body: stringifiedBody,
});
if (response.status !== 200) {
const error = new Error(`Failed to call turbopuffer. Response status ${response.status}\nFull response: ${await response.text()}`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error.response = response;
throw error;
}
return response.json();
});
return json;
}
async addVectors(vectors, documents, options) {
if (options?.ids && options.ids.length !== vectors.length) {
throw new Error("Number of ids provided does not match number of vectors");
}
if (documents.length !== vectors.length) {
throw new Error("Number of documents provided does not match number of vectors");
}
if (documents.length === 0) {
throw new Error("No documents provided");
}
const batchedVectors = (0, chunk_array_1.chunkArray)(vectors, this.batchSize);
const batchedDocuments = (0, chunk_array_1.chunkArray)(documents, this.batchSize);
const batchedIds = options?.ids
? (0, chunk_array_1.chunkArray)(options.ids, this.batchSize)
: batchedDocuments.map((docs) => docs.map((_) => (0, uuid_1.v4)()));
const batchRequests = batchedVectors.map(async (batchVectors, index) => {
const batchDocs = batchedDocuments[index];
const batchIds = batchedIds[index];
if (batchIds.length !== batchVectors.length) {
throw new Error("Number of ids provided does not match number of vectors");
}
const attributes = {
__lc_page_content: batchDocs.map((doc) => doc.pageContent),
};
const usedMetadataFields = new Set(batchDocs.map((doc) => Object.keys(doc.metadata)).flat());
for (const key of usedMetadataFields) {
attributes[key] = batchDocs.map((doc) => {
if (doc.metadata[key] !== undefined) {
if (typeof doc.metadata[key] === "string") {
return doc.metadata[key];
}
else {
console.warn([
`[WARNING]: Dropping non-string metadata key "${key}" with value "${JSON.stringify(doc.metadata[key])}".`,
`turbopuffer currently supports only string metadata values.`,
].join("\n"));
return null;
}
}
else {
return null;
}
});
}
const data = {
ids: batchIds,
vectors: batchVectors,
attributes,
};
return this.callWithRetry(`${this.apiUrl}/vectors/${this.namespace}`, JSON.stringify(data));
});
// Execute all batch requests in parallel
await Promise.all(batchRequests);
return batchedIds.flat();
}
async delete(params) {
if (params.deleteIndex) {
await this.callWithRetry(`${this.apiUrl}/vectors/${this.namespace}`, undefined, "DELETE");
}
else {
throw new Error(`You must provide a "deleteIndex" flag.`);
}
}
async addDocuments(documents, options) {
const vectors = await this.embeddings.embedDocuments(documents.map((doc) => doc.pageContent));
return this.addVectors(vectors, documents, options);
}
async queryVectors(query, k, includeVector,
// See https://Turbopuffer.com/docs/reference/query for more info
filter) {
const data = {
vector: query,
top_k: k,
distance_metric: this.distanceMetric,
filters: filter,
include_attributes: true,
include_vectors: includeVector,
};
return this.callWithRetry(`${this.apiUrl}/vectors/${this.namespace}/query`, JSON.stringify(data));
}
async similaritySearchVectorWithScore(query, k, filter) {
const search = await this.queryVectors(query, k, false, filter);
const result = search.map((res) => {
const { __lc_page_content, ...metadata } = res.attributes;
return [
new documents_1.Document({
pageContent: __lc_page_content,
metadata,
}),
res.dist,
];
});
return result;
}
static async fromDocuments(docs, embeddings, dbConfig) {
const instance = new this(embeddings, dbConfig);
await instance.addDocuments(docs);
return instance;
}
}
exports.TurbopufferVectorStore = TurbopufferVectorStore;