@forge-ml/rag
Version:
A RAG (Retrieval-Augmented Generation) package for Forge ML
92 lines (91 loc) • 3.08 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const redis_1 = require("redis");
const INDEX_KEY = "idx:chunks";
const CHUNK_KEY_PREFIX = `chunks`;
// small model is 1536, large model is 3072
var DIM;
(function (DIM) {
DIM[DIM["OPENAI_SMALL"] = 1536] = "OPENAI_SMALL";
DIM[DIM["OPENAI_LARGE"] = 3072] = "OPENAI_LARGE";
DIM[DIM["NOMIC_V1_5"] = 768] = "NOMIC_V1_5";
})(DIM || (DIM = {}));
//@TODO pass in the user's embedding model and adjust the DIM accordingly
const GenericIndex = {
"$.chunkEmbeddings": {
type: redis_1.SchemaFieldTypes.VECTOR,
TYPE: "FLOAT32",
ALGORITHM: redis_1.VectorAlgorithms.FLAT,
DIM: DIM.NOMIC_V1_5, // this needs to be set to the dimesension set by the embedding model, 3072 for text-embedding-3-large or 1536 for text-embedding-3-small, 768 for nomic v1.5 embedder
DISTANCE_METRIC: "L2",
AS: "chunkEmbeddings",
},
"$.chunkId": {
type: redis_1.SchemaFieldTypes.TEXT,
NOSTEM: true,
SORTABLE: true,
AS: "chunkId",
},
"$.documentId": {
type: redis_1.SchemaFieldTypes.TEXT,
NOSTEM: true,
SORTABLE: true,
AS: "documentId",
},
};
class RedisVectorStore {
client;
constructor(url) {
this.client = (0, redis_1.createClient)({ url });
this.client.connect().catch(console.error);
}
async createIndex() {
try {
await this.client.ft.dropIndex(INDEX_KEY).catch(() => { });
}
catch (indexErr) {
console.error(indexErr);
}
await this.client.ft.create(INDEX_KEY, GenericIndex, {
ON: "JSON",
PREFIX: CHUNK_KEY_PREFIX,
});
}
async addEmbedding(embedding) {
return this.client.json.set(`${CHUNK_KEY_PREFIX}:${embedding.chunkId}`, "$", {
chunkId: embedding.chunkId,
documentId: embedding.documentId,
chunkEmbeddings: embedding.embedding,
});
}
async storeEmbeddings(embeddings) {
await Promise.all(embeddings.map((embedding) => this.addEmbedding(embedding)));
}
async queryEmbeddings(query, k) {
const results = await this.knnSearchEmbeddings({
inputVector: query,
k,
});
return results.documents.map((doc) => ({
chunkId: doc.value.chunkId,
documentId: doc.value.documentId,
score: doc.value.score,
}));
}
async knnSearchEmbeddings({ inputVector, k, }) {
//console.log(inputVector);
const query = `*=>[KNN ${k} @chunkEmbeddings $searchBlob AS score]`;
return this.client.ft.search(INDEX_KEY, query, {
PARAMS: {
searchBlob: Buffer.from(new Float32Array(inputVector).buffer),
},
RETURN: ["score", "chunkId", "documentId"],
SORTBY: {
BY: "score",
// DIRECTION: "DESC"
},
DIALECT: 2,
});
}
}
exports.default = RedisVectorStore;