@mastra/fastembed 1.3.4 → 1.3.5-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import fsp from "fs/promises";
2
2
  import os from "os";
3
3
  import path from "path";
4
- import { AddedToken, Tokenizer } from "@anush008/tokenizers";
5
4
  import fs from "fs";
6
5
  import { Readable } from "stream";
7
6
  import { pipeline } from "stream/promises";
8
- import * as ort from "onnxruntime-node";
7
+ import { AddedToken, Tokenizer } from "@anush008/tokenizers";
9
8
  import { downloadFile } from "@huggingface/hub";
9
+ import * as ort from "onnxruntime-node";
10
10
  //#region ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/zod/4.6.7/4c9f15c99caaca8b83ba8ab68f247a75121c86fb7e498876ed36daccd0f3d3ce/node_modules/zod/v4/core/util.js
11
11
  function getEnumValues(entries) {
12
12
  const numericValues = Object.values(entries).filter((v) => typeof v === "number");
@@ -18387,12 +18387,19 @@ function normalize(v) {
18387
18387
  const epsilon = 1e-12;
18388
18388
  return v.map((val) => val / Math.max(norm, epsilon));
18389
18389
  }
18390
- function getEmbeddings(data, dimensions) {
18391
- const [x, _y, z] = dimensions;
18392
- return new Array(x).fill(void 0).map((_, index) => {
18393
- const startIndex = index * _y * z;
18394
- const endIndex = startIndex + z;
18395
- return data.slice(startIndex, endIndex);
18390
+ function getEmbeddings(data, dimensions, masks) {
18391
+ const [batchSize, sequenceLength, hiddenSize] = dimensions;
18392
+ return Array.from({ length: batchSize }, (_, batchIndex) => {
18393
+ const start = batchIndex * sequenceLength * hiddenSize;
18394
+ if (!masks) return data.slice(start, start + hiddenSize);
18395
+ const embedding = new Array(hiddenSize).fill(0);
18396
+ let tokenCount = 0;
18397
+ for (let tokenIndex = 0; tokenIndex < sequenceLength; tokenIndex++) {
18398
+ if (masks[batchIndex][tokenIndex] === 0n) continue;
18399
+ tokenCount++;
18400
+ for (let dimension = 0; dimension < hiddenSize; dimension++) embedding[dimension] = embedding[dimension] + data[start + tokenIndex * hiddenSize + dimension];
18401
+ }
18402
+ return embedding.map((value) => value / Math.max(tokenCount, 1));
18396
18403
  });
18397
18404
  }
18398
18405
  var Embedding = class {};
@@ -18409,7 +18416,7 @@ function loadTokenizerFromDir(modelDir, maxLength) {
18409
18416
  const tokenizerFilePath = path.join(modelDir.toString(), "tokenizer_config.json");
18410
18417
  if (!fs.existsSync(tokenizerFilePath)) throw new Error(`Tokenizer config file not found at ${tokenizerFilePath}`);
18411
18418
  const tokenizerConfig = JSON.parse(fs.readFileSync(tokenizerFilePath, "utf-8"));
18412
- maxLength = Math.min(maxLength, tokenizerConfig["model_max_length"]);
18419
+ maxLength = Math.min(maxLength, tokenizerConfig["model_max_length"] ?? maxLength);
18413
18420
  const tokensMapPath = path.join(modelDir.toString(), "special_tokens_map.json");
18414
18421
  if (!fs.existsSync(tokensMapPath)) throw new Error(`Tokens map file not found at ${tokensMapPath}`);
18415
18422
  const tokensMap = JSON.parse(fs.readFileSync(tokensMapPath, "utf-8"));
@@ -18544,7 +18551,7 @@ var FlagEmbedding = class FlagEmbedding extends Embedding {
18544
18551
  };
18545
18552
  if (this.model === "fast-multilingual-e5-large") delete inputs.token_type_ids;
18546
18553
  const lastHiddenState = (await this.session.run(inputs)).last_hidden_state;
18547
- yield getEmbeddings(lastHiddenState.data, lastHiddenState.dims).map(normalize);
18554
+ yield getEmbeddings(lastHiddenState.data, lastHiddenState.dims, this.model === "fast-all-MiniLM-L6-v2" || this.model === "fast-multilingual-e5-large" ? maskArray : void 0).map(normalize);
18548
18555
  }
18549
18556
  }
18550
18557
  passageEmbed(texts, batchSize = 256) {
@@ -18619,29 +18626,46 @@ var SparseTextEmbedding = class SparseTextEmbedding extends SparseEmbedding {
18619
18626
  return { tokenizer: loadTokenizerFromDir(modelDir, maxLength) };
18620
18627
  }
18621
18628
  static async retrieveModel(model, cacheDir, _showDownloadProgress = true) {
18622
- if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { mode: 493 });
18629
+ if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, {
18630
+ recursive: true,
18631
+ mode: 493
18632
+ });
18623
18633
  const modelDir = path.join(cacheDir.toString(), model.replace("/", "_"));
18624
18634
  if (fs.existsSync(modelDir)) return modelDir;
18625
- fs.mkdirSync(modelDir, { mode: 493 });
18626
- for (const fileName of [
18635
+ const filesToDownload = [
18627
18636
  "onnx/model.onnx",
18628
18637
  "tokenizer.json",
18629
18638
  "tokenizer_config.json",
18630
18639
  "config.json",
18631
18640
  "special_tokens_map.json"
18632
- ]) {
18633
- const outputPath = path.join(modelDir, fileName);
18634
- const outputDir = path.dirname(outputPath);
18635
- if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, {
18641
+ ];
18642
+ const tmpDir = fs.mkdtempSync(`${modelDir}.tmp-`);
18643
+ try {
18644
+ for (const fileName of filesToDownload) {
18645
+ const outputPath = path.join(tmpDir, fileName);
18646
+ fs.mkdirSync(path.dirname(outputPath), {
18647
+ recursive: true,
18648
+ mode: 493
18649
+ });
18650
+ const downloaded = await downloadFile({
18651
+ repo: model,
18652
+ path: fileName
18653
+ });
18654
+ if (!downloaded) throw new Error(`Model file not found in ${model}: ${fileName}`);
18655
+ await pipeline(Readable.fromWeb(downloaded.stream()), fs.createWriteStream(outputPath));
18656
+ }
18657
+ try {
18658
+ fs.renameSync(tmpDir, modelDir);
18659
+ } catch (error) {
18660
+ const code = error.code;
18661
+ if ((code === "EEXIST" || code === "ENOTEMPTY") && fs.existsSync(modelDir)) return modelDir;
18662
+ throw error;
18663
+ }
18664
+ } finally {
18665
+ fs.rmSync(tmpDir, {
18636
18666
  recursive: true,
18637
- mode: 493
18638
- });
18639
- const downloaded = await downloadFile({
18640
- repo: model,
18641
- path: fileName
18667
+ force: true
18642
18668
  });
18643
- if (!downloaded) throw new Error(`Model file not found in ${model}: ${fileName}`);
18644
- await pipeline(Readable.fromWeb(downloaded.stream()), fs.createWriteStream(outputPath));
18645
18669
  }
18646
18670
  return modelDir;
18647
18671
  }