From 1c91d369c3f50894c1b5d84426aee74bb08be94d Mon Sep 17 00:00:00 2001 From: Timothy Carambat Date: Tue, 10 Feb 2026 08:28:34 -0800 Subject: [PATCH] set embedder output dimensions for LocalAI and Gemini (gemini-embedding-001) (#4980) --- .../GeminiOptions/index.jsx | 123 ++++++++++++------ .../LocalAiOptions/index.jsx | 104 ++++++++++++--- server/models/systemSettings.js | 2 + server/utils/EmbeddingEngines/gemini/index.js | 16 ++- .../utils/EmbeddingEngines/localAi/index.js | 26 +++- server/utils/helpers/updateENV.js | 4 + 6 files changed, 221 insertions(+), 54 deletions(-) diff --git a/frontend/src/components/EmbeddingSelection/GeminiOptions/index.jsx b/frontend/src/components/EmbeddingSelection/GeminiOptions/index.jsx index 85183a49..c19f3f2d 100644 --- a/frontend/src/components/EmbeddingSelection/GeminiOptions/index.jsx +++ b/frontend/src/components/EmbeddingSelection/GeminiOptions/index.jsx @@ -1,3 +1,6 @@ +import { Info } from "@phosphor-icons/react"; +import { Tooltip } from "react-tooltip"; + const DEFAULT_MODELS = [ { id: "gemini-embedding-001", @@ -7,47 +10,93 @@ const DEFAULT_MODELS = [ export default function GeminiOptions({ settings }) { return ( -
-
-
-
+
+ - - + Maximum length of text chunks, in characters, for embedding.
@@ -59,23 +109,47 @@ export default function LocalAiOptions({ settings }) { autoComplete="off" />
+
-
-
diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js index 690c173c..2822e9ea 100644 --- a/server/models/systemSettings.js +++ b/server/models/systemSettings.js @@ -233,6 +233,8 @@ const SystemSettings = { embeddingEngine === "native" ? NativeEmbedder._getEmbeddingModel() : process.env.EMBEDDING_MODEL_PREF, + EmbeddingOutputDimensions: + process.env.EMBEDDING_OUTPUT_DIMENSIONS || null, EmbeddingModelMaxChunkLength: process.env.EMBEDDING_MODEL_MAX_CHUNK_LENGTH, OllamaEmbeddingBatchSize: process.env.OLLAMA_EMBEDDING_BATCH_SIZE || 1, diff --git a/server/utils/EmbeddingEngines/gemini/index.js b/server/utils/EmbeddingEngines/gemini/index.js index f04a49ff..410742e8 100644 --- a/server/utils/EmbeddingEngines/gemini/index.js +++ b/server/utils/EmbeddingEngines/gemini/index.js @@ -23,7 +23,10 @@ class GeminiEmbedder { // https://ai.google.dev/gemini-api/docs/models/gemini#text-embedding-and-embedding this.embeddingMaxChunkLength = MODEL_MAP[this.model] || 2_048; this.log( - `Initialized with ${this.model} - Max Size: ${this.embeddingMaxChunkLength}` + `Initialized with ${this.model} - Max Size: ${this.embeddingMaxChunkLength}` + + (this.outputDimensions + ? ` - Output Dimensions: ${this.outputDimensions}` + : " Assuming default output dimensions") ); } @@ -31,6 +34,16 @@ class GeminiEmbedder { console.log(`\x1b[36m[${this.className}]\x1b[0m ${text}`, ...args); } + get outputDimensions() { + if ( + process.env.EMBEDDING_OUTPUT_DIMENSIONS && + !isNaN(process.env.EMBEDDING_OUTPUT_DIMENSIONS) && + process.env.EMBEDDING_OUTPUT_DIMENSIONS > 0 + ) + return parseInt(process.env.EMBEDDING_OUTPUT_DIMENSIONS); + return null; + } + /** * Embeds a single text input * @param {string|string[]} textInput - The text to embed @@ -62,6 +75,7 @@ class GeminiEmbedder { .create({ model: this.model, input: chunk, + dimensions: this.outputDimensions, }) .then((result) => { resolve({ data: result?.data, error: null }); diff --git a/server/utils/EmbeddingEngines/localAi/index.js b/server/utils/EmbeddingEngines/localAi/index.js index 363ad182..4c44959b 100644 --- a/server/utils/EmbeddingEngines/localAi/index.js +++ b/server/utils/EmbeddingEngines/localAi/index.js @@ -7,7 +7,9 @@ class LocalAiEmbedder { if (!process.env.EMBEDDING_MODEL_PREF) throw new Error("No embedding model was set."); + this.className = "LocalAiEmbedder"; const { OpenAI: OpenAIApi } = require("openai"); + this.model = process.env.EMBEDDING_MODEL_PREF; this.openai = new OpenAIApi({ baseURL: process.env.EMBEDDING_BASE_PATH, apiKey: process.env.LOCAL_AI_API_KEY ?? null, @@ -16,6 +18,27 @@ class LocalAiEmbedder { // Limit of how many strings we can process in a single pass to stay with resource or network limits this.maxConcurrentChunks = 50; this.embeddingMaxChunkLength = maximumChunkLength(); + + this.log( + `Initialized with ${this.model} - Max Size: ${this.embeddingMaxChunkLength}` + + (this.outputDimensions + ? ` - Output Dimensions: ${this.outputDimensions}` + : " Assuming default output dimensions") + ); + } + + log(text, ...args) { + console.log(`\x1b[36m[${this.className}]\x1b[0m ${text}`, ...args); + } + + get outputDimensions() { + if ( + process.env.EMBEDDING_OUTPUT_DIMENSIONS && + !isNaN(process.env.EMBEDDING_OUTPUT_DIMENSIONS) && + process.env.EMBEDDING_OUTPUT_DIMENSIONS > 0 + ) + return parseInt(process.env.EMBEDDING_OUTPUT_DIMENSIONS); + return null; } async embedTextInput(textInput) { @@ -32,8 +55,9 @@ class LocalAiEmbedder { new Promise((resolve) => { this.openai.embeddings .create({ - model: process.env.EMBEDDING_MODEL_PREF, + model: this.model, input: chunk, + dimensions: this.outputDimensions, }) .then((result) => { resolve({ data: result?.data, error: null }); diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js index dff15154..b1b65d6a 100644 --- a/server/utils/helpers/updateENV.js +++ b/server/utils/helpers/updateENV.js @@ -307,6 +307,10 @@ const KEY_MAPPING = { envKey: "EMBEDDING_MODEL_MAX_CHUNK_LENGTH", checks: [nonZero], }, + EmbeddingOutputDimensions: { + envKey: "EMBEDDING_OUTPUT_DIMENSIONS", + checks: [], + }, OllamaEmbeddingBatchSize: { envKey: "OLLAMA_EMBEDDING_BATCH_SIZE", checks: [nonZero],