@langchain/community
Version:
Third-party integrations for LangChain.js
171 lines (169 loc) • 6.71 kB
JavaScript
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
const require_sqlite_where_builder = require('../utils/sqlite_where_builder.cjs');
const __langchain_core_documents = require_rolldown_runtime.__toESM(require("@langchain/core/documents"));
const __langchain_core_vectorstores = require_rolldown_runtime.__toESM(require("@langchain/core/vectorstores"));
//#region src/vectorstores/libsql.ts
var libsql_exports = {};
require_rolldown_runtime.__export(libsql_exports, { LibSQLVectorStore: () => LibSQLVectorStore });
/**
* A vector store using LibSQL/Turso for storage and retrieval.
*/
var LibSQLVectorStore = class LibSQLVectorStore extends __langchain_core_vectorstores.VectorStore {
db;
table;
column;
/**
* Returns the type of vector store.
* @returns {string} The string "libsql".
*/
_vectorstoreType() {
return "libsql";
}
/**
* Initializes a new instance of the LibSQLVectorStore.
* @param {EmbeddingsInterface} embeddings - The embeddings interface to use.
* @param {Client} db - The LibSQL client instance.
* @param {LibSQLVectorStoreArgs} options - Configuration options for the vector store.
*/
constructor(embeddings, options) {
super(embeddings, options);
this.db = options.db;
this.table = options.table || "vectors";
this.column = options.column || "embedding";
}
/**
* Adds documents to the vector store.
* @param {Document<Metadata>[]} documents - The documents to add.
* @returns {Promise<string[]>} The IDs of the added documents.
*/
async addDocuments(documents) {
const texts = documents.map(({ pageContent }) => pageContent);
const embeddings = await this.embeddings.embedDocuments(texts);
return this.addVectors(embeddings, documents);
}
/**
* Adds vectors to the vector store.
* @param {number[][]} vectors - The vectors to add.
* @param {Document<Metadata>[]} documents - The documents associated with the vectors.
* @returns {Promise<string[]>} The IDs of the added vectors.
*/
async addVectors(vectors, documents) {
const rows = vectors.map((embedding, idx) => ({
content: documents[idx].pageContent,
embedding: `[${embedding.join(",")}]`,
metadata: JSON.stringify(documents[idx].metadata)
}));
const batchSize = 100;
const ids = [];
for (let i = 0; i < rows.length; i += batchSize) {
const chunk = rows.slice(i, i + batchSize);
const insertQueries = chunk.map((row) => ({
sql: `INSERT INTO ${this.table} (content, metadata, ${this.column}) VALUES (:content, :metadata, vector(:embedding)) RETURNING ${this.table}.rowid AS id`,
args: row
}));
const results = await this.db.batch(insertQueries);
ids.push(...results.flatMap((result) => result.rows.map((row) => String(row.id))));
}
return ids;
}
/**
* Performs a similarity search using a vector query and returns documents with their scores.
* @param {number[]} query - The query vector.
* @param {number} k - The number of results to return.
* @returns {Promise<[Document<Metadata>, number][]>} An array of tuples containing the similar documents and their scores.
*/
async similaritySearchVectorWithScore(query, k, filter) {
if (!query.every((num) => typeof num === "number" && !Number.isNaN(num))) throw new Error("Invalid query vector: all elements must be numbers");
const queryVector = `[${query.join(",")}]`;
const sql = {
sql: `SELECT ${this.table}.rowid as id, ${this.table}.content, ${this.table}.metadata, vector_distance_cos(${this.table}.${this.column}, vector(:queryVector)) AS distance
FROM vector_top_k('idx_${this.table}_${this.column}', vector(:queryVector), CAST(:k AS INTEGER)) as top_k
JOIN ${this.table} ON top_k.rowid = ${this.table}.rowid`,
args: {
queryVector,
k
}
};
if (typeof filter === "string") sql.sql += ` AND ${filter}`;
else if (typeof filter === "object") if ("sql" in filter) {
sql.sql += ` AND ${filter.sql}`;
sql.args = {
...filter.args,
...sql.args
};
} else {
const builder = new require_sqlite_where_builder.SqliteWhereBuilder(filter);
const where = builder.buildWhereClause();
sql.sql += ` AND ${where.sql}`;
sql.args = {
...where.args,
...sql.args
};
}
const results = await this.db.execute(sql);
return results.rows.map((row) => {
const metadata = JSON.parse(row.metadata);
const doc = new __langchain_core_documents.Document({
id: String(row.id),
metadata,
pageContent: row.content
});
return [doc, row.distance];
});
}
/**
* Deletes vectors from the store.
* @param {Object} params - Delete parameters.
* @param {string[] | number[]} [params.ids] - The ids of the vectors to delete.
* @returns {Promise<void>}
*/
async delete(params) {
if (params.deleteAll) await this.db.execute(`DELETE FROM ${this.table}`);
else if (params.ids !== void 0) await this.db.batch(params.ids.map((id) => ({
sql: `DELETE FROM ${this.table} WHERE rowid = :id`,
args: { id }
})));
else throw new Error(`You must provide an "ids" parameter or a "deleteAll" parameter.`);
}
/**
* Creates a new LibSQLVectorStore instance from texts.
* @param {string[]} texts - The texts to add to the store.
* @param {object[] | object} metadatas - The metadata for the texts.
* @param {EmbeddingsInterface} embeddings - The embeddings interface to use.
* @param {Client} dbClient - The LibSQL client instance.
* @param {LibSQLVectorStoreArgs} [options] - Configuration options for the vector store.
* @returns {Promise<LibSQLVectorStore>} A new LibSQLVectorStore instance.
*/
static async fromTexts(texts, metadatas, embeddings, options) {
const docs = texts.map((text, i) => {
const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;
return new __langchain_core_documents.Document({
pageContent: text,
metadata
});
});
return LibSQLVectorStore.fromDocuments(docs, embeddings, options);
}
/**
* Creates a new LibSQLVectorStore instance from documents.
* @param {Document[]} docs - The documents to add to the store.
* @param {EmbeddingsInterface} embeddings - The embeddings interface to use.
* @param {Client} dbClient - The LibSQL client instance.
* @param {LibSQLVectorStoreArgs} [options] - Configuration options for the vector store.
* @returns {Promise<LibSQLVectorStore>} A new LibSQLVectorStore instance.
*/
static async fromDocuments(docs, embeddings, options) {
const instance = new this(embeddings, options);
await instance.addDocuments(docs);
return instance;
}
};
//#endregion
exports.LibSQLVectorStore = LibSQLVectorStore;
Object.defineProperty(exports, 'libsql_exports', {
enumerable: true,
get: function () {
return libsql_exports;
}
});
//# sourceMappingURL=libsql.cjs.map