{"version":3,"file":"usearch.cjs","names":["SaveableVectorStore","embeddings: EmbeddingsInterface","args: USearchArgs","documents: Document[]","index: Index","vectors: number[][]","Index","MetricKind","ScalarKind","query: number[]","k: number","return_list: [Document, number][]","uuid","directory: string","texts: string[]","metadatas: object[] | object","dbConfig?: {\n      docstore?: SynchronousInMemoryDocstore;\n    }","docs: Document[]","Document"],"sources":["../../src/vectorstores/usearch.ts"],"sourcesContent":["import { Index, MetricKind, ScalarKind } from \"usearch\";\nimport * as uuid from \"uuid\";\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { SaveableVectorStore } from \"@langchain/core/vectorstores\";\nimport { Document } from \"@langchain/core/documents\";\nimport { SynchronousInMemoryDocstore } from \"../stores/doc/in_memory.js\";\n\n/**\n * Interface that defines the arguments that can be passed to the\n * `USearch` constructor. It includes optional properties for a\n * `docstore`, `index`, and `mapping`.\n */\nexport interface USearchArgs {\n  docstore?: SynchronousInMemoryDocstore;\n  index?: Index;\n  mapping?: Record<number, string>;\n}\n\n/**\n * Class that extends `SaveableVectorStore` and provides methods for\n * adding documents and vectors to a `usearch` index, performing\n * similarity searches, and saving the index.\n */\nexport class USearch extends SaveableVectorStore {\n  _index?: Index;\n\n  _mapping: Record<number, string>;\n\n  docstore: SynchronousInMemoryDocstore;\n\n  args: USearchArgs;\n\n  _vectorstoreType(): string {\n    return \"usearch\";\n  }\n\n  constructor(embeddings: EmbeddingsInterface, args: USearchArgs) {\n    super(embeddings, args);\n    this.args = args;\n    this._index = args.index;\n    this._mapping = args.mapping ?? {};\n    this.embeddings = embeddings;\n    this.docstore = args?.docstore ?? new SynchronousInMemoryDocstore();\n  }\n\n  /**\n   * Method that adds documents to the `usearch` index. It generates\n   * embeddings for the documents and adds them to the index.\n   * @param documents An array of `Document` instances to be added to the index.\n   * @returns A promise that resolves with an array of document IDs.\n   */\n  async addDocuments(documents: Document[]) {\n    const texts = documents.map(({ pageContent }) => pageContent);\n    return this.addVectors(\n      await this.embeddings.embedDocuments(texts),\n      documents\n    );\n  }\n\n  public get index(): Index {\n    if (!this._index) {\n      throw new Error(\n        \"Vector store not initialised yet. Try calling `fromTexts` or `fromDocuments` first.\"\n      );\n    }\n    return this._index;\n  }\n\n  private set index(index: Index) {\n    this._index = index;\n  }\n\n  /**\n   * Method that adds vectors to the `usearch` index. It also updates the\n   * mapping between vector IDs and document IDs.\n   * @param vectors An array of vectors to be added to the index.\n   * @param documents An array of `Document` instances corresponding to the vectors.\n   * @returns A promise that resolves with an array of document IDs.\n   */\n  async addVectors(vectors: number[][], documents: Document[]) {\n    if (vectors.length === 0) {\n      return [];\n    }\n    if (vectors.length !== documents.length) {\n      throw new Error(`Vectors and documents must have the same length`);\n    }\n    const dv = vectors[0].length;\n    if (!this._index) {\n      this._index = new Index(dv, MetricKind.L2sq, ScalarKind.F32, 16);\n    }\n    const d = this.index.dimensions();\n    if (dv !== d) {\n      throw new Error(\n        `Vectors must have the same length as the number of dimensions (${d})`\n      );\n    }\n\n    const docstoreSize = this.index.size();\n    const documentIds = [];\n    for (let i = 0; i < vectors.length; i += 1) {\n      const documentId = uuid.v4();\n      documentIds.push(documentId);\n      const id = Number(docstoreSize) + i;\n      this.index.add(BigInt(id), new Float32Array(vectors[i]));\n      this._mapping[id] = documentId;\n      this.docstore.add({ [documentId]: documents[i] });\n    }\n    return documentIds;\n  }\n\n  /**\n   * Method that performs a similarity search in the `usearch` index. It\n   * returns the `k` most similar documents to a given query vector, along\n   * with their similarity scores.\n   * @param query The query vector.\n   * @param k The number of most similar documents to return.\n   * @returns A promise that resolves with an array of tuples, each containing a `Document` and its similarity score.\n   */\n  async similaritySearchVectorWithScore(query: number[], k: number) {\n    const d = this.index.dimensions();\n    if (query.length !== d) {\n      throw new Error(\n        `Query vector must have the same length as the number of dimensions (${d})`\n      );\n    }\n    if (k > this.index.size()) {\n      const total = this.index.size();\n      console.warn(\n        `k (${k}) is greater than the number of elements in the index (${total}), setting k to ${total}`\n      );\n      // eslint-disable-next-line no-param-reassign\n      k = Number(total);\n    }\n    const result = this.index.search(new Float32Array(query), k);\n\n    const return_list: [Document, number][] = [];\n    for (\n      let i = 0;\n      i < result.keys.length && i < result.distances.length;\n      i += 1\n    ) {\n      const uuid = this._mapping[Number(result.keys[i])];\n      return_list.push([this.docstore.search(uuid), result.distances[i]]);\n    }\n\n    return return_list;\n  }\n\n  /**\n   * Method that saves the `usearch` index and the document store to disk.\n   * @param directory The directory where the index and document store should be saved.\n   * @returns A promise that resolves when the save operation is complete.\n   */\n  async save(directory: string) {\n    const fs = await import(\"node:fs/promises\");\n    const path = await import(\"node:path\");\n    await fs.mkdir(directory, { recursive: true });\n    await Promise.all([\n      this.index.save(path.join(directory, \"usearch.index\")),\n      await fs.writeFile(\n        path.join(directory, \"docstore.json\"),\n        JSON.stringify([\n          Array.from(this.docstore._docs.entries()),\n          this._mapping,\n        ])\n      ),\n    ]);\n  }\n\n  /**\n   * Static method that creates a new `USearch` instance from a list of\n   * texts. It generates embeddings for the texts and adds them to the\n   * `usearch` index.\n   * @param texts An array of texts to be added to the index.\n   * @param metadatas Metadata associated with the texts.\n   * @param embeddings An instance of `Embeddings` used to generate embeddings for the texts.\n   * @param dbConfig Optional configuration for the document store.\n   * @returns A promise that resolves with a new `USearch` instance.\n   */\n  static async fromTexts(\n    texts: string[],\n    metadatas: object[] | object,\n    embeddings: EmbeddingsInterface,\n    dbConfig?: {\n      docstore?: SynchronousInMemoryDocstore;\n    }\n  ): Promise<USearch> {\n    const docs: Document[] = [];\n    for (let i = 0; i < texts.length; i += 1) {\n      const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;\n      const newDoc = new Document({\n        pageContent: texts[i],\n        metadata,\n      });\n      docs.push(newDoc);\n    }\n    return this.fromDocuments(docs, embeddings, dbConfig);\n  }\n\n  /**\n   * Static method that creates a new `USearch` instance from a list of\n   * documents. It generates embeddings for the documents and adds them to\n   * the `usearch` index.\n   * @param docs An array of `Document` instances to be added to the index.\n   * @param embeddings An instance of `Embeddings` used to generate embeddings for the documents.\n   * @param dbConfig Optional configuration for the document store.\n   * @returns A promise that resolves with a new `USearch` instance.\n   */\n  static async fromDocuments(\n    docs: Document[],\n    embeddings: EmbeddingsInterface,\n    dbConfig?: {\n      docstore?: SynchronousInMemoryDocstore;\n    }\n  ): Promise<USearch> {\n    const args: USearchArgs = {\n      docstore: dbConfig?.docstore,\n    };\n    const instance = new this(embeddings, args);\n    await instance.addDocuments(docs);\n    return instance;\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAuBA,IAAa,UAAb,cAA6BA,kDAAoB;CAC/C;CAEA;CAEA;CAEA;CAEA,mBAA2B;AACzB,SAAO;CACR;CAED,YAAYC,YAAiCC,MAAmB;EAC9D,MAAM,YAAY,KAAK;EACvB,KAAK,OAAO;EACZ,KAAK,SAAS,KAAK;EACnB,KAAK,WAAW,KAAK,WAAW,CAAE;EAClC,KAAK,aAAa;EAClB,KAAK,WAAW,MAAM,YAAY,mDAAI;CACvC;;;;;;;CAQD,MAAM,aAAaC,WAAuB;EACxC,MAAM,QAAQ,UAAU,IAAI,CAAC,EAAE,aAAa,KAAK,YAAY;AAC7D,SAAO,KAAK,WACV,MAAM,KAAK,WAAW,eAAe,MAAM,EAC3C,UACD;CACF;CAED,IAAW,QAAe;AACxB,MAAI,CAAC,KAAK,OACR,OAAM,IAAI,MACR;AAGJ,SAAO,KAAK;CACb;CAED,IAAY,MAAMC,OAAc;EAC9B,KAAK,SAAS;CACf;;;;;;;;CASD,MAAM,WAAWC,SAAqBF,WAAuB;AAC3D,MAAI,QAAQ,WAAW,EACrB,QAAO,CAAE;AAEX,MAAI,QAAQ,WAAW,UAAU,OAC/B,OAAM,IAAI,MAAM,CAAC,+CAA+C,CAAC;EAEnE,MAAM,KAAK,QAAQ,GAAG;AACtB,MAAI,CAAC,KAAK,QACR,KAAK,SAAS,IAAIG,cAAM,IAAIC,mBAAW,MAAMC,mBAAW,KAAK;EAE/D,MAAM,IAAI,KAAK,MAAM,YAAY;AACjC,MAAI,OAAO,EACT,OAAM,IAAI,MACR,CAAC,+DAA+D,EAAE,EAAE,CAAC,CAAC;EAI1E,MAAM,eAAe,KAAK,MAAM,MAAM;EACtC,MAAM,cAAc,CAAE;AACtB,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,GAAG;GAC1C,MAAM,aAAa,KAAK,IAAI;GAC5B,YAAY,KAAK,WAAW;GAC5B,MAAM,KAAK,OAAO,aAAa,GAAG;GAClC,KAAK,MAAM,IAAI,OAAO,GAAG,EAAE,IAAI,aAAa,QAAQ,IAAI;GACxD,KAAK,SAAS,MAAM;GACpB,KAAK,SAAS,IAAI,GAAG,aAAa,UAAU,GAAI,EAAC;EAClD;AACD,SAAO;CACR;;;;;;;;;CAUD,MAAM,gCAAgCC,OAAiBC,GAAW;EAChE,MAAM,IAAI,KAAK,MAAM,YAAY;AACjC,MAAI,MAAM,WAAW,EACnB,OAAM,IAAI,MACR,CAAC,oEAAoE,EAAE,EAAE,CAAC,CAAC;AAG/E,MAAI,IAAI,KAAK,MAAM,MAAM,EAAE;GACzB,MAAM,QAAQ,KAAK,MAAM,MAAM;GAC/B,QAAQ,KACN,CAAC,GAAG,EAAE,EAAE,uDAAuD,EAAE,MAAM,gBAAgB,EAAE,OAAO,CACjG;GAED,IAAI,OAAO,MAAM;EAClB;EACD,MAAM,SAAS,KAAK,MAAM,OAAO,IAAI,aAAa,QAAQ,EAAE;EAE5D,MAAMC,cAAoC,CAAE;AAC5C,OACE,IAAI,IAAI,GACR,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,UAAU,QAC/C,KAAK,GACL;GACA,MAAMC,SAAO,KAAK,SAAS,OAAO,OAAO,KAAK,GAAG;GACjD,YAAY,KAAK,CAAC,KAAK,SAAS,OAAOA,OAAK,EAAE,OAAO,UAAU,EAAG,EAAC;EACpE;AAED,SAAO;CACR;;;;;;CAOD,MAAM,KAAKC,WAAmB;EAC5B,MAAM,KAAK,MAAM,OAAO;EACxB,MAAM,OAAO,MAAM,OAAO;EAC1B,MAAM,GAAG,MAAM,WAAW,EAAE,WAAW,KAAM,EAAC;EAC9C,MAAM,QAAQ,IAAI,CAChB,KAAK,MAAM,KAAK,KAAK,KAAK,WAAW,gBAAgB,CAAC,EACtD,MAAM,GAAG,UACP,KAAK,KAAK,WAAW,gBAAgB,EACrC,KAAK,UAAU,CACb,MAAM,KAAK,KAAK,SAAS,MAAM,SAAS,CAAC,EACzC,KAAK,QACN,EAAC,CACH,AACF,EAAC;CACH;;;;;;;;;;;CAYD,aAAa,UACXC,OACAC,WACAd,YACAe,UAGkB;EAClB,MAAMC,OAAmB,CAAE;AAC3B,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;GACxC,MAAM,WAAW,MAAM,QAAQ,UAAU,GAAG,UAAU,KAAK;GAC3D,MAAM,SAAS,IAAIC,oCAAS;IAC1B,aAAa,MAAM;IACnB;GACD;GACD,KAAK,KAAK,OAAO;EAClB;AACD,SAAO,KAAK,cAAc,MAAM,YAAY,SAAS;CACtD;;;;;;;;;;CAWD,aAAa,cACXD,MACAhB,YACAe,UAGkB;EAClB,MAAMd,OAAoB,EACxB,UAAU,UAAU,SACrB;EACD,MAAM,WAAW,IAAI,KAAK,YAAY;EACtC,MAAM,SAAS,aAAa,KAAK;AACjC,SAAO;CACR;AACF"}