$rT%uRbT$kkdRXe35
zbUj1`=Xg!6IB^OkB^2<-&7&kVny4W*X;+!jcYU)=crDn=F6nPI(EHqI2)3^fO)?`F
znYh1qT7BA2Y31PLd~2g}Wg3=8i^vZ?CVujk2tKB(bMEScoZ-h(`S9rUts%Eg1x;^l
zqnO8<+6f0Pn^;{JW&TRn^EhZXD_%YS=&Ic}-N`Ud>J?9$fHb}g-94%@;#h;_Cx)+^
zm&fWhWRw-+`2B2-3Z_h7N-K@*8VI8d*07y>t9~Cfg1UC~nvt=KefhGOhkykkrx
z5<$gl4%{{1&%57c5Qv$XoY%TcILb6UdoL+VK0U}ckiTqHx51ZU
zmwjXW&11_L&eEgCFq@TP2dU4yzzlh^iUi9p_NpSM8p1Mj^7zmjK?2}Op8*u3nr2;h
Kf#<=y@BRlu0mfYb
literal 0
HcmV?d00001
diff --git a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
index bd6ae511..1efa818d 100644
--- a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
+++ b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
@@ -12,6 +12,7 @@ import OllamaLogo from "@/media/llmprovider/ollama.png";
import LMStudioLogo from "@/media/llmprovider/lmstudio.png";
import LocalAiLogo from "@/media/llmprovider/localai.png";
import TogetherAILogo from "@/media/llmprovider/togetherai.png";
+import MistralLogo from "@/media/llmprovider/mistral.jpeg";
import PreLoader from "@/components/Preloader";
import OpenAiOptions from "@/components/LLMSelection/OpenAiOptions";
import AzureAiOptions from "@/components/LLMSelection/AzureAiOptions";
@@ -21,9 +22,10 @@ import LocalAiOptions from "@/components/LLMSelection/LocalAiOptions";
import NativeLLMOptions from "@/components/LLMSelection/NativeLLMOptions";
import GeminiLLMOptions from "@/components/LLMSelection/GeminiLLMOptions";
import OllamaLLMOptions from "@/components/LLMSelection/OllamaLLMOptions";
+import TogetherAiOptions from "@/components/LLMSelection/TogetherAiOptions";
+import MistralOptions from "@/components/LLMSelection/MistralOptions";
import LLMItem from "@/components/LLMSelection/LLMItem";
import { MagnifyingGlass } from "@phosphor-icons/react";
-import TogetherAiOptions from "@/components/LLMSelection/TogetherAiOptions";
export default function GeneralLLMPreference() {
const [saving, setSaving] = useState(false);
@@ -134,6 +136,13 @@ export default function GeneralLLMPreference() {
options: ,
description: "Run open source models from Together AI.",
},
+ {
+ name: "Mistral",
+ value: "mistral",
+ logo: MistralLogo,
+ options: ,
+ description: "Run open source models from Mistral AI.",
+ },
{
name: "Native",
value: "native",
diff --git a/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx b/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx
index 281f1e8c..3b004638 100644
--- a/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx
+++ b/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx
@@ -9,6 +9,7 @@ import OllamaLogo from "@/media/llmprovider/ollama.png";
import TogetherAILogo from "@/media/llmprovider/togetherai.png";
import LMStudioLogo from "@/media/llmprovider/lmstudio.png";
import LocalAiLogo from "@/media/llmprovider/localai.png";
+import MistralLogo from "@/media/llmprovider/mistral.jpeg";
import ChromaLogo from "@/media/vectordbs/chroma.png";
import PineconeLogo from "@/media/vectordbs/pinecone.png";
import LanceDbLogo from "@/media/vectordbs/lancedb.png";
@@ -91,6 +92,13 @@ const LLM_SELECTION_PRIVACY = {
],
logo: TogetherAILogo,
},
+ mistral: {
+ name: "Mistral",
+ description: [
+ "Your prompts and document text used in response creation are visible to Mistral",
+ ],
+ logo: MistralLogo,
+ },
};
const VECTOR_DB_PRIVACY = {
diff --git a/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx b/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx
index dc060594..9e8ab84a 100644
--- a/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx
+++ b/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx
@@ -9,6 +9,7 @@ import LMStudioLogo from "@/media/llmprovider/lmstudio.png";
import LocalAiLogo from "@/media/llmprovider/localai.png";
import TogetherAILogo from "@/media/llmprovider/togetherai.png";
import AnythingLLMIcon from "@/media/logo/anything-llm-icon.png";
+import MistralLogo from "@/media/llmprovider/mistral.jpeg";
import OpenAiOptions from "@/components/LLMSelection/OpenAiOptions";
import AzureAiOptions from "@/components/LLMSelection/AzureAiOptions";
import AnthropicAiOptions from "@/components/LLMSelection/AnthropicAiOptions";
@@ -17,6 +18,7 @@ import LocalAiOptions from "@/components/LLMSelection/LocalAiOptions";
import NativeLLMOptions from "@/components/LLMSelection/NativeLLMOptions";
import GeminiLLMOptions from "@/components/LLMSelection/GeminiLLMOptions";
import OllamaLLMOptions from "@/components/LLMSelection/OllamaLLMOptions";
+import MistralOptions from "@/components/LLMSelection/MistralOptions";
import LLMItem from "@/components/LLMSelection/LLMItem";
import System from "@/models/system";
import paths from "@/utils/paths";
@@ -109,6 +111,13 @@ export default function LLMPreference({
options: ,
description: "Run open source models from Together AI.",
},
+ {
+ name: "Mistral",
+ value: "mistral",
+ logo: MistralLogo,
+ options: ,
+ description: "Run open source models from Mistral AI.",
+ },
{
name: "Native",
value: "native",
diff --git a/server/.env.example b/server/.env.example
index d060e0ab..26c51927 100644
--- a/server/.env.example
+++ b/server/.env.example
@@ -41,6 +41,10 @@ JWT_SECRET="my-random-string-for-seeding" # Please generate random string at lea
# TOGETHER_AI_API_KEY='my-together-ai-key'
# TOGETHER_AI_MODEL_PREF='mistralai/Mixtral-8x7B-Instruct-v0.1'
+# LLM_PROVIDER='mistral'
+# MISTRAL_API_KEY='example-mistral-ai-api-key'
+# MISTRAL_MODEL_PREF='mistral-tiny'
+
###########################################
######## Embedding API SElECTION ##########
###########################################
diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js
index cd008d42..53d42f2e 100644
--- a/server/models/systemSettings.js
+++ b/server/models/systemSettings.js
@@ -159,6 +159,18 @@ const SystemSettings = {
AzureOpenAiEmbeddingModelPref: process.env.EMBEDDING_MODEL_PREF,
}
: {}),
+ ...(llmProvider === "mistral"
+ ? {
+ MistralApiKey: !!process.env.MISTRAL_API_KEY,
+ MistralModelPref: process.env.MISTRAL_MODEL_PREF,
+
+ // For embedding credentials when mistral is selected.
+ OpenAiKey: !!process.env.OPEN_AI_KEY,
+ AzureOpenAiEndpoint: process.env.AZURE_OPENAI_ENDPOINT,
+ AzureOpenAiKey: !!process.env.AZURE_OPENAI_KEY,
+ AzureOpenAiEmbeddingModelPref: process.env.EMBEDDING_MODEL_PREF,
+ }
+ : {}),
...(llmProvider === "native"
? {
NativeLLMModelPref: process.env.NATIVE_LLM_MODEL_PREF,
diff --git a/server/utils/AiProviders/anthropic/index.js b/server/utils/AiProviders/anthropic/index.js
index 17f2abc4..56d3a80f 100644
--- a/server/utils/AiProviders/anthropic/index.js
+++ b/server/utils/AiProviders/anthropic/index.js
@@ -26,6 +26,7 @@ class AnthropicLLM {
);
this.embedder = embedder;
this.answerKey = v4().split("-")[0];
+ this.defaultTemp = 0.7;
}
streamingEnabled() {
diff --git a/server/utils/AiProviders/azureOpenAi/index.js b/server/utils/AiProviders/azureOpenAi/index.js
index f59fc51f..639ac102 100644
--- a/server/utils/AiProviders/azureOpenAi/index.js
+++ b/server/utils/AiProviders/azureOpenAi/index.js
@@ -25,6 +25,7 @@ class AzureOpenAiLLM {
"No embedding provider defined for AzureOpenAiLLM - falling back to AzureOpenAiEmbedder for embedding!"
);
this.embedder = !embedder ? new AzureOpenAiEmbedder() : embedder;
+ this.defaultTemp = 0.7;
}
#appendContext(contextTexts = []) {
@@ -93,7 +94,7 @@ class AzureOpenAiLLM {
);
const textResponse = await this.openai
.getChatCompletions(this.model, messages, {
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
})
.then((res) => {
@@ -130,7 +131,7 @@ class AzureOpenAiLLM {
this.model,
messages,
{
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
}
);
diff --git a/server/utils/AiProviders/gemini/index.js b/server/utils/AiProviders/gemini/index.js
index 348c8f5e..63549fb8 100644
--- a/server/utils/AiProviders/gemini/index.js
+++ b/server/utils/AiProviders/gemini/index.js
@@ -22,6 +22,7 @@ class GeminiLLM {
"INVALID GEMINI LLM SETUP. No embedding engine has been set. Go to instance settings and set up an embedding interface to use Gemini as your LLM."
);
this.embedder = embedder;
+ this.defaultTemp = 0.7; // not used for Gemini
}
#appendContext(contextTexts = []) {
diff --git a/server/utils/AiProviders/lmStudio/index.js b/server/utils/AiProviders/lmStudio/index.js
index 61480803..08950a7b 100644
--- a/server/utils/AiProviders/lmStudio/index.js
+++ b/server/utils/AiProviders/lmStudio/index.js
@@ -25,6 +25,7 @@ class LMStudioLLM {
"INVALID LM STUDIO SETUP. No embedding engine has been set. Go to instance settings and set up an embedding interface to use LMStudio as your LLM."
);
this.embedder = embedder;
+ this.defaultTemp = 0.7;
}
#appendContext(contextTexts = []) {
@@ -85,7 +86,7 @@ class LMStudioLLM {
const textResponse = await this.lmstudio
.createChatCompletion({
model: this.model,
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
messages: await this.compressMessages(
{
@@ -122,7 +123,7 @@ class LMStudioLLM {
const streamRequest = await this.lmstudio.createChatCompletion(
{
model: this.model,
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
stream: true,
messages: await this.compressMessages(
diff --git a/server/utils/AiProviders/localAi/index.js b/server/utils/AiProviders/localAi/index.js
index 6623ac88..6d265cf8 100644
--- a/server/utils/AiProviders/localAi/index.js
+++ b/server/utils/AiProviders/localAi/index.js
@@ -27,6 +27,7 @@ class LocalAiLLM {
"INVALID LOCAL AI SETUP. No embedding engine has been set. Go to instance settings and set up an embedding interface to use LocalAI as your LLM."
);
this.embedder = embedder;
+ this.defaultTemp = 0.7;
}
#appendContext(contextTexts = []) {
@@ -85,7 +86,7 @@ class LocalAiLLM {
const textResponse = await this.openai
.createChatCompletion({
model: this.model,
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
messages: await this.compressMessages(
{
@@ -123,7 +124,7 @@ class LocalAiLLM {
{
model: this.model,
stream: true,
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
messages: await this.compressMessages(
{
diff --git a/server/utils/AiProviders/mistral/index.js b/server/utils/AiProviders/mistral/index.js
new file mode 100644
index 00000000..a25185c7
--- /dev/null
+++ b/server/utils/AiProviders/mistral/index.js
@@ -0,0 +1,184 @@
+const { chatPrompt } = require("../../chats");
+
+class MistralLLM {
+ constructor(embedder = null, modelPreference = null) {
+ const { Configuration, OpenAIApi } = require("openai");
+ if (!process.env.MISTRAL_API_KEY)
+ throw new Error("No Mistral API key was set.");
+
+ const config = new Configuration({
+ basePath: "https://api.mistral.ai/v1",
+ apiKey: process.env.MISTRAL_API_KEY,
+ });
+ this.openai = new OpenAIApi(config);
+ this.model =
+ modelPreference || process.env.MISTRAL_MODEL_PREF || "mistral-tiny";
+ this.limits = {
+ history: this.promptWindowLimit() * 0.15,
+ system: this.promptWindowLimit() * 0.15,
+ user: this.promptWindowLimit() * 0.7,
+ };
+
+ if (!embedder)
+ console.warn(
+ "No embedding provider defined for MistralLLM - falling back to OpenAiEmbedder for embedding!"
+ );
+ this.embedder = embedder;
+ this.defaultTemp = 0.0;
+ }
+
+ #appendContext(contextTexts = []) {
+ if (!contextTexts || !contextTexts.length) return "";
+ return (
+ "\nContext:\n" +
+ contextTexts
+ .map((text, i) => {
+ return `[CONTEXT ${i}]:\n${text}\n[END CONTEXT ${i}]\n\n`;
+ })
+ .join("")
+ );
+ }
+
+ streamingEnabled() {
+ return "streamChat" in this && "streamGetChatCompletion" in this;
+ }
+
+ promptWindowLimit() {
+ return 32000;
+ }
+
+ async isValidChatCompletionModel(modelName = "") {
+ return true;
+ }
+
+ constructPrompt({
+ systemPrompt = "",
+ contextTexts = [],
+ chatHistory = [],
+ userPrompt = "",
+ }) {
+ const prompt = {
+ role: "system",
+ content: `${systemPrompt}${this.#appendContext(contextTexts)}`,
+ };
+ return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
+ }
+
+ async isSafe(_ = "") {
+ return { safe: true, reasons: [] };
+ }
+
+ async sendChat(chatHistory = [], prompt, workspace = {}, rawHistory = []) {
+ if (!(await this.isValidChatCompletionModel(this.model)))
+ throw new Error(
+ `Mistral chat: ${this.model} is not valid for chat completion!`
+ );
+
+ const textResponse = await this.openai
+ .createChatCompletion({
+ model: this.model,
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
+ messages: await this.compressMessages(
+ {
+ systemPrompt: chatPrompt(workspace),
+ userPrompt: prompt,
+ chatHistory,
+ },
+ rawHistory
+ ),
+ })
+ .then((json) => {
+ const res = json.data;
+ if (!res.hasOwnProperty("choices"))
+ throw new Error("Mistral chat: No results!");
+ if (res.choices.length === 0)
+ throw new Error("Mistral chat: No results length!");
+ return res.choices[0].message.content;
+ })
+ .catch((error) => {
+ throw new Error(
+ `Mistral::createChatCompletion failed with: ${error.message}`
+ );
+ });
+
+ return textResponse;
+ }
+
+ async streamChat(chatHistory = [], prompt, workspace = {}, rawHistory = []) {
+ if (!(await this.isValidChatCompletionModel(this.model)))
+ throw new Error(
+ `Mistral chat: ${this.model} is not valid for chat completion!`
+ );
+
+ const streamRequest = await this.openai.createChatCompletion(
+ {
+ model: this.model,
+ stream: true,
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
+ messages: await this.compressMessages(
+ {
+ systemPrompt: chatPrompt(workspace),
+ userPrompt: prompt,
+ chatHistory,
+ },
+ rawHistory
+ ),
+ },
+ { responseType: "stream" }
+ );
+
+ return streamRequest;
+ }
+
+ async getChatCompletion(messages = null, { temperature = 0.7 }) {
+ if (!(await this.isValidChatCompletionModel(this.model)))
+ throw new Error(
+ `Mistral chat: ${this.model} is not valid for chat completion!`
+ );
+
+ const { data } = await this.openai.createChatCompletion({
+ model: this.model,
+ messages,
+ temperature,
+ });
+
+ if (!data.hasOwnProperty("choices")) return null;
+ return data.choices[0].message.content;
+ }
+
+ async streamGetChatCompletion(messages = null, { temperature = 0.7 }) {
+ if (!(await this.isValidChatCompletionModel(this.model)))
+ throw new Error(
+ `Mistral chat: ${this.model} is not valid for chat completion!`
+ );
+
+ const streamRequest = await this.openai.createChatCompletion(
+ {
+ model: this.model,
+ stream: true,
+ messages,
+ temperature,
+ },
+ { responseType: "stream" }
+ );
+ return streamRequest;
+ }
+
+ // Simple wrapper for dynamic embedder & normalize interface for all LLM implementations
+ async embedTextInput(textInput) {
+ return await this.embedder.embedTextInput(textInput);
+ }
+ async embedChunks(textChunks = []) {
+ return await this.embedder.embedChunks(textChunks);
+ }
+
+ async compressMessages(promptArgs = {}, rawHistory = []) {
+ const { messageArrayCompressor } = require("../../helpers/chat");
+ const messageArray = this.constructPrompt(promptArgs);
+ return await messageArrayCompressor(this, messageArray, rawHistory);
+ }
+}
+
+module.exports = {
+ MistralLLM,
+};
diff --git a/server/utils/AiProviders/native/index.js b/server/utils/AiProviders/native/index.js
index 66cc84d0..fff904c4 100644
--- a/server/utils/AiProviders/native/index.js
+++ b/server/utils/AiProviders/native/index.js
@@ -29,6 +29,7 @@ class NativeLLM {
// Make directory when it does not exist in existing installations
if (!fs.existsSync(this.cacheDir)) fs.mkdirSync(this.cacheDir);
+ this.defaultTemp = 0.7;
}
async #initializeLlamaModel(temperature = 0.7) {
@@ -132,7 +133,7 @@ class NativeLLM {
);
const model = await this.#llamaClient({
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
});
const response = await model.call(messages);
return response.content;
@@ -145,7 +146,7 @@ class NativeLLM {
async streamChat(chatHistory = [], prompt, workspace = {}, rawHistory = []) {
const model = await this.#llamaClient({
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
});
const messages = await this.compressMessages(
{
diff --git a/server/utils/AiProviders/ollama/index.js b/server/utils/AiProviders/ollama/index.js
index fce96f36..af7fe821 100644
--- a/server/utils/AiProviders/ollama/index.js
+++ b/server/utils/AiProviders/ollama/index.js
@@ -20,6 +20,7 @@ class OllamaAILLM {
"INVALID OLLAMA SETUP. No embedding engine has been set. Go to instance settings and set up an embedding interface to use Ollama as your LLM."
);
this.embedder = embedder;
+ this.defaultTemp = 0.7;
}
#ollamaClient({ temperature = 0.07 }) {
@@ -113,7 +114,7 @@ class OllamaAILLM {
);
const model = this.#ollamaClient({
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
});
const textResponse = await model
.pipe(new StringOutputParser())
@@ -136,7 +137,7 @@ class OllamaAILLM {
);
const model = this.#ollamaClient({
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
});
const stream = await model
.pipe(new StringOutputParser())
diff --git a/server/utils/AiProviders/openAi/index.js b/server/utils/AiProviders/openAi/index.js
index 038d201d..582bc054 100644
--- a/server/utils/AiProviders/openAi/index.js
+++ b/server/utils/AiProviders/openAi/index.js
@@ -23,6 +23,7 @@ class OpenAiLLM {
"No embedding provider defined for OpenAiLLM - falling back to OpenAiEmbedder for embedding!"
);
this.embedder = !embedder ? new OpenAiEmbedder() : embedder;
+ this.defaultTemp = 0.7;
}
#appendContext(contextTexts = []) {
@@ -127,7 +128,7 @@ class OpenAiLLM {
const textResponse = await this.openai
.createChatCompletion({
model: this.model,
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
messages: await this.compressMessages(
{
@@ -165,7 +166,7 @@ class OpenAiLLM {
{
model: this.model,
stream: true,
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
messages: await this.compressMessages(
{
diff --git a/server/utils/AiProviders/togetherAi/index.js b/server/utils/AiProviders/togetherAi/index.js
index 44061dd0..341661f8 100644
--- a/server/utils/AiProviders/togetherAi/index.js
+++ b/server/utils/AiProviders/togetherAi/index.js
@@ -28,6 +28,7 @@ class TogetherAiLLM {
"INVALID TOGETHER AI SETUP. No embedding engine has been set. Go to instance settings and set up an embedding interface to use Together AI as your LLM."
);
this.embedder = embedder;
+ this.defaultTemp = 0.7;
}
#appendContext(contextTexts = []) {
@@ -89,7 +90,7 @@ class TogetherAiLLM {
const textResponse = await this.openai
.createChatCompletion({
model: this.model,
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
messages: await this.compressMessages(
{
@@ -127,7 +128,7 @@ class TogetherAiLLM {
{
model: this.model,
stream: true,
- temperature: Number(workspace?.openAiTemp ?? 0.7),
+ temperature: Number(workspace?.openAiTemp ?? this.defaultTemp),
n: 1,
messages: await this.compressMessages(
{
diff --git a/server/utils/chats/index.js b/server/utils/chats/index.js
index d63de47d..764c7795 100644
--- a/server/utils/chats/index.js
+++ b/server/utils/chats/index.js
@@ -171,7 +171,7 @@ async function chatWithWorkspace(
// Send the text completion.
const textResponse = await LLMConnector.getChatCompletion(messages, {
- temperature: workspace?.openAiTemp ?? 0.7,
+ temperature: workspace?.openAiTemp ?? LLMConnector.defaultTemp,
});
if (!textResponse) {
diff --git a/server/utils/chats/stream.js b/server/utils/chats/stream.js
index ceea8d7d..cff565ed 100644
--- a/server/utils/chats/stream.js
+++ b/server/utils/chats/stream.js
@@ -141,7 +141,7 @@ async function streamChatWithWorkspace(
`\x1b[31m[STREAMING DISABLED]\x1b[0m Streaming is not available for ${LLMConnector.constructor.name}. Will use regular chat method.`
);
completeText = await LLMConnector.getChatCompletion(messages, {
- temperature: workspace?.openAiTemp ?? 0.7,
+ temperature: workspace?.openAiTemp ?? LLMConnector.defaultTemp,
});
writeResponseChunk(response, {
uuid,
@@ -153,7 +153,7 @@ async function streamChatWithWorkspace(
});
} else {
const stream = await LLMConnector.streamGetChatCompletion(messages, {
- temperature: workspace?.openAiTemp ?? 0.7,
+ temperature: workspace?.openAiTemp ?? LLMConnector.defaultTemp,
});
completeText = await handleStreamResponses(response, stream, {
uuid,
diff --git a/server/utils/helpers/customModels.js b/server/utils/helpers/customModels.js
index 87fe976e..53c641e7 100644
--- a/server/utils/helpers/customModels.js
+++ b/server/utils/helpers/customModels.js
@@ -5,6 +5,7 @@ const SUPPORT_CUSTOM_MODELS = [
"ollama",
"native-llm",
"togetherai",
+ "mistral",
];
async function getCustomModels(provider = "", apiKey = null, basePath = null) {
@@ -20,6 +21,8 @@ async function getCustomModels(provider = "", apiKey = null, basePath = null) {
return await ollamaAIModels(basePath);
case "togetherai":
return await getTogetherAiModels();
+ case "mistral":
+ return await getMistralModels(apiKey);
case "native-llm":
return nativeLLMModels();
default:
@@ -117,6 +120,26 @@ async function getTogetherAiModels() {
return { models, error: null };
}
+async function getMistralModels(apiKey = null) {
+ const { Configuration, OpenAIApi } = require("openai");
+ const config = new Configuration({
+ apiKey: apiKey || process.env.MISTRAL_API_KEY,
+ basePath: "https://api.mistral.ai/v1",
+ });
+ const openai = new OpenAIApi(config);
+ const models = await openai
+ .listModels()
+ .then((res) => res.data.data.filter((model) => !model.id.includes("embed")))
+ .catch((e) => {
+ console.error(`Mistral:listModels`, e.message);
+ return [];
+ });
+
+ // Api Key was successful so lets save it for future uses
+ if (models.length > 0 && !!apiKey) process.env.MISTRAL_API_KEY = apiKey;
+ return { models, error: null };
+}
+
function nativeLLMModels() {
const fs = require("fs");
const path = require("path");
diff --git a/server/utils/helpers/index.js b/server/utils/helpers/index.js
index 2b1f3dac..2eed9057 100644
--- a/server/utils/helpers/index.js
+++ b/server/utils/helpers/index.js
@@ -52,6 +52,9 @@ function getLLMProvider(modelPreference = null) {
case "togetherai":
const { TogetherAiLLM } = require("../AiProviders/togetherAi");
return new TogetherAiLLM(embedder, modelPreference);
+ case "mistral":
+ const { MistralLLM } = require("../AiProviders/mistral");
+ return new MistralLLM(embedder, modelPreference);
case "native":
const { NativeLLM } = require("../AiProviders/native");
return new NativeLLM(embedder, modelPreference);
@@ -76,6 +79,7 @@ function getEmbeddingEngineSelection() {
return new LocalAiEmbedder();
case "native":
const { NativeEmbedder } = require("../EmbeddingEngines/native");
+ console.log("\x1b[34m[INFO]\x1b[0m Using Native Embedder");
return new NativeEmbedder();
default:
return null;
diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js
index 5c43da51..54e68402 100644
--- a/server/utils/helpers/updateENV.js
+++ b/server/utils/helpers/updateENV.js
@@ -95,6 +95,15 @@ const KEY_MAPPING = {
checks: [nonZero],
},
+ MistralApiKey: {
+ envKey: "MISTRAL_API_KEY",
+ checks: [isNotEmpty],
+ },
+ MistralModelPref: {
+ envKey: "MISTRAL_MODEL_PREF",
+ checks: [isNotEmpty],
+ },
+
// Native LLM Settings
NativeLLMModelPref: {
envKey: "NATIVE_LLM_MODEL_PREF",
@@ -268,6 +277,7 @@ function supportedLLM(input = "") {
"ollama",
"native",
"togetherai",
+ "mistral",
].includes(input);
return validSelection ? null : `${input} is not a valid LLM provider.`;
}