@jackhua/mini-langchain
Version:
A lightweight TypeScript implementation of LangChain with cost optimization features
179 lines • 5.28 kB
JavaScript
;
/**
* In-memory vector store implementation
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemoryVectorStore = void 0;
const uuid_1 = require("uuid");
const base_1 = require("./base");
/**
* Simple in-memory vector store
*/
class MemoryVectorStore extends base_1.VectorStore {
constructor(embeddings) {
super(embeddings);
this.vectors = new Map();
this.documents = new Map();
}
/**
* Add documents to the vector store
*/
async addDocuments(documents) {
const texts = documents.map(doc => doc.pageContent);
const embeddings = await this.embeddings.embedDocuments(texts);
return this.addVectors(embeddings, documents);
}
/**
* Add vectors directly
*/
async addVectors(vectors, documents) {
const ids = [];
for (let i = 0; i < vectors.length; i++) {
const id = (0, uuid_1.v4)();
const vector = {
id,
values: vectors[i],
metadata: documents[i].metadata
};
this.vectors.set(id, vector);
this.documents.set(id, documents[i]);
ids.push(id);
}
return ids;
}
/**
* Similarity search
*/
async similaritySearch(query, k = 4, filter) {
const results = await this.similaritySearchWithScore(query, k, filter);
return results.map(([doc]) => doc);
}
/**
* Similarity search with score
*/
async similaritySearchWithScore(query, k = 4, filter) {
const queryEmbedding = await this.embeddings.embedQuery(query);
return this.similaritySearchVectorWithScore(queryEmbedding, k, filter);
}
/**
* Similarity search by vector
*/
async similaritySearchVectorWithScore(query, k, filter) {
const scores = [];
// Calculate similarity scores
for (const [id, vector] of this.vectors.entries()) {
const doc = this.documents.get(id);
// Apply filter if provided
if (filter && !this.matchesFilter(doc.metadata || {}, filter)) {
continue;
}
const similarity = this.cosineSimilarity(query, vector.values);
scores.push([id, similarity]);
}
// Sort by similarity (descending)
scores.sort((a, b) => b[1] - a[1]);
// Return top k results
return scores.slice(0, k).map(([id, score]) => {
const doc = this.documents.get(id);
return [doc, score];
});
}
/**
* Delete documents
*/
async delete(params) {
if (!params) {
// Clear all
this.vectors.clear();
this.documents.clear();
return;
}
const { ids, filter } = params;
if (ids) {
// Delete by IDs
for (const id of ids) {
this.vectors.delete(id);
this.documents.delete(id);
}
}
if (filter) {
// Delete by filter
const toDelete = [];
for (const [id, doc] of this.documents.entries()) {
if (this.matchesFilter(doc.metadata || {}, filter)) {
toDelete.push(id);
}
}
for (const id of toDelete) {
this.vectors.delete(id);
this.documents.delete(id);
}
}
}
/**
* Calculate cosine similarity between two vectors
*/
cosineSimilarity(a, b) {
let dotProduct = 0;
let normA = 0;
let normB = 0;
for (let i = 0; i < a.length; i++) {
dotProduct += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
normA = Math.sqrt(normA);
normB = Math.sqrt(normB);
if (normA === 0 || normB === 0) {
return 0;
}
return dotProduct / (normA * normB);
}
/**
* Check if metadata matches filter
*/
matchesFilter(metadata, filter) {
for (const [key, value] of Object.entries(filter)) {
if (metadata[key] !== value) {
return false;
}
}
return true;
}
/**
* Create from texts
*/
static async fromTexts(texts, metadatas, embeddings) {
const docs = [];
for (let i = 0; i < texts.length; i++) {
const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;
docs.push({
pageContent: texts[i],
metadata: metadata || {}
});
}
return MemoryVectorStore.fromDocuments(docs, embeddings);
}
/**
* Create from documents
*/
static async fromDocuments(docs, embeddings) {
const store = new MemoryVectorStore(embeddings);
await store.addDocuments(docs);
return store;
}
/**
* Get all documents
*/
getAllDocuments() {
return Array.from(this.documents.values());
}
/**
* Get document count
*/
getDocumentCount() {
return this.documents.size;
}
}
exports.MemoryVectorStore = MemoryVectorStore;
//# sourceMappingURL=memory.js.map