mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2025-04-23 13:08:11 +00:00
Patch bad models endpoint path in LM Studio embedding engine (#2628)
* patch bad models endpoint path in lm studio embedding engine * convert to OpenAI wrapper compatibility * add URL force parser/validation for LMStudio connections * remove comment --------- Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
parent
b701660f88
commit
27b07d46b3
5 changed files with 51 additions and 23 deletions
server/utils
AiProviders/lmStudio
EmbeddingEngines/lmstudio
agents/aibitat/providers
helpers
|
@ -11,7 +11,7 @@ class LMStudioLLM {
|
||||||
|
|
||||||
const { OpenAI: OpenAIApi } = require("openai");
|
const { OpenAI: OpenAIApi } = require("openai");
|
||||||
this.lmstudio = new OpenAIApi({
|
this.lmstudio = new OpenAIApi({
|
||||||
baseURL: process.env.LMSTUDIO_BASE_PATH?.replace(/\/+$/, ""), // here is the URL to your LMStudio instance
|
baseURL: parseLMStudioBasePath(process.env.LMSTUDIO_BASE_PATH), // here is the URL to your LMStudio instance
|
||||||
apiKey: null,
|
apiKey: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -173,6 +173,23 @@ class LMStudioLLM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the base path for the LMStudio API. Since the base path must end in /v1 and cannot have a trailing slash,
|
||||||
|
* and the user can possibly set it to anything and likely incorrectly due to pasting behaviors, we need to ensure it is in the correct format.
|
||||||
|
* @param {string} basePath
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function parseLMStudioBasePath(providedBasePath = "") {
|
||||||
|
try {
|
||||||
|
const baseURL = new URL(providedBasePath);
|
||||||
|
const basePath = `${baseURL.origin}/v1`;
|
||||||
|
return basePath;
|
||||||
|
} catch (e) {
|
||||||
|
return providedBasePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
LMStudioLLM,
|
LMStudioLLM,
|
||||||
|
parseLMStudioBasePath,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
const { parseLMStudioBasePath } = require("../../AiProviders/lmStudio");
|
||||||
const { maximumChunkLength } = require("../../helpers");
|
const { maximumChunkLength } = require("../../helpers");
|
||||||
|
|
||||||
class LMStudioEmbedder {
|
class LMStudioEmbedder {
|
||||||
|
@ -6,10 +7,14 @@ class LMStudioEmbedder {
|
||||||
throw new Error("No embedding base path was set.");
|
throw new Error("No embedding base path was set.");
|
||||||
if (!process.env.EMBEDDING_MODEL_PREF)
|
if (!process.env.EMBEDDING_MODEL_PREF)
|
||||||
throw new Error("No embedding model was set.");
|
throw new Error("No embedding model was set.");
|
||||||
this.basePath = `${process.env.EMBEDDING_BASE_PATH}/embeddings`;
|
|
||||||
|
const { OpenAI: OpenAIApi } = require("openai");
|
||||||
|
this.lmstudio = new OpenAIApi({
|
||||||
|
baseURL: parseLMStudioBasePath(process.env.EMBEDDING_BASE_PATH),
|
||||||
|
apiKey: null,
|
||||||
|
});
|
||||||
this.model = process.env.EMBEDDING_MODEL_PREF;
|
this.model = process.env.EMBEDDING_MODEL_PREF;
|
||||||
|
|
||||||
// Limit of how many strings we can process in a single pass to stay with resource or network limits
|
|
||||||
// Limit of how many strings we can process in a single pass to stay with resource or network limits
|
// Limit of how many strings we can process in a single pass to stay with resource or network limits
|
||||||
this.maxConcurrentChunks = 1;
|
this.maxConcurrentChunks = 1;
|
||||||
this.embeddingMaxChunkLength = maximumChunkLength();
|
this.embeddingMaxChunkLength = maximumChunkLength();
|
||||||
|
@ -20,10 +25,9 @@ class LMStudioEmbedder {
|
||||||
}
|
}
|
||||||
|
|
||||||
async #isAlive() {
|
async #isAlive() {
|
||||||
return await fetch(`${this.basePath}/models`, {
|
return await this.lmstudio.models
|
||||||
method: "HEAD",
|
.list()
|
||||||
})
|
.then((res) => res?.data?.length > 0)
|
||||||
.then((res) => res.ok)
|
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
this.log(e.message);
|
this.log(e.message);
|
||||||
return false;
|
return false;
|
||||||
|
@ -55,29 +59,29 @@ class LMStudioEmbedder {
|
||||||
for (const chunk of textChunks) {
|
for (const chunk of textChunks) {
|
||||||
if (hasError) break; // If an error occurred don't continue and exit early.
|
if (hasError) break; // If an error occurred don't continue and exit early.
|
||||||
results.push(
|
results.push(
|
||||||
await fetch(this.basePath, {
|
await this.lmstudio.embeddings
|
||||||
method: "POST",
|
.create({
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
model: this.model,
|
model: this.model,
|
||||||
input: chunk,
|
input: chunk,
|
||||||
}),
|
})
|
||||||
})
|
.then((result) => {
|
||||||
.then((res) => res.json())
|
const embedding = result.data?.[0]?.embedding;
|
||||||
.then((json) => {
|
|
||||||
const embedding = json.data[0].embedding;
|
|
||||||
if (!Array.isArray(embedding) || !embedding.length)
|
if (!Array.isArray(embedding) || !embedding.length)
|
||||||
throw {
|
throw {
|
||||||
type: "EMPTY_ARR",
|
type: "EMPTY_ARR",
|
||||||
message: "The embedding was empty from LMStudio",
|
message: "The embedding was empty from LMStudio",
|
||||||
};
|
};
|
||||||
|
console.log(`Embedding length: ${embedding.length}`);
|
||||||
return { data: embedding, error: null };
|
return { data: embedding, error: null };
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((e) => {
|
||||||
|
e.type =
|
||||||
|
e?.response?.data?.error?.code ||
|
||||||
|
e?.response?.status ||
|
||||||
|
"failed_to_embed";
|
||||||
|
e.message = e?.response?.data?.error?.message || e.message;
|
||||||
hasError = true;
|
hasError = true;
|
||||||
return { data: [], error };
|
return { data: [], error: e };
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ const { ChatBedrockConverse } = require("@langchain/aws");
|
||||||
const { ChatOllama } = require("@langchain/community/chat_models/ollama");
|
const { ChatOllama } = require("@langchain/community/chat_models/ollama");
|
||||||
const { toValidNumber } = require("../../../http");
|
const { toValidNumber } = require("../../../http");
|
||||||
const { getLLMProviderClass } = require("../../../helpers");
|
const { getLLMProviderClass } = require("../../../helpers");
|
||||||
|
const { parseLMStudioBasePath } = require("../../../AiProviders/lmStudio");
|
||||||
|
|
||||||
const DEFAULT_WORKSPACE_PROMPT =
|
const DEFAULT_WORKSPACE_PROMPT =
|
||||||
"You are a helpful ai assistant who can assist the user and use tools available to help answer the users prompts and questions.";
|
"You are a helpful ai assistant who can assist the user and use tools available to help answer the users prompts and questions.";
|
||||||
|
@ -169,7 +170,7 @@ class Provider {
|
||||||
case "lmstudio":
|
case "lmstudio":
|
||||||
return new ChatOpenAI({
|
return new ChatOpenAI({
|
||||||
configuration: {
|
configuration: {
|
||||||
baseURL: process.env.LMSTUDIO_BASE_PATH?.replace(/\/+$/, ""),
|
baseURL: parseLMStudioBasePath(process.env.LMSTUDIO_BASE_PATH),
|
||||||
},
|
},
|
||||||
apiKey: "not-used", // Needs to be specified or else will assume OpenAI
|
apiKey: "not-used", // Needs to be specified or else will assume OpenAI
|
||||||
...config,
|
...config,
|
||||||
|
|
|
@ -2,6 +2,9 @@ const OpenAI = require("openai");
|
||||||
const Provider = require("./ai-provider.js");
|
const Provider = require("./ai-provider.js");
|
||||||
const InheritMultiple = require("./helpers/classes.js");
|
const InheritMultiple = require("./helpers/classes.js");
|
||||||
const UnTooled = require("./helpers/untooled.js");
|
const UnTooled = require("./helpers/untooled.js");
|
||||||
|
const {
|
||||||
|
parseLMStudioBasePath,
|
||||||
|
} = require("../../../AiProviders/lmStudio/index.js");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The agent provider for the LMStudio.
|
* The agent provider for the LMStudio.
|
||||||
|
@ -18,7 +21,7 @@ class LMStudioProvider extends InheritMultiple([Provider, UnTooled]) {
|
||||||
const model =
|
const model =
|
||||||
config?.model || process.env.LMSTUDIO_MODEL_PREF || "Loaded from Chat UI";
|
config?.model || process.env.LMSTUDIO_MODEL_PREF || "Loaded from Chat UI";
|
||||||
const client = new OpenAI({
|
const client = new OpenAI({
|
||||||
baseURL: process.env.LMSTUDIO_BASE_PATH?.replace(/\/+$/, ""), // here is the URL to your LMStudio instance
|
baseURL: parseLMStudioBasePath(process.env.LMSTUDIO_BASE_PATH),
|
||||||
apiKey: null,
|
apiKey: null,
|
||||||
maxRetries: 3,
|
maxRetries: 3,
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,6 +5,7 @@ const { togetherAiModels } = require("../AiProviders/togetherAi");
|
||||||
const { fireworksAiModels } = require("../AiProviders/fireworksAi");
|
const { fireworksAiModels } = require("../AiProviders/fireworksAi");
|
||||||
const { ElevenLabsTTS } = require("../TextToSpeech/elevenLabs");
|
const { ElevenLabsTTS } = require("../TextToSpeech/elevenLabs");
|
||||||
const { fetchNovitaModels } = require("../AiProviders/novita");
|
const { fetchNovitaModels } = require("../AiProviders/novita");
|
||||||
|
const { parseLMStudioBasePath } = require("../AiProviders/lmStudio");
|
||||||
const SUPPORT_CUSTOM_MODELS = [
|
const SUPPORT_CUSTOM_MODELS = [
|
||||||
"openai",
|
"openai",
|
||||||
"localai",
|
"localai",
|
||||||
|
@ -235,7 +236,9 @@ async function getLMStudioModels(basePath = null) {
|
||||||
try {
|
try {
|
||||||
const { OpenAI: OpenAIApi } = require("openai");
|
const { OpenAI: OpenAIApi } = require("openai");
|
||||||
const openai = new OpenAIApi({
|
const openai = new OpenAIApi({
|
||||||
baseURL: basePath || process.env.LMSTUDIO_BASE_PATH,
|
baseURL: parseLMStudioBasePath(
|
||||||
|
basePath || process.env.LMSTUDIO_BASE_PATH
|
||||||
|
),
|
||||||
apiKey: null,
|
apiKey: null,
|
||||||
});
|
});
|
||||||
const models = await openai.models
|
const models = await openai.models
|
||||||
|
|
Loading…
Add table
Reference in a new issue